精华内容
下载资源
问答
  • CDC跨时钟域处理方法

    2018-08-14 09:37:05
    根据各种应用场景,详细介绍了各种CDC跨时钟域电路的处理方法
  • 跨时钟域处理方法总结

    千次阅读 2020-03-08 10:54:00
    目录 跨时钟域处理 1. 异步时序定义 2. 亚稳态 3. 同步策略 方法一:双锁存器 方法二:握手信号(结绳法) 方法三:异步双口RAM+格雷码 跨时钟域处理 为了彻底理...

    跨时钟域处理

    为了彻底理解跨时钟域问题,多方搜集资料,做个简单整理备忘。主要参考了如下几个资源:

    1. https://zhuanlan.zhihu.com/p/45186793 跟IC君一起学习集成电路
    2. https://www.cnblogs.com/PG13/p/10329678.html 新芯时代
    3. 格雷码 https://www.cnblogs.com/zhuruibi/p/8988044.html
    4. 主要参考来源:“ASIC 中的异步时序设计” 王夏泉 华中科技大学

    1. 异步时序定义

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

    2. 亚稳态

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

    触发器进入亚稳态的时间可以用参数 MTBF(mean time between failures)来描述, MTBF即触发器采样失败的时间间隔,其公式描述如下:

    \[ MTBF = e^{t_r/\tau}/T_0fa\]

    其中:

    • \(t_r\) = 分辨时间(时钟沿开始)
    • \(\tau,T_0\) = 触发器参数
    • \(f\) = 采样时钟频率
    • a = 异步事件触发频率

    对于一个典型的 0.25µm 工艺的 ASIC 库中的一个触发器,我们取如下的参数:

    tr = 2.3ns, τ = 0.31ns, T0 = 9.6as, f=100MHZ, a = 10MHZ, MTBF = 2.01 days

    也就是说触发器以100MHZ工作,我们用10MHZ的频率去不停地采它的数据,则每两天就可能采集到一次亚稳态(个人理解,如有误请指正)。如果使用单锁存器同步:

    20200302172619.png

    b的时钟上升沿采集a的数据时很可能采到亚稳态数据。

    3. 同步策略

    方法一:双触发器

    为了避免亚稳态,应该使得MTBF尽量大。采用双触发器可以改善这一问题:

    20200302173321.png

    当使用了双触发器以后, b_dat2 的MTBF由以下公式可以得出:
    \[MTBF = e^{(tr/τ)}/ T_0fa × e^{(tr/τ)}/ T_0fa\]
    如果我们仍然使用上一节所提供的参数,则b_dat2 的MTBF为 **9.57*109(years)**。由上述结果可以看出,双锁存器法可以消除亚稳态问题。

    注意问题1

    时钟域B两级同步的寄存器跟时钟域A的输出寄存器之间不能有组合逻辑。组合逻辑电路各个输入信号的不一致性以及组合逻辑内部路径的延时时间不一样,运算后的信号存在毛刺如图(2),我们无法预先知道CLKB 的上升沿何时会到来,CLKB 采样到的信号就无法预知。

    v2-c25ca7bd181e08a7e06b3955cc38b7c0_720w.jfif

    因此,要想CLKB 能采到稳定的信号,时钟域A的信号必须是经过CLKA 敲过,在一个时钟周期内是稳定的信号,如图(3)所示:

    v2-7a495d3e706d70ccf36a5642e188b24f_720w.jfif

    注意问题2

    Clock-gating enable 信号没有经过异步处理:

    v2-3fd99ab9b5abb64b4fc3cd9e17c7d194_720w.jfif

    在下图中a_in 信号经过CLKA的DFF敲过,再送到两级DFF 同步器处理,完全没毛病。但是F2的使能信号EN是从时钟域A来的,当EN信号变化的时候,由于时钟域不一样,无法保证使能之后的CLKB信号采样数据时满足setup/hold time 要求,这时F2输出信号也就变得无法预测了。因此对clk gating的信号也要做处理。

    方法二:握手信号(结绳法)

    如果a_clk的频率比b_clk频率高,将可能会出现因为dat变化太快而使b_clk无法采到的问题。即在信号从快时钟域向慢时钟域过渡的时候, 如果信号变化太快, 慢时钟将可能无法对该信号进行正确采样, 如下图所示。 所以在使用双锁存器法的时候, 应该使原始信号保持足够长的时间, 以便另一个时钟域的锁存器可以正确的对其进行采样。

    20200302174247.png

    下面介绍一种“结绳法”,适合任何时钟域的过渡:

    20200302194822.png

    其中标明_clk1 的信号表示该信号属于 clk1 时钟域, 同理标明_clk2 的信号表示该信号属于 clk2 时钟域。在两次src_req_clk1 之间被 src_vld_clk1“ 结绳” (pluse2toggle),在将src_vld_clk1 用双锁存器同步以后, 将该信号转换为 dst_req_clk2(toggle2pluse)。同理,用dst_vld_clk2 将 dst_req_clk2“结绳”, dst_vld_clk2 表明在 clk2 时钟域中, src_dat_clk1 已经可以进行正确采样了。 最后将 dst_vld_clk2 转换为 dst_ack_clk1(synchronizer and toggle2pluse), dst_ack_clk1 表明 src_dat_clk1 已经被 clk2 正确采样了, 此后 clk1 时钟域就可以安全地传输下一个数据了。 可以看出,“结绳法” 关键是将信号结绳以后, 使其保持了足够长的时间,以便另一个时钟可以正确地采样。

    电路图如下:

    20200302200302.png

    上图描述了握手协议的完整流程,其中三角带横线的符号是异或门。同时给出了两个脉冲之间结绳信号(vld信号)的产生方法。

    • 优点:“结绳法” 可以解决快时钟域向慢时钟域过渡的问题, 且其适用的范围很广。
    • 缺点:实现较为复杂,特别是其效率不高,在对设计性能要求较高的场合应该慎用。

    下图是一种更加直观的描述:

    20200302200336.png

    脉冲信号一般是通过上升沿采样实现的。

    方法三:异步双口RAM+格雷码

    处理多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的时钟域变化都是同步的,肯定有一个先后顺序。如果在低速的环境中不一定会出错,在高速的环境下就不一定能保证了。所以更为妥当的一种处理方法就是使用格雷码转换。

    格雷码简介

    在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码(Gray Code),另外由于最大数与最小数之间也仅一位数不同,即“首尾相连”,因此又称循环码或反射码。格雷码(Gray Code)又称Grey Code、葛莱码、格莱码、戈莱码、循环码、反射二进制码、最小差错码等。

    格雷码有多种编码形式

    十进制数4位自然二进制码4位典型格雷码十进制余三格雷码十进制空六格雷码十进制跳六格雷码步进码
    00000000000100000000000000
    10001000101100001000100001
    20010001101110011001100011

    表中典型格雷码具有代表性。若不作特别说明,格雷码就是指典型格雷码,它可从自然二进制码转换而来。

    二进制格雷码的生成方法有很多,具体可自行搜索或见:

    https://www.cnblogs.com/zhuruibi/p/8988044.html

    回到刚才的问题,多比特利用双寄存器打两拍在高速场合不再适用,而使用格雷码可以将这种多比特变为单比特传输(格雷码每次变化只有一位会变)如果先将RAM的写地址转为格雷码,然后再将写地址的格雷码进行打两拍,之后再在RAM的读时钟域将格雷码恢复成10进制。这种处理就相当于对单bit数据的跨时钟域处理了。

    异步FIFO

    使用异步双口ram的场合其实用异步fifo也是一样的。

    使用场景:在有大量的数据需要进行跨时钟域传输, 并且对数据传输速度要求比较高的场合 。

    一个异步 FIFO 一般由如下部分组成:
    1. Memory, 作为数据的存储器;
    2. 写逻辑部分,主要负责产生写信号和地址;
    3. 读逻辑部分,主要负责产生读信号和地址;
    4. 地址比较部分,主要负责产生 FIFO 空、满的标志。

    异步FIFO代码可以参考我的另一篇文章:

    https://blog.csdn.net/darknessdarkness/article/details/104726798

    展开全文
  • 本文主要介绍单比特信号跨时钟域处理问题,感性趣的朋友可以参考下。
  • FPGA跨时钟域处理方法

    2021-07-17 20:19:16
    前提条件是 快时钟域到慢时钟域,原因有两个,1)只有快时钟域到慢时钟域,才能保证慢时钟域的脉冲信号能被快时钟域采样到。2)两级寄存器的主要作用是消除亚稳态(不能完全消除亚稳态,但可以使亚稳态出现的概率...

            跨时钟域的信号分为两类,一类是单比特的信号,一类是多比特的信号。这两类信号无论是快时钟域到慢时钟域还是慢时钟域到快时钟域,无论是流数据还是控制信号,都可以使用异步FIFO进行同步。因此下文分类的不同情景,每一种情景都可以使用异步FIFO进行同步,后文就不作介绍。但需要注意的是,快时钟域到慢时钟域的同步,在使用异步FIFO时,快时钟域平均流量是不能大于慢时钟域的处理速度的,否则数据会丢失,这其实与是否使用FIFO来进行同步无关。因为FIFO的作用本就是在某一段持续时间内,发送方发送的数据大于接收方的处理能力时,暂时作为缓存用的。若发送方的平均流量大于接受方的处理能力,那么除非FIFO无限大,否则随着时间的增加,就会丢失数据。

    1、单比特信号

             大部分文章介绍单比特信号的跨时钟域处理时,都是默认该单比特信号为控制信号或者说变化相对较慢的单比特脉冲信号。但实际上单比特信号也存在是流数据的可能,可能实际工程上单比特的流数据信号较少,但是起码理论上存在这种可能,如果不加以区分讨论,初学者往往容易混淆。

    1.1 单比特脉冲信号

    1.1.1 慢时钟域到快时钟域

            慢时钟域的单比特脉冲信号同步至快时钟域,可以采用多级寄存器的方法,也就是将单比特脉冲信号在快时钟域打多拍。一般情况下只需要采用两级寄存器即可,因为更多级的寄存器对性能提升并不明显。前提条件要求从慢时钟域到快时钟域,原因是只有慢时钟域到快时钟域,才能保证慢时钟域的脉冲信号能被快时钟域采样到。

            需要注意的是,多级寄存器的主要作用是避免亚稳态的传播(不能完全消除亚稳态,但可以使亚稳态出现的概率大大降低),并不能保证数据稳定后,是正确的值,而是随机的0或1。但是由于慢时钟域的脉冲信号持续时间大于快时钟域的一个周期,因此在快时钟域的下一个上升沿到来时,慢时钟域的脉冲信号仍然持续,此时快时钟域可以采到正确的值。也就是说,出现亚稳态时,快时钟域实际上需要已经对慢时钟域的信号进行第二次采样了。显然地,第二次采样时,需要满足建立时间与保持时间,否则可能会再次出现亚稳态。因此可以看出快时钟域与慢时钟域的关系并不是任意的,两者并不能接近到无法满足第二次采样的建立时间和保持时间。快时钟域域慢时钟域需要满足下面的条件:Tslow>Tfast+Thold+Tsetup,其中Tslow为慢时钟域的时钟周期,Tfast为快时钟域的时钟周期,Thold与Tsetup分别为快时钟域寄存器的保持时间和建立时间。通过上面的讨论我们可以发现,当使用多级寄存器时,如果出现了亚稳态,快时钟域 能够 采到慢时钟域信号所需的时间 比没有出现亚稳态时 可能会多一个周期。如果有彼此关联的两个多比特信号,比如说地址信号,它们从慢时钟域同步至快时钟域时,可能到达快时钟域的时间时不一样的,那么得到的地址就是错误的,这就是多比特信号即使是从慢时钟域到快时钟域,也不能够使用多级寄存器同步的原因。但如果多比特信号彼此无关,从慢时钟域到快时钟域时,是可以使用多级寄存器同步的。

    代码如下:

    module syn(
        input         rsta_n,
        input         clka,
        input         dataa,
        input         rstb_n,
        input         clkb,
        output        datab
        );
       
    reg syn1;
    reg syn2;
    
    always@(posedge clkb or negedge rstb_n) begin
        if(!rstb_n) begin
            syn1<=1'b0;
            syn2<=1'b0;
        end
        else begin
            syn1<=level;
            syn2<=syn1;
        end
    end
    
    assign datab=syn2;
        
    endmodule
    

    2、快时钟域到慢时钟域

    (1)使用握手信号

            快时钟但慢时钟域的单比特信号同步可以使用握手信号。握手信号的使用相对来说耗时较长,如果快时钟域的信号变化较快,是无法使用握手信号来进行同步的,否则慢时钟域可能会漏采快时钟域的信号。(下图输出的不是脉冲信号而是电平信号,与下文的代码有点区别)

     

    verilog代码如下:

    module syn(
        input     clka,
        input     rsta_n,
        input     bit_in,
        input     clkb,
        input     rstb_n,
        output    bit_out
        );
        reg     req;
        reg     req_f;
        reg     req_ff;
        reg     req_fff;
        
        wire    ack;
        reg     ack_f;
        reg     ack_ff;
        
        //使用req信号对a时钟域数据进行保持 
        always@(posedge clka or negedge rsta_n) begin
            if(!rsta_n)
                req<=1'b0;
            else if(ack_ff)//ack信号为高时,不接收新的数据
                req<= 1'b0;
            else if(bit_in)
                req<=1'b1;
            else
                req<=req;
        end
        
        //将a时钟域的req信号同步至b时钟域
        always@(posedge clkb or negedge rstb_n) begin
            if(!rstb_n) begin
                req_f <=1'b0;
                req_ff<=1'b0;
            end
            else begin
                req_f <=req;
                req_ff<=req_f; 
            end
        end
        //在b时钟域产生单个数据脉冲
        always@(posedge clkb or negedge rstb_n) begin
            if(!rstb_n) 
                req_fff<=1'b0;
            else 
                req_fff<=req_ff; 
        end
        assign bit_out=~req_fff&req_ff;
        //将b时钟域的ack信号同步至a时钟域
        assign ack=req_ff;
        always@(posedge clka or negedge rsta_n) begin
            if(!rsta_n) begin
                ack_f  <= 1'b0;
                ack_ff <= 1'b0;
            end
            else begin
                ack_f  <= ack;
                ack_ff <= ack_f;
            end
        end
      
    endmodule
    

    testbench:

    `timescale 1ns / 1ps
    
    module tb(
    
        );
        
        reg clka,clkb;
        reg bit_in;
        reg rsta_n,rstb_n;
        wire bit_out;
       
       syn test(
         .clka(clka),
         .rsta_n(rsta_n),
         .bit_in(bit_in),
         .clkb(clkb),
         .rstb_n(rstb_n),
         .bit_out(bit_out)
        );
        
        initial begin
        clka=1'b0;
        clkb=1'b1;
        rsta_n=1'b0;
        rstb_n=1'b0;
        bit_in=1'b0;
        #28
        rsta_n=1'b1;
        rstb_n=1'b1;
        end
        
        always #2 clka=~clka;
        always #7 clkb=~clkb;
        
     initial begin
        #98
        bit_in =1'b1;
        #4
        bit_in =1'b0;
        #60
        bit_in =1'b1;
        #4
        bit_in =1'b0;
        #8
        bit_in =1'b1;
        #4
        bit_in =1'b0;
        #300
        bit_in =1'b1;
     end
        
    endmodule
    

    仿真时序图:

    从仿真图可以看出,对于快时钟域的两个脉冲离得比较近的话,慢时钟域是会漏采的,使用握手信号时,对此需要注意。

    (2)T触发器 + 多级触发器

            对于单比特的脉冲信号,我们也可以使用T触发器 + 多级触发器的方法来进行同步,这种方法相较于使用握手信号所需时间较短,但没有ack信号,无法判断接受方是否接受到了脉冲信号。因此使用时一定要保证 满足使用条件。

            T触发器的真值表达式为 Qn+1 =T⊕Qn。总结来说的话,就是每来一个周期的高电平,输出就翻转一次。我们利用这个特性,可以将单比特的信号展宽。就是说在两个脉冲之间的信号是保持不变的,不管保持的是0还是1并不重要,我们只要知道脉冲到来之时,T触发器的输出会翻转就足够了。只要信号发生了变化,我们在进行同步的时钟域多打一拍,并与前一拍的信号进行异或就可以得到一个周期的脉冲,虽然b时钟域采到的并不是脉冲,但是异或之后得到的就是一个脉冲。

            这种方法的本质实际上是将信号展宽,只不过展宽的信号可能是0也可能是1。但很显然,a时钟域的两个脉冲间隔要足够大,因为两个脉冲的信号的间隔就是a时钟域的信号持续的时间。如果这个时间太短,在b时钟域是无法采到的。两个脉冲之间的间隔要大于Tb+Thold+Tsetup,其中Tb为b时钟域的时钟周期,Thold与Tsetup分别为b时钟域寄存器的保持时间和建立时间。

    verilog代码如下:

    module syn(
        input         rsta_n,
        input         clka,
        input         plusea,
        input         rstb_n,
        input         clkb,
        output        pluseb
        );
        
    reg level;
    reg syn1;
    reg syn2;
    reg syn2_f;
    
    //将a时钟域的脉冲信号转为电平信号
    always@(posedge clka or negedge rsta_n) begin
        if(!rsta_n)
            level<=1'b0;
        else if(plusea)
            level<=~level;
        else
            level<=level;
    end
    
    //用两级寄存器同步电平信号
    always@(posedge clkb or negedge rstb_n) begin
        if(!rstb_n) begin
            syn1<=1'b0;
            syn2<=1'b0;
        end
        else begin
            syn1<=level;
            syn2<=syn1;
        end
    end
    
    //在b时钟域将同步过来的电平信号转为脉冲信号
    always@(posedge clkb or negedge rstb_n) begin
        if(!rstb_n) 
            syn2_f<=1'b0;   
        else 
            syn2_f<=syn2;
    end
    assign pluseb=syn2^syn2_f;
        
    endmodule

    1.2 单比特流数据

            对于单比特流数据而言,无论是快时钟域到慢时钟域,还是慢时钟域到快时钟域,如果不使用RAM或者FIFO这类存储空间,想直接将数据通过流的方式进行同步,是无法做到的。这是因为两个时钟域的时钟周期长度不一样,随着时间的积累,一定会发生数据的错位。因此若想同步跨时钟域的流数据,必须要借助存储器空间,否则是无法同步流数据的。需要注意的是,快时钟域到慢时钟域的流数据,是不能一直持续的,否则就需要无限大的存储空间,这在文章开头已经提到了。

    2、多比特信号

    2.1 多比特单

    (1)方法一:DUUX实现CDC

    控制信号tx_sel经两级寄存器同步后作为多路选择器的sel信号,cdc_d为发送时钟域多比特数据。tx_sel信号与cdc_d信号都需要持续一定的时间以保证能被接收时钟域采到。 

    2.2 多比特流数据

            分析方法同但比特的流数据。

    ---------------------------------------------------------------------------------------------------------------------------------

            最后需要说明的一点是,除了异步FIFO,当一个时钟域的信号送入另一个时钟域时,都需要另一个时钟域使用两级寄存器进行打拍,这是为了避免出现亚稳态的传播。但需要注意的是,一个时钟域的信号送入另一个时钟域时,这个信号必须时寄存器输出的。这是因为若不是寄存器输出,输入另一个时钟域时,就可能产生毛刺,会加大出现亚稳态的概率。虽然说即使出现亚稳态,多级寄存器同步后大概率数据也是会稳定下来的,但是发生故障的概率会随着亚稳态出现次数的增加而增加,系统的稳定性会受到影响。更为重要的是,毛刺产生的亚稳态会导致出现一个不想要出现的0或1。这我们之前讨论的亚稳态有所不同,之前讨论的出现了亚稳态,数据稳定下来后,最多也就是数据推迟一个周期来到,但这个数据我们还是需要的。但是因毛刺产生的亚稳态稳定之后,产生的0或1是我们不需要的,这个不需要的0或1如果出现在后续的电路中,且后续的电路有较强的因果关系时,整个系统都会出现错误,且难以排查。

    参考链接:

    1.你真的懂2-flop synchronizer吗-- CDC的那些事(2)

    2.常见数电面试题Pulse Synchronizer -- CDC的那些事(3)

    3.多bit信号跨时钟域怎么办?

    展开全文
  • 跨时钟域处理的3大方法,讲的很细,很清楚,很适合初学者的学习
  • 在逻辑设计领域,只涉及单个时钟域的设计并不多。尤其对于一些复杂的应用,FPGA往往需要和多个时钟域的信号进行通信。异步时钟域所涉及的两个时钟之间可能存在相位差,也可能没有任何频率关系,即通常所说的不同频...
  • 1.1 FPGA跨时钟域处理方法FIFO 1.1.1 本节目录 1)本节目录; 2)本节引言; 3)FPGA简介; 4)FPGA跨时钟域处理方法FIFO; 5)结束语。 1.1.2 本节引言 “不积跬步,无以至千里;不积小流,无以成江海。...

    1.1 FPGA跨时钟域处理方法FIFO

    1.1.1 本节目录

    1)本节目录;

    2)本节引言;

    3)FPGA简介;

    4)FPGA跨时钟域处理方法FIFO;

    5)结束语。

    1.1.2 本节引言

    “不积跬步,无以至千里;不积小流,无以成江海。就是说:不积累一步半步的行程,就没有办法达到千里之远;不积累细小的流水,就没有办法汇成江河大海。

    1.1.3 FPGA简介

    FPGA(Field Programmable Gate Array)是在PAL、GAL等可编程器件的基础上进一步发展的产物。它是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的,既解决了定制电路的不足,又克服了原有可编程器件门电路数有限的缺点。

    FPGA设计不是简单的芯片研究,主要是利用 FPGA 的模式进行其他行业产品的设计。 与 ASIC 不同,FPGA在通信行业的应用比较广泛。通过对全球FPGA产品市场以及相关供应商的分析,结合当前我国的实际情况以及国内领先的FPGA产品可以发现相关技术在未来的发展方向,对我国科技水平的全面提高具有非常重要的推动作用。

    与传统模式的芯片设计进行对比,FPGA 芯片并非单纯局限于研究以及设计芯片,而是针对较多领域产品都能借助特定芯片模型予以优化设计。

    展开全文
  • 讲述在IC设计中,跨时钟域信号同步方法6种
  • 假如设计中所有的触发器都使用一个全局网络,比如FPGA的主时钟输入,那么我们说这个设计只有一个时钟域。假如设计有两个输入时钟,如图1所示,一个时钟给接口1使用,另一给接口2使用,那么我们说这个设计中有两个...

    文章主要是基于学习后的总结。

    1. 时钟域

    假如设计中所有的触发器都使用一个全局网络,比如FPGA的主时钟输入,那么我们说这个设计只有一个时钟域。假如设计有两个输入时钟,如图1所示,一个时钟给接口1使用,另一给接口2使用,那么我们说这个设计中有两个时钟域。

    966190-20170910161527960-1397115132.png

    2. 亚稳态

    触发器的建立时间和保持时间在时钟上升沿左右定义了一个时间窗口,如果触发器的数据输入端口上数据在这个时间窗口内发生变化(或者数据更新),那么就会产生时序违规。存在这个时序违规是因为建立时间要求和保持时间要求被违反了,此时触发器内部的一个节点(或者要输出到外部的节点)可能会在一个电压范围内浮动,无法稳定在逻辑0或者逻辑1状态。换句话说,如果数据在上述窗口中被采集,触发器中的晶体管不能可靠地设置为逻辑0或者逻辑1对应的电平上。所以此时的晶体管并未处于饱和区对应的高或者低电平,而是在稳定到一个确定电平之前,徘徊在一个中间电平状态(这个中间电平或许是一个正确值,也许不是)。如图2所示,这就是所谓的亚稳态。

    966190-20170910161534054-653657163.png

    一般解决信号亚稳态有三种方法:

    1. 相位控制
      相位控制技术可以在一个时钟频率是另外一个时钟的数倍,并且其中一个时钟可以由FPGA 内部PLL 或者DLL 控制时使用。
    2. 多级寄存器
      一般针对单bit控制信号跨越两个异步时钟域传输,可以采用多级寄存器,俗称多打拍。同步电路中的第一拍后也许会产生亚稳态,但是信号有机会在其被第二级寄存以及被其它逻辑看到之前稳定下来。常用的就是对单bit信号打两拍,这也是最简单、最常见的处理方式。
    3. 异步FIFO缓存
      一般用于跨时钟域传输数据,写端和读端分别对应两个时钟域,由空/满信号控制着读写过程,实现数据的跨域传输。

    每种方法应对的情况不同,下面着重介绍最常用的单bit信号消除亚稳态的方法:多级触发器法。


    3. 多级寄存器处理

    在全同步设计中,如果信号来自同一时钟域,各模块的输入不需要使用寄存器来寄存。只要满足建立时间和保持时间的约束,可以保证在时钟上升沿到来时,输入信号已经稳定,可以采样得到正确的值。但是如果要采用输入信号的边沿来触发某一过程,则需要寄存来检测上升沿,这是另外一个范畴的问题。

    一般而言单bit信号就是我们所用到的脉冲信号或者电平信号。假设A和B是两个时钟域,各自的频率是clk_a和clk_b,clk_a的频率高于clk_b(同频相位差稳定的,不在讨论范围内),那么单bit信号传输分为两种情况。

    3.1 信号从B到A(慢到快)

    966190-20170910161545741-1470581816.png

    在时钟域B下的脉冲信号pulse_b在时钟域A看来,是一个很宽的“电平”信号会,保持多个clk_a的时钟周期,所以一定能被clk_a采到。经验设计采集过程必须寄存两拍。第一拍将输入信号同步化,同步化后的输出可能带来建立/保持时间的冲突,产生亚稳态。需要再寄存一拍,减少亚稳态带来的影响。一般来说两级是最基本要求,如果是高频率设计,则需要增加寄存级数来大幅降低系统的不稳定性。也就是说采用多级触发器来采样来自异步时钟域的信号,级数越多,同步过来的信号越稳定。

    特别需要强调的是,此时pulse_b必须是clk_b下的寄存器信号,如果pulse_b是clk_b下的组合逻辑信号,一定要先在clk_b先用D触发器(DFF)抓一拍,再使用两级DFF向clk_a传递。这是因为clk_b下的组合逻辑信号会有毛刺,在clk_b下使用时会由setup/hold时间保证毛刺不会被clk_b采到,但由于异步相位不确定,组合逻辑的毛刺却极有可能被clk_a采到。一般代码设计如下:

    always @ (posedge clk_a or negedge rst_n)
        begin
            if (rst_n == 1'b0) 
                begin
                   pules_a_r1 <= 1'b0;
                   pules_a_r2 <= 1'b0;
                   pules_a_r3 <= 1'b0;
                end
            else 
                begin                                   //打3拍
                   pules_a_r1 <= pulse_b;
                   pules_a_r2 <= pules_a_r1;
                   pules_a_r3 <= pules_a_r2;
                end
        end
    
    assign pulse_a_pos  = pules_a_r2 & (~pules_a_r3);   //上升沿检测
    assign pulse_a_neg  = pules_a_r3 & (~pules_a_r2);   //下降沿检测
    assign pulse_a      = pules_a_r2;
    

    实际上,具体打几拍背后是有时序收敛的理论作支撑的,对于一般的设计而言,打两三拍就已经足够了。

    3.2 信号从A到B(快到慢)

    966190-20170910161559429-1951738620.png

    如果单bit信号从时钟域A到时钟域B,那么存在两种不同的情况,传输脉冲信号pulse_a或传输电平信号level_a。实际上,在一般情况下只有电平信号level_a的宽度能被clk_b采集到才可以保证系统正常工作。那么对于脉冲信号pulse_a采取怎样的处理方法呢?可以用一个展宽信号来替代pulse_a实现垮时钟域的握手。

    主要原理就是先把脉冲信号在clk_a下展宽,变成电平信号signal_a,再向clk_b传递,当确认clk_b已经“看见”信号同步过去之后,再清掉signal_a。代码通用框架如下:

    module Sync_Pulse (
                      clk_a,        
                      clk_b,   
                      rst_n,            
                      pulse_a_in,   
                     
                      pulse_b_out,  
                      b_out 
                      );
    /****************************************************/
    
        input               clk_a;
        input               clk_b;
        input               rst_n;
        input               pulse_a;
        
        output              pulse_b_out;
        output              b_out;      
        
    /****************************************************/  
    
        reg                 signal_a;
        reg                 signal_b;
        reg                 signal_b_r1;
        reg                 signal_b_r2;
        reg                 signal_b_a1;
        reg                 signal_b_a2;
        
    /****************************************************/
        //在时钟域clk_a下,生成展宽信号signal_a
        always @ (posedge clk_a or negedge rst_n)
            begin
                if (rst_n == 1'b0)
                    signal_a <= 1'b0;
                else if (pulse_a_in)            //检测到到输入信号pulse_a_in被拉高,则拉高signal_a
                    signal_a <= 1'b1;
                else if (signal_b_a2)           //检测到signal_b1_a2被拉高,则拉低signal_a
                    signal_a <= 1'b0;
                else;
            end
        
        //在时钟域clk_b下,采集signal_a,生成signal_b
        always @ (posedge clk_b or negedge rst_n)
            begin
                if (rst_n == 1'b0)
                    signal_b <= 1'b0;
                else
                    signal_b <= signal_a;
            end
        //多级触发器处理
        always @ (posedge clk_b or negedge rst_n)
            begin
                if (rst_n == 1'b0) 
                    begin
                        signal_b_r1 <= 1'b0;
                        signal_b_r2 <= 1'b0;
                    end
                else 
                    begin
                        signal_b_r1 <= signal_b;        //对signal_b打两拍
                        signal_b_r2 <= signal_b_r1;
                    end
            end
        //在时钟域clk_a下,采集signal_b_r1,用于反馈来拉低展宽信号signal_a
        always @ (posedge clk_a or negedge rst_n)
            begin
                if (rst_n == 1'b0) 
                    begin
                        signal_b_a1 <= 1'b0;
                        signal_b_a2 <= 1'b0;
                    end
                else 
                    begin
                        signal_b_a1 <= signal_b_r1;     //对signal_b_r1打两拍,因为同样涉及到跨时钟域   
                        signal_b_a2 <= signal_b_a1;
                    end
            end
    
        assign  pulse_b_out =   signal_b_r1 & (~signal_b_r2);
        assign  b_out       =   signal_b_r1;
    
    endmodule
    

    这样一来,实际上clk_a下的脉冲信号“作用”到了clk_b时钟域下,它对于clk_a与clk_b的时钟频率关系没有任何限制,快到慢,慢到快就都没问题了。

    总而言之,在设计中可以简单的牢记以下五条原则:
    1. 再全局时钟的跳变沿最可靠。
    2. 来自异步时钟域的输入需要寄存一次以同步化,再寄存一次以减少亚稳态带来的影响。
    3. 不需要用到跳变沿的来自同一时钟域的输入,没有必要对信号进行寄存。
    4. 需要用到跳变沿的来自同一时钟域的输入,寄存一次即可。
    5. 需要用到跳变沿的来自不同时钟域的输入,需要用到3个触发器,前两个用以同步,第3个触发器的输出和第2个的输出经过逻辑门来判断跳变沿。

    3.3 设计分区同步器模块

    在顶层为设计分区是一个好的设计实践行为,这样任何功能模块外面都包含一个独立的同步器模块。这样有利于在划分模块的基础上实现所谓的理想时钟域情况(即整个设计模块只有一个时钟),如下图所示:
    966190-20170910161615382-433558239.png

    对设计进行分区有很多理由。首先,对每个独立的功能模块进行时序分析变得简易,因为模块都是完全的同步设计。其次,整个同步模块中的时序例外也很容易得到定义。再次,底层模块的同步器加时序例外在代入到设计顶层时,大大降低了由于人为失误造成的疏漏。所以,同步寄存器应该在功能模块外单独分区。


    参考:

    Verilog基本电路设计之一(单bit跨时钟域同步)
    异步时钟的同步化,俗称“慢打一拍",寄存一拍
    高级FPGA设计:第六章 时钟域(译文)

    转载于:https://www.cnblogs.com/rouwawa/p/7501319.html

    展开全文
  • 上次提出了一个处于异步时钟域的MCU与FPGA直接通信的实现方式,其实在这之前,特权同学想列举一个异步时钟域中出现的很典型的问题。也就是要用一个反例来说明没有足够重视异步通信会给整个设计带来什么样的危害。
  • FPGA跨时钟域处理方法

    万次阅读 多人点赞 2018-09-07 14:25:26
    一、时钟域 如果一个设计全局只使用了一个时钟,那么此设计有一个时钟域。如果在一个设计中有两个时钟去控制不同的接口,那么就称这个设计中有两个时钟域。如下图所示 当时钟不匹配时,就要进行同步化,否则就...
  • 跨时钟域处理三大方法

    万次阅读 多人点赞 2017-09-07 22:51:54
    在本篇文章中,主要介绍3种跨时钟域处理方法,这3种方法可以说是FPGA界最常用也最实用的方法,这三种方法包含了单bit和多bit数据的跨时钟域处理,学会这3招之后,对于FPGA相关的跨时钟域数据处理便可以手到擒来。
  • 跨时钟域信号处理方法: 1.两拍同步 2.使用握手协议 3.使用异步FIFO
  • 本文介绍的3种方法跨时钟域处理方法如下第一种方法:打两拍第二种方法:异步双口RAM第三种方法:格雷码转换 跨时钟域处理方法如下 跨时钟域处理是FPGA设计中经常遇到的问题,而如何处理好跨时钟域间的数据,可以说是...
  • 上次提出了一个处于异步时钟域的MCU与FPGA直接通信的实现方式,其实在这之前,特权同学想列举一个异步时钟域中出现的很典型的问题。也就是要用一个反例来说明没有足够重视异步通信会给整个设计带来什么样的危害。 ...
  • 单bit:两级触发器同步(适用于慢到快) ...跨时钟域处理https://www.cnblogs.com/ninghechuan/p/9828705.html 跨时钟域信号传输(一)——控制信号篇 https://www.cnblogs.com/IClearner/p/6485389.html 跨时钟...
  • Verilog--CDC跨时钟域处理(快时钟域到慢时钟域)CDC问题单比特信号的跨时钟域问题从快时钟域到慢时钟域从慢时钟域到快时钟域多比特信号的跨时钟域问题异步FIFO握手协议 今天先写单比特信号从快时钟域到慢时钟域的...
  • 跨时钟域处理(CDC)

    2021-09-04 10:17:33
    信号跨时钟域传输时,两个时钟的上升沿相位差没有固定关系,所以采样时钟很容易出现建立保持时间违例而采到亚稳态。 不做处理 如图,如果不做处理,A信号建立保持时间违例,导致B为亚稳态,对下游很危险。(B之后是...
  • 跨时钟域处理方式

    2019-01-28 19:19:00
    假如设计中所有的 D 触发器都使用一个全局网络 GCLK ,比如 FPGA 的主时钟输入,那么我们说这个设计只有一个时钟域。假如设计有两个输入时钟,分别给不同的接口使用,那么我们说这个...跨时钟域处理方式: 1、对于...
  • FPGA跨时钟域处理3大方法1 打两拍2 异步双口RAM3 格雷码转换 跨时钟域处理是FPGA设计中不可避免的问题,而如何处理好跨时钟域间的数据,可以说是每个FPGA...这里介绍的三种方法跨时钟域处理方法如下: 打两拍 异步双
  • 跨时钟域处理

    2018-08-30 09:00:05
    跨时钟域处理是FPGA和ASIC中非常常见的问题,这里有详细的文档介绍了6中跨时钟域处理的中文文档。
  • 本文我们主要来讨论一下基于FPGA的跨时钟域信号处理同步设计的重要,希望能对你的学习有所帮助。
  • 点击上方“蓝字”,学习更多干货!在数字电路中,跨时钟域处理是个很庞大的问题,因此将会作为一个专题来陆续分享。今天先来从处理单bit跨时钟域信号同步问题来入手。01握手(handshake...
  • 转:https://blog.csdn.net/darknessdarkness/article/details/105153216 跨时钟域处理–最终详尽版 文章目录 跨时钟域处理--最终详尽版 1. 异步时序定义 2. 亚稳态 3. 单比特同步策略 方法一:双锁存器 注意问题1 ...
  • 解决跨时钟域问题的三大方法

    万次阅读 多人点赞 2018-10-07 09:51:51
    在本篇文章中,主要介绍3种跨时钟域处理方法,这3种方法可以说是FPGA界最常用也最实用的方法,这三种方法包含了单bit和多bit数据的跨时钟域处理,学会这3招之后,对于FPGA相关的跨时钟域数据处理便可以手到擒来。...
  • Clock Domain Crossing (CDC) Design & Verification Techniques Using SystemVerilog 外文经典
  • 点击上方“蓝字”,学习更多干货!上篇文章介绍了基本的握手电路,以及为了防止漏采样而设计的带输出“同步失败”信号的改进握手电路,这次我们介绍一下与”握手“相似但不同的处理单bit跨时钟域的...
  • 方法只用于慢到快时钟域的1bit信号传递。 module ff2( input clk0,//10M input din, input clk1,//100M output dout ); reg din_r=1'd0; reg r0=1'd0; reg r1=1'd0; assign dout = r1; always@(posedge ...
  • FPGA跨时钟域处理方式

    2020-01-03 14:42:54
    跨时钟处理有三种方式: 控制信号脉冲检测法,适合于快时钟采慢时钟; 握手信号法,适合慢时钟采快时钟; 异步fifo法,适合大量数据的传输 脉冲检测法 在快时钟的上升沿,使用两级或三级寄存器,检测慢时钟域的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,217
精华内容 2,486
关键字:

跨时钟域处理方法