跨時(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í)的小伙伴有一些幫助!