CDC

CDC

CDC(clock domain crossing)

思维导图:
在这里插入图片描述
跨时钟域处理方法总结如下:
1、有关系的时钟之间传单bit数据,理论上只需要源数据保持足够长的时间(clk2的两个周期)即可;
2、无关系的时钟之间传单bit数据,必须要使用同步器;
3、不管有无关系的时钟进行单bit传输,脉冲同步器都可以解决这个问题;
4、多bit传输只能使用握手机制或者异步fifo;跨时钟域传输多bit数据,采用握手协议或者异步FIFO,握手信号的缺点在于传输单次数据的延迟比FIFO要大很多。双口RAM搭配格雷码也可以实现。二深度FIFO也可以,此时就不需要使用二进制码/格雷码转换,因为地址位只有一位。
5、低频采高频,为防止数据不丢失,应当让源数据变慢,多保持一些周期;高频采低频则不需要,但是高频采低频得到的结果可能带有很多冗余。
补充:
多个控制信号合并。在可能的情况下,将多个CDC位合并为1位CDC信号。
多周期路径法。使用同步负载信号安全地传递多个CDC位。
使用格雷码传递多个CDC位,格雷码只能解决地址信号这种规律递增信号的异步传输。对于前后值没有确定关系的并行数据来说,格雷码也无能为力。

脉冲同步器:
在这里插入图片描述
分析:前面其实是一个T触发器,Data为1的时候输出就翻转。当Data是单周期脉冲时,输出变为一次toggle,后面跟两级同步器同步到时钟域2,经过边沿检测得到脉冲。(边沿检测即是一个D触发器延迟加异或)一段时间后,Data产生第二个脉冲,T触发器再次Toggle,后级同步加异或产生单周期脉冲。
适用情况:必须是单周期脉冲的同步,快时钟到慢时钟 和 慢时钟到快时钟 都适用。但要求输入脉冲的间隔(两个脉冲的下降沿间隔)要大于两个clk2周期。
堪称 单比特跨时钟域 脉冲传输 的万能解决方案。
在这里插入图片描述
对于单比特的CDC问题,有三种同步器,基本可以满足各种需求。但都有相应的限制。
三种同步器的详细说明:
A. 电平(level signal)同步器
在这里插入图片描述
就是一级clk1触发器+两级clk2触发器
要求跨时钟域的信号在新时钟域中要保持高电平或低电平两个时钟周期以上。
在电平同步器中,
跨时钟域的信号在新时钟域中要保持高电平或低电平两个时钟周期以上。
同步之后的信号是电平的形式,
而该电平所维持的时钟周期个数是其在跨时钟域期间被上升沿检测到的次数。
这种同步器是所有同步器电路的核心。
下面是用Verilog描述的电平同步器

module synzer_ls(
                 data_out,
                 clk1,
                 clk2,
                 data_in
                 ); //level signal synchronizer

  output     data_out;  // signal that after synchronized
  input      clk1;      // old clk signal
  input      clk2;      // new clk signal
  input      data_in;   // signal that before synchronized

  reg        a;         // DFF in the old clk domain
  reg        b;         // the first DFF in the new clk domain
  reg        c;         // the second DFF in the new clk domain

  always @(posedge clk1) //a
    a<=data_in; 
  
  always @(posedge clk2) //b
    b<=a;

  always @(posedge clk2) //c
    c<=b;
 
  assign data_out=c;

endmodule

B. 边沿检测(edge detecting)同步器
在这里插入图片描述
边沿检测同步器就是加上了 脉冲起始端同步产生器A&A_delay’
就是一级clk1触发器+两级clk2触发器+一级起始同步脉冲产生器
要求脉冲宽度维持T+Thold,最好两个周期。所以不适用于单时钟脉冲进入慢时钟域。
边沿检测同步器在电平同步器的输出端增加了一个触发器。
新增触发器的输出经反相后和电平同步器的输出进行与操作。
这一电路会检测同步器输入的上升沿,
产生一个与时钟周期等宽、高电平有效的脉冲。
如果将与门的两个输入端交换使用,
就可以构成一个检测输入信号下降沿的同步器。
将与门改为非门可以构建一个产生低电平有效脉冲的电路。
当一个脉冲进入更快的时钟域中时,
边沿检测同步器可以工作的很好。
这一电路会产生一个脉冲,用来指示输入信号上升或下降沿。
这种同步器有一个限制,
即输入脉冲的宽度必须大于同步时钟周期与第一个同步触发器所需保持时间之和。
最保险的脉冲宽度是同步器时钟周期的两倍。
如果输入是一个单时钟宽度脉冲进入一个较慢的时钟域,
则这种同步器没有作用,
在这种情况下就要采用脉冲同步器。
下面是用Verilog描述的边沿(上升沿)检测同步器

