亞穩態的產生機理、消除辦法 (可以理解為什么打拍)
https://blog.csdn.net/gordon_77/article/details/79483119
1. 應用背景
1.1 亞穩態發生原因
在FPGA系統中,如果數據傳輸中不滿足觸發器的Tsu和Th不滿足,或者復位過程中復位信號的釋放相對於有效時鍾沿的恢復時間(recovery time)不滿足,就可能產生亞穩態,此時觸發器輸出端Q在有效時鍾沿之后比較長的一段時間處於不確定的狀態,在這段時間里Q端在0和1之間處於振盪狀態,而不是等於數據輸入端D的值。這段時間稱為決斷時間(resolution time)。經過resolution time之后Q端將穩定到0或1上,但是穩定到0或者1,是隨機的,與輸入沒有必然的關系。
1.2 亞穩態發生場合
只要系統中有異步元件,亞穩態就是無法避免的,亞穩態主要發生在異步信號檢測、跨時鍾域信號傳輸以及復位電路等常用設計中。
1.3 亞穩態危害
由於產生亞穩態后,寄存器Q端輸出在穩定下來之前可能是毛刺、振盪、固定的某一電壓值。在信號傳輸中產生亞穩態就會導致與其相連其他數字部件將其作出不同的判斷,有的判斷到“1”有的判斷到“0”,有的也進入了亞穩態,數字部件就會邏輯混亂。在復位電路中產生亞穩態可能會導致復位失敗。怎么降低亞穩態發生的概率成了FPGA設計需要重視的一個注意事項。
2. 理論分析
2.1 信號傳輸中的亞穩態
在同步系統中,輸入信號總是系統時鍾同步,能夠達到寄存器的時序要求,所以亞穩態不會發生。亞穩態問題通常發生在一些跨時鍾域信號傳輸以及異步信號采集上。
它們發生的原因如下:
(1)在跨時鍾域信號傳輸時,由於源寄存器時鍾和目的寄存器時鍾相移未知,所以源寄存器數據發出數據,數據可能在任何時間到達異步時鍾域的目的寄存器,所以無法保證滿足目的寄存器Tsu和Th的要求;
(2)在異步信號采集中,由於異步信號可以在任意時間點到達目的寄存器,所以也無法保證滿足目的寄存器Tsu和Th的要求;

2.2 復位電路的亞穩態
2.2.1 異步復位電路
在復位電路設計中,復位信號基本都是異步的,常用異步復位電路Verilog描述如下:
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) a <= 1’b0;
else a <= b;
end


2.2.1.1 恢復和去除時間(Recovery and Removal Time)
恢復時間(Recovery Time)是指異步控制信號(如寄存器的異步清除和置位控制信號)在“下個時鍾沿”來臨之前變無效的最小時間長度。這個時間的意義是,如果保證不了這個最小恢復時間,也就是說這個異步控制信號的解除與“下個時鍾沿”離得太近(但在這個時鍾沿之前),沒有給寄存器留有足夠時間來恢復至正常狀態,那么就不能保證“下個時鍾沿”能正常作用,也就是說這個“時鍾沿”可能會失效。
去除時間(Removal)是指異步控制信號(如寄存器的異步清除和置位控制信號)在“有效時鍾沿”之后變無效的最小時間長度。這個時間的意義是,如果保證不了這個去除時間,也就是說這個異步控制信號的解除與“有效時鍾沿”離得太近(但在這個時鍾沿之后),那么就不能保證有效地屏蔽這個“時鍾沿”,也就是說這個“時鍾沿”可能會起作用。
2.2.2 同步復位電路的亞穩態
在復位電路中,由於復位信號是異步的,因此,有些設計采用同步復位電路進行復位,並且絕大多數資料對於同步復位電路都認為不會發生亞穩態,其實不然,同步電路也會發生亞穩態,只是幾率小於異步復位電路。
如下面verilog代碼對同步復位電路的描述。
always @(posedge clk)
begin
if(!rst_n) a <= 1’b0;
else a <= b;
end

在此,我們不討論同步復位的消耗資源問題,只討論同步復位的亞穩態產生情況。

2.3 亞穩態產生概率以及串擾概率
在實際的FPGA電路設計中,常常人們想的是怎么減少亞穩態對系統的影響,很少有人考慮怎么才能減少亞穩態發生幾率,以及亞穩態串擾的概率問題。
2.3.1 亞穩態發生概率
由上面分析得知,系統亞穩態發生的都是由於clk的Tsu和Th不滿足,又或者是復位信號的移除和恢復時間不滿足。常用FPGA器件的Tsu+Th約等於1ns,復位移除和恢復時間相加約等於1ns。
當異步信號不是一組數據,或者信號量較少,那就需要對異步信號進行同步處理,例如對一個異步脈沖信號進行采集,只要脈沖信號變化發生在時鍾Tsu和Th窗口內,那就很可能會產生亞穩態,亞穩態產生的概率大概為:
概率 = (建立時間 + 保持時間)/ 采集時鍾周期 (公式3-1)
由公式3-1可以看出,隨着clk頻率的增加,亞穩態發生的幾率是增加的。
例如,為系統采用100M時鍾對一個外部信號進行采集,采集時鍾周期為10ns,那采集產生亞穩態的概率為:1ns/10ns = 10%
同理采用300M時鍾對一個外部信號進行采集,那產生亞穩態的概率為:1ns/3.3ns = 30%
如果采用三相相位差為120°的時鍾對一個外部信號進行采集,那產生亞穩態的概率接近90%
所以在異步信號采集過程中,要想減少亞穩態發生的概率:
(1) 降低系統工作時鍾,增大系統周期,亞穩態概率就會減小;
(2) 采用工藝更好的FPGA,也就是Tsu和Th時間較小的FPGA器件;
2.3.2 亞穩態的串擾概率
使用異步信號進行使用的時候,好的設計都會對異步信號進行同步處理,同步一般采用多級D觸發器級聯處理,如圖2.6所示,采用三級D觸發器對異步信號進行同步處理。

