(Clock Domain Crossing)跨时钟域信号的处理 (自我总结)

CummingsSNUG2008Boston_CDC.pdf
参考:
跨时钟域处理方法总结–最终详尽版 - love小酒窝 - 博客园
跨时钟域(CDC)设计方法之单bit信号篇(一) | 电子创新网赛灵思社区
孤独的单刀_Verilog语法,FPGA设计与调试,FPGA接口与协议-CSDN博客
跨时钟域传输总结(包含verilog代码|Testbench|仿真结果)-腾讯云开发者社区-腾讯云

异步时序定义

异步时序设计指的是在设计中有两个或以上的时钟, 且时钟之间是同频不同相或不同频率的关系。而异步时序设计的关键就是把数据或控制信号正确地进行跨时钟域传输。

亚稳态

每一个触发器都有其规定的建立(setup)和保持(hold)时间参数, 在这个时间参数内, 输入信号在时钟的上升沿是不允许发生变的。 如果在信号的建立时间中对其进行采样, 得到的结果将是不可预知的,即亚稳态

(Clock Domain Crossing)跨时钟域信号的处理 (自我总结)_第1张图片
MTBF(mean time between failures) : 平均故障间隔时间
通常,MTBF越大说明系统采样失败的可能越小。可见,对于高速的设计,MTBF是更容易发生的。对于一个典型的 0.25µm 工艺的 ASIC 库中的一个触发器,我们取如下的参数:
tr = 2.3ns, τ = 0.31ns, T0 = 9.6as, f=100MHZ, a = 10MHZ, MTBF = 2.01 days
也就是说触发器以100MHZ工作,假设异步事件触发的频率,也就是数据变化的频率跟采样时钟频率相同。我们用10MHZ的频率去不停地采它的数据,每个上升沿数据都会发生变化,则每两天就可能采集到一次亚稳态(个人理解,如有误请指正)。如果使用单锁存器同步,b的时钟上升沿采集a的数据时很可能采到亚稳态数据。

单bit跨时钟域处理

信号从源时钟域跨到目的时钟域后,需要在目的时钟的“指挥”下进行操作,这一过程可视为用目的时钟对被处理后的信号进行“采集”,既然是采集,则必须满足奈奎斯特采样定理,也就是说目的时钟频率需要至少是源时钟频率的2倍。

电平信号

电平信号进行CDC时,由于可以将电平信号看作一个频率很低的脉冲信号,所以不需要考虑时钟快慢,使用两级DFF就能够实现信号的同步

慢时钟域到快时钟域的脉冲信号

首先需要约定的是,所谓快时钟频率应该至少是慢时钟频率的两倍
(Clock Domain Crossing)跨时钟域信号的处理 (自我总结)_第2张图片
(Clock Domain Crossing)跨时钟域信号的处理 (自我总结)_第3张图片

从快时钟域到慢时钟域的脉冲信号 降频

从快时钟域到慢时钟域会出现漏采的情况,所以需要通过降频的方法实现对数据的扩展

(Clock Domain Crossing)跨时钟域信号的处理 (自我总结)_第4张图片
既然脉冲信号频率高于目的时钟才导致的漏采,那么我将脉冲信号拓宽到一定的程度不就可以保证采集到了吗?这一方法的本质实质上是降频,也就是将问题转换为我们已经能解决的用较快的时钟来采集较慢的时钟。如下图:
将信号adat扩宽为3倍aclk后,脉冲信号成为了一个较慢的信号,而目的时钟成为了一个较快的时钟,这样我们就可以使用2级同步器的方法来对被CDC信号进行同步。
(Clock Domain Crossing)跨时钟域信号的处理 (自我总结)_第5张图片

module quicktoslow # (
  parameter CLK_QUICK = 50k,
            CLK_SLOW  = 5k ,
)
(
	input i_quick_clk,
  input i_quick_rst,
  input i_a,

  input i_slow_clk,
  input i_slow_rst,
  output o_a
)
  parameter CLK_DIV = CLK_QUICK / CLK_SLOW;
	reg ri_a;
  reg [1:0] ro_a;
  assign o_a = ro_a[1];
	reg [5:0] r_clk_cnt;
  always @(posedge i_quick_clk, posedge i_quick_rst) begin
    if(i_quick_rst) begin
      r_clk_cnt <= 'd0;
    end else if (r_clk_cnt == CLK_DIV - 1) begin
      r_clk_cnt <= 'd0;
    end else if (r_clk_cnt || ri_a) begin
      r_clk_cnt <= r_clk_cnt + 1;
    end else begin
      r_clk_cnt <= r_clk_cnt;
    end
  end
  always @(posedge i_quick_clk, posedge i_quick_rst)begin
    if (i_quick_rst) begin 
        ri_a <= 'd0;
    end else if (i_a) begin
        ri_a <= 'd1;
    end else if (r_clk_cnt == CLK_DIV - 1) begin 
        ri_a <= 'd0;
    end else begin
        ri_a <= ri_a;
    end
  end

  always @(posedge i_slow_clk, posedge i_slow_rst) begin
    if(i_slow_rst) begin
      ro_a <= 'd0;
    end else begin
      ro_a[0] <= ri_a		;
      ro_a[1] <= ro_a[0];
    end
  end

endmodule

缺点:

  1. 若需要同步的两个脉冲信号距离很近,则第一个脉冲信号的扩宽可能会覆盖第二个脉冲信号,从而导致第二个脉冲信号的漏采;
  2. 脉冲信号的扩宽是以目的时钟为参考的,但是若不知道目的时钟的频率,则该方法可能失效,也就是说该方法不具备普遍性。

从快时钟域到慢时钟域 握手