module synzer_ed(
                 data_out,
                 clk1,
                 clk2,
                 data_in
                 ); // edge detecting synchronizer

  output     data_out;  // signal that after synchronized
  input      clk1;      // old clk signal
  input      clk2;      // new clk signal
  input      data_in;   // signal that before synchronized

  reg        a;         // DFF in the old clk domain
  reg        b;         // the first DFF in the new clk domain
  reg        c;         // the second DFF in the new clk domain
  reg        d;         // the third DFF in the new clk domain

  always @(posedge clk1) //a
    a<=data_in; 
  
  always @(posedge clk2) //b
    b<=a;

  always @(posedge clk2) //c
    c<=b;
  
  always @(posedge clk2) //d
    d<=c;

  assign data_out=c&&(~d);

endmodule

C. 脉冲(Pulse)同步器
在这里插入图片描述
脉冲同步器将前级的D触发器换成了T触发器(见1翻转),输出和延迟异或
1级clk1域的T触发器 + 两级clk2D触发器 +一级触发器进行异或
只能单周期脉冲,且两个脉冲之间至少两个clk2周期。快到慢或慢到快均可。
脉冲同步器的输入信号是一个单时钟宽度脉冲,
它触发原时钟域中的一个翻转电路。
每当翻转电路接收到一个脉冲时,它就会在高低电平间进行转换,
然后通过电平同步器到达异或门的一个输入端,
而另一个信号经过一个时钟周期的延迟进入异或门的另一端,
翻转电路每转换一次状态,
这个同步器的输出端就产生一个单时钟宽度的脉冲。
脉冲同步器的基本功能是从某个时钟域取出一个单时钟宽度脉冲,
然后在新时钟域中建立另一个单时钟宽度的脉冲。
脉冲同步器也有一个限制,
及输入脉冲之间的最小间隔必须等于两个同步器时钟周期。
如果输入脉冲相互过近,
则新时钟域中的输出脉冲也紧密相邻,
结果是输出脉冲宽度比一个时钟周期宽。
当输入脉冲时钟周期大于两个同步器时钟周期时,这个问题更加严重。
这种情况下,如果输入脉冲相邻太近,则同步器就不能检测到每个脉冲。
下面是用Verilog描述的脉冲同步器

module synzer_pl(
                 data_out,
                 clk1,
                 clk2,
                 data_in,
                 rst_n
                );  // pulse synchronizer
             
 output     data_out; // signal that after synchronized
 input      clk1;     // old clk signal
 input      clk2;     // new clk signal
 input      data_in;  // signal that before synchronized
 input      rst_n;    // signal indicating reset 
 
 reg        a;        // DFF in the old clk domain
 reg        b;        // the first DFF in the new clk domain
 reg        c;        // the second DFF in the new clk domain
 reg        d;        // the third DFF in the new clk domain
 
 wire       q;
 wire       q1;
 wire       di;
 
 assign di=data_in?q1:q;
 assign q=a;
 assign q1=~a;
 assign data_out=(c==d)?0:1;
 
 always @(posedge clk1) //a
 begin
   if(!rst_n)
     a<=1'b0;
   else
     a<=di;
 end
 
 always @(posedge clk2) //b
    b<=a;

  always @(posedge clk2) //c
    c<=b;
  
  always @(posedge clk2) //d
    d<=c;
    
endmodule

