跨時鍾域處理


跨時鍾域處理是FPGA設計中經常遇到的問題,而如何處理好跨時鍾域間的數據,可以說是每個FPGA初學者的必修課。如果是還在校的學生,跨時鍾域處理也是 面試中經常被問到的一個問題。
脈沖信號:跟隨時鍾,信號發生轉變。
電平信號:不跟隨時間,信號發生轉變。

1、單bit的異頻傳輸

主要分為兩種情況。

第一種:信號從B到A,(慢到快)

在時鍾域B下的脈沖信號pulse_b在時鍾域A看來,是一個很寬的“電平”信號會,保持多個clk_a的時鍾周期,所以一定能被clk_a采到。經驗設計采集過程必須寄存兩拍。第一拍將輸入信號同步化,同步化后的輸出可能帶來建立/保持時間的沖突,產生亞穩態。需要再寄存一拍,減少亞穩態帶來的影響。一般來說兩級是最基本要求,如果是高頻率設計,則需要增加寄存級數來大幅降低系統的不穩定性。也就是說采用多級觸發器來采樣來自異步時鍾域的信號,級數越多,同步過來的信號越穩定。
 
特別需要強調的是,此時pulse_b必須是clk_b下的寄存器信號,如果pulse_b是clk_b下的組合邏輯信號,一定要先在clk_b先用D觸發器(DFF)抓一拍,再使用兩級DFF向clk_a傳遞。這是因為clk_b下的組合邏輯信號會有毛刺,在clk_b下使用時會由setup/hold時間保證毛刺不會被clk_b采到,但由於異步相位不確定,組合邏輯的毛刺卻極有可能被clk_a采到。一般代碼設計如下:
always @ (posedge clk_a or negedge rst_n) 
begin 
    if (rst_n == 1'b0) 
        begin 
            pules_a_r1 <= 1'b0;
            pules_a_r2 <= 1'b0;
            pules_a_r3 <= 1'b0; 
        end 
    else
        begin //打3拍
            pules_a_r1 <= pulse_b;
            pules_a_r2 <= pules_a_r1;
            pules_a_r3 <= pules_a_r2; 
        end 
    end 
assign pulse_a_pos = pules_a_r2 & (~pules_a_r3); //上升沿檢測 
assign pulse_a_neg = pules_a_r3 & (~pules_a_r2); //下降沿檢測 
assign pulse_a = pules_a_r2;

應該很多人都會問,為什么是打兩拍呢,打一拍、打三拍行不行呢?

先簡單說下兩級寄存器的原理:兩級寄存是一級寄存的平方,兩級並不能完全消除亞穩態危害,但是提高了可靠性減少其發生概率。總的來講,就是一級概率很大,三級改善不大。
這樣說可能還是有很多人不夠完全理解,那么請看下面的時序示意圖:
data是時鍾域1的數據,需要傳到時鍾域2(clk)進行處理,寄存器1和寄存器2使用的時鍾都為clk。假設在clk的上升沿正好采到data的跳變沿(從0變1的上升沿,實際上的數據跳變不可能是瞬時的,所以有短暫的跳變時間),那這時作為寄存器1的輸入到底應該是0還是1呢?這是一個不確定的問題。所以Q1的值也不能確定,但至少可以保證,在clk的下一個上升沿,Q1基本可以滿足第二級寄存器的保持時間和建立時間要求,出現亞穩態的概率得到了很大的改善。
如果再加上第三級寄存器,由於第二級寄存器對於亞穩態的處理已經起到了很大的改善作用,第三級寄存器在很大程度上可以說只是對於第二級寄存器的延拍,所以意義是不大的。

第二種:信號從A到B(快到慢)

如果單bit信號從時鍾域A到時鍾域B,那么存在兩種不同的情況,傳輸脈沖信號pulse_a或傳輸電平信號level_a。實際上,在一般情況下只有電平信號level_a的寬度能被clk_b采集到才可以保證系統正常工作。那么對於脈沖信號pulse_a采取怎樣的處理方法呢?可以用一個展寬信號來替代pulse_a實現垮時鍾域的握手。
主要原理就是先把脈沖信號在clk_a下展寬,變成電平信號signal_a,再向clk_b傳遞,當確認clk_b已經“看見”信號同步過去之后,再清掉signal_a。代碼通用框架如下:
module Sync_Pulse ( clk_a, clk_b, rst_n, pulse_a_in, pulse_b_out, b_out ); 
/****************************************************/ 
input clk_a; input clk_b; input rst_n; input pulse_a; output pulse_b_out; output b_out; 
/****************************************************/ 
reg signal_a; reg signal_b; reg signal_b_r1; reg signal_b_r2; reg signal_b_a1; reg signal_b_a2; 
/****************************************************/ 
//在時鍾域clk_a下,生成展寬信號signal_a 
always @ (posedge clk_a or negedge rst_n) 
begin 
     if (rst_n == 1'b0)
        signal_a <= 1'b0; 
     else if (pulse_a_in) //檢測到到輸入信號pulse_a_in被拉高,則拉高signal_a
        signal_a <= 1'b1; 
     else if (signal_b_a2) //檢測到signal_b1_a2被拉高,則拉低signal_a 
        signal_a <= 1'b0; else; 
end 
//在時鍾域clk_b下,采集signal_a,生成signal_b 
always @ (posedge clk_b or negedge rst_n) 
begin 
    if (rst_n == 1'b0)
        signal_b <= 1'b0; 
    else 
        signal_b <= signal_a; 
end 
//多級觸發器處理 
always @ (posedge clk_b or negedge rst_n) 
begin
    if (rst_n == 1'b0) 
    begin 
        signal_b_r1 <= 1'b0;
        signal_b_r2 <= 1'b0; 
    end 
    else begin 
        signal_b_r1 <= signal_b; 
        //對signal_b打兩拍 
        signal_b_r2 <= signal_b_r1;
        end 
    end 
//在時鍾域clk_a下,采集signal_b_r1,用於反饋來拉低展寬信號signal_a
always @ (posedge clk_a or negedge rst_n) 
begin 
    if (rst_n == 1'b0) 
    begin 
        signal_b_a1 <= 1'b0;
        signal_b_a2 <= 1'b0; 
    end 
    else begin 
        signal_b_a1 <= signal_b_r1; 
        //對signal_b_r1打兩拍,因為同樣涉及到跨時鍾域 
        signal_b_a2 <= signal_b_a1; 
    end 
end 
assign pulse_b_out = signal_b_r1 & (~signal_b_r2); 
assign b_out = signal_b_r1; 
endmodule

總而言之,在設計中可以簡單的牢記以下五條原則:

1. 再全局時鍾的跳變沿最可靠。
2. 來自異步時鍾域的輸入需要寄存一次以同步化,再寄存一次以減少亞穩態帶來的影響。
3. 不需要用到跳變沿的來自同一時鍾域的輸入,沒有必要對信號進行寄存。
4. 需要用到跳變沿的來自同一時鍾域的輸入,寄存一次即可。
5. 需要用到跳變沿的來自不同時鍾域的輸入,需要用到3個觸發器,前兩個用以同步,第3個觸發器的輸出和第2個的輸出經過邏輯門來判斷跳變沿。

2、多bit傳輸(異頻問題)

處理多bit數據的跨時鍾域,一般采用異步雙口RAM。假設我們現在有一個信號采集平台,ADC芯片提供源同步時鍾60MHz,ADC芯片輸出的數據在60MHz的時鍾上升沿變化,而FPGA內部需要使用100MHz的時鍾來處理ADC采集到的數據(多bit)。
在這種類似的場景中,我們便可以使用異步雙口RAM來做跨時鍾域處理。先利用ADC芯片提供的60MHz時鍾將ADC輸出的數據寫入異步雙口RAM,然后使用100MHz的時鍾從RAM中讀出。
對於使用異步雙口RAM來處理多bit數據的跨時鍾域,相信大家還是可以理解的。當然,在能使用異步雙口RAM來處理跨時鍾域的場景中,也可以使用異步FIFO來達到同樣的目的。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM