一、有din_en信號&&頻率相差較小
假設兩個異步時鍾頻率比為 5, 我們可以先用延遲打拍的方法對數據使能信號進行 3 級打拍緩存以檢測其上升沿,此時得到的上升沿信號剛好在數據使能信號的中間時刻附近,然后就可以在快時鍾域對慢時鍾域的數據信號進行采集了。具體對數據使能信號打幾拍,需要根據快慢時鍾的頻率比來決定。
該方法的基本思想就是選擇合適的時刻(例如數據的中間時刻)去采集信號,而不用同步多位寬的數據信號,可節省硬件資源。
module delay_sample(
input rstn,
input clk1,
input [7:0] din,
input din_en,
input clk2,
output [7:0] dout,
output dout_en);
//sync din_en
reg din_en_r1 ;
reg din_en_r2 ;
reg din_en_r3 ;
always @(posedge clk2 or negedge rstn) begin
if (!rstn) begin
din_en_r1 <= 0;
din_en_r2 <= 0;
din_en_r3 <= 0;
end
else begin
din_en_r1 <= din_en;
din_en_r2 <= din_en_r1;
din_en_r3 <= din_en_r2;
end
end
//檢測din_en上升沿
wire din_en_pos = din_en_r2 && !din_en_r3 ;
reg [7:0] dout_r ;
reg dout_en_r ;
always @(posedge clk2 or negedge rstn) begin
if (!rstn)
dout_r <= 'b0 ;
else if (din_en_pos)
dout_r <= din ;
end
//dout_en delay
always @(posedge clk2 or negedge rstn) begin
if (!rstn)
dout_en_r <= 1'b0 ;
else
dout_en_r <= din_en_pos ;
end
assign dout = dout_r ;
assign dout_en = dout_en_r ;
endmodule
由圖可知,快時鍾是在慢時鍾域的數據有效時間段的中間時刻左右對數據進行采樣的,這樣采到的數據非常的安全。
二、有din_en信號&&頻率相差較大
如果頻率相差較大,那在設計一個計數器,在din_en的上升沿附近開始計數,根據頻率比確定計數值到達多少時剛好處於din_en有效期的中間時刻附近,當計數到此值時對數據進行采樣即可。
三、無din_en或din_en一直拉高
如果慢時鍾域沒有數據使能信號 din_en, 或數據使能信號一直有效,此時在快時鍾域對數據使能信號進行上升沿檢測的方法將會失效。因為數據使能信號一直有效,除了第一個數據,快時鍾域將無法檢測到后繼數據的傳輸時刻。
解決方法就是,在快時鍾域對慢時鍾信號的邊沿進行檢測。如果兩個時鍾的頻率相差較小,可能還需要對數據進行延遲緩存,以保證采集到的是當拍時鍾的數據(因為當頻率相近時,第一個時鍾邊沿不容易被直接采樣到,可能到下一個數據有效期間才能被采樣到,所以應該將上一個數據延遲到此刻才能正確采樣);如果兩個時鍾的頻率相差較大,數據采樣時刻可以通過計數的方法獲得,而不用對數據進行緩存。
module delay_cnt_sample(
input rstn,
input clk1,
input [7:0] din,
input din_en,
input clk2,
output [7:0] dout,
output dout_en);
reg clk1_r1 ;
reg clk1_r2 ;
reg clk1_r3 ;
always @(posedge clk2 or negedge rstn) begin
if (!rstn) begin
clk1_r1 <= 0;
clk1_r2 <= 0;
clk1_r3 <= 0;
end
else begin
clk1_r1 <= clk1;
clk1_r2 <= clk1_r1;
clk1_r3 <= clk1_r2;
end
end
wire clk1_pos = clk1_r2 && !clk1_r3 ;
//delay counter
reg [5:0] cnt ;
always @(posedge clk2 or negedge rstn) begin
if (!rstn)
cnt <= 0 ;
//每檢測到新的慢時鍾上升沿並且din_en有效,那么就預示着新的數據到來了,就要重新計數了
else if (clk1_pos && din_en)
cnt <= 0 ;
else if (cnt != 6'b111111)
cnt <= cnt + 1'b1 ;
else
cnt <= cnt ;
end
//sync data
reg [7:0] dout_r ;
reg dout_en_r ;
always @(posedge clk2 or negedge rstn) begin
if (!rstn)
dout_r <= 'b0 ;
else if (din_en && cnt == 33)
dout_r <= din ;
end
always @(posedge clk2 or negedge rstn) begin
if (!rstn)
dout_en_r <= 1'b0 ;
else if (din_en && cnt == 33)
dout_en_r <= 1'b1 ;
else
dout_en_r <= 1'b0 ;
end
assign dout = dout_r ;
assign dout_en = dout_en_r ;
endmodule
由圖可知,快時鍾是在慢時鍾域的數據有效時間段的中間時刻左右對數據進行采樣的,這樣采到的數據非常的安全。
三、總結
無論是考慮打拍需要打多少拍,還是計數需要計多少次,都需要根據快慢時鍾的實際頻率比來決定。大多數情況下,我們的目標是保證在數據有效時間段的中間時刻去采樣,這樣采出的數據才非常准確安全。