數(shù)字電路設(shè)計(jì)中的單bit脈沖信號(hào)跨時(shí)鐘域處理

跨時(shí)鐘域處理一直是數(shù)字IC,F(xiàn)PGA等數(shù)字電路設(shè)計(jì)中最常見(jiàn)的問(wèn)題,英文說(shuō)法是Clock Domain Conversion。之所以需要進(jìn)行數(shù)字信號(hào)的跨時(shí)鐘域處理,主要是因?yàn)楫?dāng)信號(hào)進(jìn)入異步時(shí)鐘域時(shí),如果信號(hào)進(jìn)行跳變的時(shí)刻處于異步時(shí)鐘域中觸發(fā)器的建立時(shí)間和保持時(shí)間內(nèi),觸發(fā)器無(wú)法確定采集到的信號(hào)究竟是高還是低,所以輸出端會(huì)出現(xiàn)不穩(wěn)定的狀態(tài),也就是亞穩(wěn)態(tài)。如下圖所示:

亞穩(wěn)態(tài)示意圖

對(duì)于數(shù)字信號(hào)的跨時(shí)鐘域問(wèn)題,有很多已經(jīng)非常成熟的處理方式,例如寄存器打兩拍,DMUX,結(jié)繩信號(hào)法,異步FIFO等。本篇文章主要介紹的方法是單bit脈沖信號(hào)跨時(shí)鐘域的結(jié)繩信號(hào)法。該方法具有一定的普適性,無(wú)論信號(hào)是從快到慢時(shí)鐘域,還是慢到快時(shí)鐘域,都可以實(shí)現(xiàn)信號(hào)跨時(shí)鐘域的安全傳輸。話(huà)不多說(shuō),先上代碼:

module cdc_pro(
 input     clka            , // 時(shí)鐘 a 
 input     clkb            , // 時(shí)鐘 b
 input     rst_n           , // 復(fù)位信號(hào),低有效
 input     pulse_ina       , // 脈沖信號(hào),時(shí)鐘域 a 到時(shí)鐘域 b 的傳輸信號(hào) ( a --> b )
 output    signal_outb     , // 時(shí)鐘域的雙寄存器打拍信號(hào)
 output    pulse_outb        // 時(shí)鐘域 b 最終的同步信號(hào)
    );

reg       signal_b_r1 ;      // 時(shí)鐘域 b 第1級(jí)打拍信號(hào)
reg       signal_b_r2 ;      // 時(shí)鐘域 b 第2級(jí)打拍信號(hào)
reg       signal_b_r3 ;      // 時(shí)鐘域 b 第2級(jí)打拍信號(hào)  
reg       signal_a_r1 ;      // 時(shí)鐘域 b 反饋到 a 的第1級(jí)打拍 結(jié)繩信號(hào)  
reg       signal_a_r2 ;      // 時(shí)鐘域 b 反饋到 a 的第2級(jí)打拍 結(jié)繩信號(hào)
reg       signal_a    ;      // 脈沖信號(hào) pulse_ina 的展寬信號(hào)

// 在 clka 內(nèi)對(duì)脈沖信號(hào)進(jìn)行展寬
always @ (posedge clka or negedge rst_n) begin
    if (~rst_n) begin
        signal_a <= 1'b0 ;
    end // 
    else if (pulse_ina == 1'b1) begin   // 對(duì)輸入脈沖信號(hào)進(jìn)行展寬
        signal_a <= 1'b1 ;
    end // 
    else if (signal_a_r2 == 1'b1) begin // 直到收到時(shí)鐘域 b 的結(jié)繩信號(hào)才結(jié)束展寬,拉低信號(hào)
        signal_a <= 1'b0 ;
    end // 
    else begin
        signal_a <= signal_a ;
    end // 
end // 
 
//  對(duì)脈沖展寬信號(hào) signal_a 進(jìn)行寄存器打拍
always @ (posedge clkb or negedge rst_n) begin
    if (~rst_n) begin
        {signal_b_r3, signal_b_r2, signal_b_r1} <= 0;
    end // 
    else begin
        {signal_b_r3, signal_b_r2, signal_b_r1} <= {signal_b_r2, signal_b_r1, signal_a}; 
    end //
end // 
 
assign signal_outb = signal_b_r2 ;                     // 2級(jí)打拍信號(hào)輸出
assign pulse_outb  = (~signal_b_r3) & (signal_b_r2) ;  // 上升沿檢測(cè),形成 clkb 內(nèi)脈沖信號(hào)

// 對(duì) clkb 內(nèi)提取的二級(jí)打拍信號(hào)進(jìn)行反饋結(jié)繩,結(jié)繩信號(hào)在clka內(nèi)也需要進(jìn)行打兩拍
always @ (posedge clka or negedge rst_n) begin
    if (~rst_n) begin
        {signal_a_r2, signal_a_r1} <= 0 ;
    end // 
    else begin
        {signal_a_r2, signal_a_r1} <= {signal_a_r1, signal_b_r2} ;
    end // 
end // 

endmodule

觀察上述結(jié)繩法的代碼,其實(shí)可以按照結(jié)構(gòu)分為3部分,第1部分是將時(shí)鐘域a的脈沖信號(hào)進(jìn)行展寬處理,防止時(shí)鐘域b漏采到信號(hào);第2部分是脈沖展寬信號(hào)的跨時(shí)鐘域打拍和上升邊沿檢測(cè);第3部分是時(shí)鐘域b的反饋結(jié)繩信號(hào)到時(shí)鐘域a的跨時(shí)鐘域處理。在vivado軟件中生成上述代碼的RTL圖,如下所示:

RTL_CDC

利用結(jié)繩法處理跨時(shí)鐘域信號(hào)有兩個(gè)關(guān)鍵點(diǎn)需要注意,一個(gè)是對(duì)脈沖信號(hào)的展寬和拉低處理;另一個(gè)是對(duì)結(jié)繩信號(hào)的選擇和打拍處理,這兩點(diǎn)在代碼中都有很好的體現(xiàn)與注釋。
跨時(shí)鐘域信號(hào)的處理在數(shù)字電路設(shè)計(jì)相關(guān)工作的筆試和面試中屬于高頻出現(xiàn)的題目,希望我的文章能夠?qū)π枰獙W(xué)習(xí)相關(guān)知識(shí)的小伙伴有一些幫助!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容