本文转载自: 无界逻辑(微信号:wujieluoji)微信公众号
多bit信号跨时钟域的处理方法之一是握手法,也可以称作应答法。我们使用握手法的前提,一定要清楚源时钟域和目的时钟域的时钟关系,如:频率比,相位差。是快时钟域到慢时钟域?还是慢时钟域到快时钟域?比例是2.5倍,还是4倍,是同源时钟,还是非同源时钟,相位差多少等。
举例如下:源时钟域A(100MHz)的数据data_a要同步到目的时钟域B(250MHz)锁存为data_b,其基本思路如下:
1.首先保持源时钟域A的数据data_a不变。
2.在源时钟域A上产生一个请求脉冲req_a,需要使得req_a的周期足够大,确保时钟B可以采到。可参考:FPGA的单bit信号跨时钟域处理方法(面试比问)
3.时钟B采到req_a的上升沿,产生req_b_p1,方法可参考:FPGA如何进行边沿检测
4.利用req_b_p1,锁存data_a,产生data_b。注意此时data_a一直是保持稳定不变的,所以可以安全的采到。
5.利用req_b_p1,打一拍产生ack_b,此处需考虑是否需要脉冲展宽,产生ack_b_p3,确保时钟A可以采到ack_b_p3的上升沿。
6.时钟A,采到ack_b的上升沿,产生ack_a_p1。一次握手完成,data_a可更新,进行下一次的跨时钟域处理。
图1:握手法步骤1~4的时序图
图2:握手法步骤5~6的时序图
总结,源时钟域先产生req_a,并保持数据不变,等源时钟域收到ack_a后,一次握手结束。目的时钟域需要通过两级打拍的方式同步源时钟域req_a信号。源时钟域需要通过两级打拍的方式同步目的时钟域ack_b信号。
always @(posedge clkb or negedge rst_b_n) begin
if (rst_b_n == 1'b0) begin
req_b_d0 <= 1'b0 ;
req_b_d1 <= 1'b0 ;
req_b_d2 <= 1'b0 ;
end
else begin
req_b_d1 <= req_b_d0 ;
req_b_d2 <= req_b_d1 ;
end
end
assign req_b_p1 = req_b_d1 & !req_b_d2;
always @(posedge clkb or negedge rst_b_n) begin
if (rst_b_n == 1'b0) begin
data_b <= 16'b0 ;
end
else begin
if (req_b_p1) begin
data_b <= data_a ;
end
end
end
always @(posedge clkb or negedge rst_b_n) begin
if (rst_b_n == 1'b0) begin
ack_b <= 1'b0 ;
end
else begin
ack_b <= req_b_p1 ;
end
end
always @(posedge clkb or negedge rst_b_n) begin
if (rst_b_n == 1'b0) begin
ack_b_d1 <= 1'b0 ;
ack_b_d2 <= 1'b0 ;
ack_b_d3 <= 1'b0 ;
end
else begin
ack_b_d1 <= ack_b ;
ack_b_d2 <= ack_b_d1 ;
ack_b_d3 <= ack_b_d2 ;
end
end
assign ack_b_p4 = ack_b | ack_b_d1 | ack_b_d2 | ack_b_d3;
always @(posedge clka or negedge rst_a_n) begin
if (rst_a_n == 1'b0) begin
ack_a_d0 <= 1'b0 ;
ack_a_d1 <= 1'b0 ;
ack_a_d2 <= 1'b0 ;
end
else begin
ack_a_d1 <= ack_a_d0 ;
ack_a_d2 <= ack_a_d1 ;
end
end
assign ack_a = ack_a_d1 & !ack_a_d2;
同理,你是否可以尝试研究清楚,时钟域B到时钟域A的跨时钟域握手法?
So easy?如有疑问,请联系作者。