为了探寻一种具备普遍性的方法,我们可以使用握手法来进行CDC。握手法的本质是负反馈,通俗来讲,就是我先将被CDC信号展宽,展宽后将其同步到目的时钟域,在目的时钟域生成指示信号,该指示信号用来指示此时信号已经被目的时钟域接收,然后将指示信号反馈到源时钟域(反馈过程),源时钟域接收到这个反馈信号后将被CDC信号拉低,从而确定了展宽长度,也通过”发送--反馈--操作“这一握手过程完成了一次CDC传输。

(Clock Domain Crossing)跨时钟域信号的处理 (自我总结)_第6张图片
上图是典型的握手过程来进行CDC:

  1. 源时钟域aclk下的信号adt1信号是要进行CDC的信号;
  2. adt1先是在源时钟域aclk下被展宽,然后通过两级同步器被同步到目的时钟域bclk下,分别为bq1_dat,bq2_dat;
  3. bq2_dat作为指示信号(反馈信号,也可以通过bq1_dat和bq2_dat来生成新的指示信号)又被反馈到了目的时钟域aclk下,并进行同步,分别为aq1_dat,aq2_dat;
  4. aq2_dat的拉高则说明反馈信号的同步完成,此时可以将adt1拉低(结束展宽过程);
  5. adt1拉低(结束展宽过程)后表示一次CDC操作结束。
//单比特快到慢“握手协议”
module cdc_sbit_handshake(
    input 		aclk,	//快时钟
    input 		arst_n,	//快时钟域复位信号
    input 		signal_a,//快时钟域信号
    input 		bclk,	//慢时钟
    input 		brst_n,	//慢时钟域复位信号
    output 		signal_b//慢时钟域输出信号
    );
                             
//慢时钟域信号展宽直至反馈信号回来再恢复
reg   req;//寄存慢时钟域展宽信号
reg   ack_r0;//反馈信号
always@(posedge aclk or negedge arst_n) begin
    if(!arst_n) begin
        req <= 1'b0;
    end
    else if(signal_a) begin
        req <= 1'b1;	//信号展宽
    end
    else if(ack_r0) begin
        req <= 1'b0; 	//反馈信号到来时恢复
    end
end

//展宽信号跨时钟同步至慢时钟域
reg   req_r0;
reg   req_r1; 
reg   req_r2;                          
always@(posedge bclk or negedge brst_n) begin
    if(!brst_n)begin
        {req_r2,req_r1,req_r0} <= 3'b0;
    end
    else begin        
        {req_r2,req_r1,req_r0} <=  {req_r1,req_r0,req};
    end
end

//生成反馈信号并同步至快时钟域
reg   ack;                          
always@(posedge aclk or negedge arst_n) begin
    if(!arst_n) begin
        {ack_r0,ack} <= 2'b0;
    end
    else begin
        {ack_r0,ack} <=  {ack,req_r1}; 
    end
end

//信号上升沿检测,让输出持续一个慢时钟周期
assign signal_b = ~req_r2 & req_r1;

endmodule

多bit跨时钟域处理

信号的跨时钟域传输可能会引入亚稳态问题,那么就需要想办法对其进行处理,从而降低亚稳态发生的概率(即提高MTBF)。
跨时钟域处理方法可以分为两个大类:单Bit信号跨时钟域处理、多Bit信号跨时钟域处理。分类的原因是多bit信号的传递不光只有亚稳态这一个问题,还可能会因为多个信号之间由于工艺、PCB布局等因素导致的信号传输延时(skew)的存在,从而导致信号被漏采或者错采。

通过合并控制信号实现问题的简化

在下面的例子中,数据的读取需要载入信号load和使能信号en同时置位,但是这两个信号之间存在一个小偏差(skew),在分别进行单bit的跨时钟域同步时,由于小skew的存在,导致这两个信号在被同步到目的时钟域后有一个时钟周期的偏差,而这个偏差直接导致数据无法被读取。

(Clock Domain Crossing)跨时钟域信号的处理 (自我总结)_第7张图片
现在不妨问自己:这两个信号是否都必须传递?实际上不是必须的,应用中我们可以把两个信号合并为一个控制信号,这样就将多bit信号的跨时钟域传递转换成了单bit信号的跨时钟域传递。如下:
(Clock Domain Crossing)跨时钟域信号的处理 (自我总结)_第8张图片

同源时钟与不同源时钟的跨时钟域

同步和异步跨时钟域示例分析
同步时钟、异步时钟----概念解析_一点一点的进步的博客-CSDN博客

格雷码

FPGA跨时钟域处理之gray码_哔哩哔哩_bilibili
跨时钟域传输的黄金搭档:异步FIFO与格雷码_格雷码跨时钟域处理 csdn 变两位_城外南风起的博客-CSDN博客
(Clock Domain Crossing)跨时钟域信号的处理 (自我总结)_第9张图片

数据流的跨时钟域处理

FPGA跨时钟域之数据流跨时钟域
所谓数据流跨时钟域即:时钟不同但是时间段内的数据量一定要相同。
常用的数据流跨时钟域可以使用fifo或者ram实现。fifo的实现我们之前文章中fifo资源的介绍中已经详细讲解过了,xilinx FIFO 硬核的结构如下:
(Clock Domain Crossing)跨时钟域信号的处理 (自我总结)_第10张图片

但是FIFO实现有一个问题,由于没有地址控制,需要固定时延是不方便,另外就是xilinx IP的fifo深度较大,可能存在资源浪费。
第二种方法就是使用ram自己搭建跨时钟域模块。我们使用bram做数据流跨时钟域。
例示代码如下 ,代码时钟比例为5:4,a时钟每5个clk写入4个数据,b时钟每个clk输出,代码中有两个点要注意:
1、0地址的写是能;
2、有一个防抖处理。

你可能感兴趣的:(fpga开发)