当输入两个脉冲间隔小于两个clk2周期时,输出的同步信号将会出错,如下图
在这里插入图片描述
CDC(不同时钟之间传数据)问题是ASIC/FPGA设计中最头疼的问题。CDC本身又分为同步时钟域和异步时钟域。这里要注意,同步时钟域是指时钟频率和相位具有一定关系的时钟域,并非一定只有频率和相位相同的时钟才是同步时钟域。异步时钟域的两个时钟则没有任何关系。这里假设数据由clk1传向clk2。
单bit传输时,同步时钟域因为频率和相位关系都是已知的,可以推导的,所以不需要采用额外的硬件电路就可以解决CDC问题,只需要源数据在clk1端保持足够长时间即可。让其保持足够长时间有两个好处:即便出现亚稳态,也可以在两个clk2时钟周期后数据变得稳定下来,从而采到正确的结果。还可以防止低频采高频时,因为频率跟不上而导致数据丢失。
单bit传输时,异步时钟域的传输就必须使用额外的电路模块(同步器)来保证数据正确的传输。最基本的同步器是双锁存结构的电平同步器,其余的同步器都是由其衍生而来。该同步器的基本原理,也是让数据至少在clk2的时钟下保存两个周期,消除亚稳态。当然同步器能解决异步时钟域的同步问题,自然也可以拿来解决同步时钟域的问题,毕竟同步时钟域更简单一些。
实际的电路设计中,才不会管那么多细节,不管你是同步时钟域还是异步时钟域,只要是不同的时钟之间传数据,就加上同步器的结构,这当然是一种偷懒的解决办法。脉冲同步器就是这么一种万能的结构,对于单bit跨时钟域传输而言,使用脉冲同步器就够了,不需要区分时钟有没有关系,也不需要区分是高频采低频还是低频采高频,毕竟也很少有人能掌握这么全的细节。
对于多bit传输,不能采用单bit传输的方法。原因在于,单bit传输时,不能确定该数据到底经过1个clk2时钟周期之后有效还是两个clk2时钟周期之后才有效。所以对多个bit各自采用单bit的同步机制,会导致输出一些错误的中间状态。
对于多bit传输,只能使用握手信号或者异步fifo。
还可以使用下面几种方法:
异步双口RAM+格雷码(异步FIFO)
处理多bit数据的跨时钟域,一般采用异步双口RAM。假设我们现在有一个信号采集平台,ADC芯片提供源同步时钟60MHz,ADC芯片输出的数据在60MHz的时钟上升沿变化,而FPGA内部需要使用100MHz的时钟来处理ADC采集到的数据(多bit)。
在这种类似的场景中,我们便可以使用异步双口RAM来做跨时钟域处理。先利用ADC芯片提供的60MHz时钟将ADC输出的数据写入异步双口RAM,然后使用100MHz的时钟从RAM中读出。
但我们读出RAM中的数据时,肯定不是一上电就直接读取,而是要等RAM中有ADC的数据之后才去读RAM。这就需要100MHz的时钟对RAM的写地址进行判断,当写地址大于某个值之后再去读取RAM。
在这个场景中,其实很多人都是使用直接用100MHz的时钟对RAM的写地址进行打两拍的方式,但RAM的写地址属于多bit,如果单纯只是打两拍,那不一定能确保写地址数据的每一个bit在100MHz的时钟域变化都是同步的,肯定有一个先后顺序。如果在低速的环境中不一定会出错,在高速的环境下就不一定能保证了。所以更为妥当的一种处理方法就是使用格雷码转换。
多比特利用双寄存器打两拍在高速场合不再适用,而使用格雷码可以将这种多比特变为单比特传输(格雷码每次变化只有一位会变)如果先将RAM的写地址转为格雷码,然后再将写地址的格雷码进行打两拍,之后再在RAM的读时钟域将格雷码恢复成10进制。这种处理就相当于对单bit数据的跨时钟域处理了。
异步FIFO
使用异步双口ram的场合其实用异步fifo也是一样的。
使用场景:在有大量的数据需要进行跨时钟域传输, 并且对数据传输速度要求比较高的场合 。
一个异步 FIFO 一般由如下部分组成:
1. Memory, 作为数据的存储器;
2. 写逻辑部分,主要负责产生写信号和地址;
3. 读逻辑部分,主要负责产生读信号和地址;
4. 地址比较部分,主要负责产生 FIFO 空、满的标志。
二深度FIFO同步器
二深度FIFO的地址实际上只有单bit,所以不需要进行gary编码,所以异步FIFO中的编码模块可以简化:
在这里插入图片描述
其中的gray2bin,bin2gray都可以省略,并且空满信号的产生之间通过同或门和异或门即可产生。
限制: 由于深度只有2,所以只适合某些特定场景(突发传输要求FIFO最小深度小于2的场景)
DMUX同步器
对于多bit的data信号,还可以使用使能技术,也就是通过一个使能信号来判断data信号是否已经稳定,当使能信号有效的时候说明data处于稳定状态,在这种情况下终点寄存器才对信号进行采样,可以保证没有setup/hold违例。而使能信号一般使用double FF的方法来进行同步。下面是DMUX的同步示意图:
在这里插入图片描述

哈姆雷特,请保持前行!

  • 21
    点赞
  • 188
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值