這種模型大部分資料都說的是第一級寄存器產生亞穩態后,第二級寄存器穩定輸出概率為90%,第三極寄存器穩定輸出的概率為99%,如果亞穩態跟隨電路一直傳遞下去,那就會另自我修護能力較弱的系統直接崩潰。接下來我們分析這種串擾的概率問題。
如圖2.7所示為一個正常第一級寄存器發生了亞穩態,第二級、第三極寄存器消除亞穩態時序模型。

由上圖可以看出,當第一個寄存器發生亞穩態后,經過Tmet的振盪穩定后,第二級寄存器能采集到一個穩定的值。但是為什么第二級寄存器還是可能會產生亞穩態呢?

2.3.3 亞穩態振盪時間Tmet
亞穩態震盪時間Tmet關系到后級寄存器的采集穩定問題,Tmet影響因素包括:器件的生產工藝、溫度、環境以及寄存器采集到亞穩態離穩定態的時刻等。甚至某些特定條件,如干擾、輻射等都會造成Tmet增長。
3. 應用分析
有亞穩態產生,我們就要對亞穩態進行消除,常用對亞穩態消除有三種方式:
(1) 對異步信號進行同步處理;
(2) 采用FIFO對跨時鍾域數據通信進行緩沖設計;
(3) 對復位電路采用異步復位、同步釋放方式處理。
3.1.1 對異步信號進行同步提取邊沿
在異步通信或者跨時鍾域通信過程中,最常用的就是對異步信號進行同步提取邊沿處理。對一個異步信號進行提取上升沿通常采用程序清單 4.1所示。
程序清單 4.1 雙極寄存器提取邊沿
input sig_nsyn;
wire sig_nsyn_p;
reg[1:0] sig_nsyn_r;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) sig_nsyn_r <= 2’d0;
else sig_nsyn_r <= { sig_nsyn_r [0], sig_nsyn };
end
assign sig_nsyn_p = sig_nsyn_r[0] & ~sig_nsyn_r[1];
這種邊沿提取方式對於一個穩定的系統是不合適的,例如:當第一級寄存器采集到亞穩態,那勢必造成sig_nsyn_p輸出亞穩態,這樣就會對采用sig_nsyn_p的信號進行判斷的電路造成影響,甚至判斷出錯誤的值。
根據3.3.1小節的亞穩態產生概率,如果在100M時種下那第一級寄存器產生亞穩態的概率約為10%,隨着系統采集頻率升高,那產生亞穩態的概率也會隨之上升。因此,在進行異步信號跨頻提取邊沿時候,一般采用多進行一級寄存器消除亞穩態,可能在系統穩定性要求高的情況下,采用更多級寄存器來消除亞穩態,如程序清單 4.2所示,即為采用4級寄存器消除亞穩態,相應的邊沿信號產生的時間就晚了兩個時鍾周期。
程序清單 4.2 多級寄存器提取邊沿信號
input sig_nsyn;
wire sig_nsyn_p;
reg[3:0] sig_nsyn_r;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) sig_nsyn_r <= 2’d0;
else sig_nsyn_r <= { sig_nsyn_r [2::0], sig_nsyn };
end
assign sig_nsyn_p = sig_nsyn_r[2] & ~sig_nsyn_r[3];
3.1.2 FIFO進行異步跨頻數據處理
當數據流從一個時鍾域到另一個時鍾域的時候,絕大多數情況下都采用FIFO來作為中間緩沖,采用雙時鍾對數據緩沖,就可以避免亞穩態的發生。
3.1.3 異步復位,同步釋放
對於復位情況下的亞穩態,常常是由於恢復時間和移除時鍾不滿足造成的,因此,最常用的處理方式是采用異步復位、同步釋放。常用電路模型如所示。采用第二級寄存器輸出作為全局復位信號輸出。
程序清單 4.3 異步復位處理
wire sys_rst_n;
reg [1:0] rst_r;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) rst_r <= 2’d0;
else rst_r <= {rst_r[0], 1’b1};
end
assign sys_rst_n = rst_r[1];
input clk ,
input reset_l ,
output reg reset_out
);
reg reset_d ;
always @ (posedge clk )
begin
reset_d <= reset_l ;
reset_out<= reset_d ;
end
endmodule

reset_out信號是已經同步過的復位信號,可以直接在其它模塊使用。需要注意的是,這個復位信號會延遲幾個時鍾周期。並且,復位信號必須要大於時鍾周期,才能被系統檢測到。
module test(
input reset_l ,
output reg reset_out
);
reg reset_d ;
always @ (posedge clk or negedge reset_l)
begin
if(!reset_l)begin
reset_out <= 1'b0 ;
reset_d <= 1'b0 ;
end
else begin
reset_d <= 1'b1 ;
reset_out <= reset_d ;
end
end
endmodule
