• 跨时钟域处理方法


    1、亚稳态 

    亚稳态问题:亚稳态问题_发光中请勿扰的博客-CSDN博客

    原因:由于触发器的建立时间和保持时间不满足,当触发器进入亚稳态,使得无法预测该单元的输出,这种不稳定是会沿着信号通道的各个触发器级联传播。

    减少亚稳态的方法有以下几种:
    (1)使用同步器:比如常用的2级或者多级FF打拍的方法
    (2)降低频率:如果能满足功能要求,降低频率能够减少亚稳态的发生
    (3)避免变化过快或者过于频繁的信号进行跨时钟采样
    (4)采用更快的触发器:更快的触发器,也可以亚稳态的产生
    (5)改善时钟质量,用边沿变化快速的时钟信号消除

    为什么两级触发器可以防止亚稳态传播?
            假设第一级触发器的输入不满足其建立保持时间,它在第一个脉冲沿到来后输出的数据就为亚稳态,那么在下一个脉冲沿到来之前,其输出的亚稳态数据在一段恢复时间后必须稳定下来,而且稳定的数据必须满足第二级触发器的建立时间,如果都满足了,在下一个脉冲沿到来时,第二级触发器将不会出现亚稳态,因为其输入端的数据满足其建立保持时间。

    2、跨时钟信号处理方法

            跨时钟域的信号可以分为单bit信号和多bit信号。
            单bit:两级触发器同步(适用于慢到快)
            多bit:采用异步FIFO,异步双口RAM 加握手信号 格雷码转换

    从慢到快
    单bit:两级触发器(延迟打拍)

    从快到慢:
    单bit:
    1.电平信号同步:两级触发器(延迟打拍)
    2.脉冲信号同步:脉冲信号脉宽是一致的,两个时钟域频率比已知:快时钟域脉冲展宽+慢时钟域打两拍。
                                脉冲信号有时候表现为电平信号:握手传输。

    为何多bit信号不能采用打两拍的方法进行跨时钟域同步?

            每个寄存器的位置不同,布局布线会导致每比特数据到达下一级寄存器的延时不同,因此可能会采样的中间变化的任何值。

    为什么快到慢不能直接和慢到快这种情况一样采用两级寄存器打拍的方式?

            快时钟域信号变化快,慢时钟域信号采样时容易造成采样丢失,或者直接采不到,例如对快时钟域的脉冲检测。如果不经特殊处理,极有可能就采不到信号。

    慢到快使用打两拍同步的前提条件为?

            1.传输的是单bit数据
            2.周期不要太接近,频率比最好能大于或等于二,满足时序约束。

    2.1 跨时钟域处理方法:

    • 1、打2拍

            打两拍的方式常见于处理单bit数据的跨时钟域问题。打两拍的方式,其实说白了,就是定义两级寄存器,对输入的数据进行延拍。如下图所示。

    one_bit

            两级寄存器的原理:两级寄存是一级寄存的平方,两级并不能完全消除亚稳态危害,但是提高了可靠性减少其发生概率。总的来讲,就是一级概率很大,三级改善不大

            data是时钟域1的数据,需要传到时钟域2(clk)进行处理,寄存器1和寄存器2使用的时钟都为clk。假设在clk的上升沿正好采到data的跳变沿(从0变1的上升沿,实际上的数据跳变不可能是瞬时的,所以有短暂的跳变时间),那这时作为寄存器1的输入到底应该是0还是1呢?这是一个不确定的问题。所以Q1的值也不能确定,但至少可以保证,在clk的下一个上升沿,Q1基本可以满足第二级寄存器的保持时间和建立时间要求,出现亚稳态的概率得到了很大的改善。

            如果再加上第三级寄存器,由于第二级寄存器对于亚稳态的处理已经起到了很大的改善作用,第三级寄存器在很大程度上可以说只是对于第二级寄存器的延拍,所以意义是不大的。

    • 2、异步双口RAM

            处理多bit数据的跨时钟域,一般采用异步双口RAM。假设我们现在有一个信号采集平台,ADC芯片提供源同步时钟60MHz,ADC芯片输出的数据在60MHz的时钟上升沿变化,而FPGA内部需要使用100MHz的时钟来处理ADC采集到的数据(多bit)。

            在这种类似的场景中,我们便可以使用异步双口RAM来做跨时钟域处理。先利用ADC芯片提供的60MHz时钟将ADC输出的数据写入异步双口RAM,然后使用100MHz的时钟从RAM中读出。

            对于使用异步双口RAM来处理多bit数据的跨时钟域,相信大家还是可以理解的。当然,在能使用异步双口RAM来处理跨时钟域的场景中,也可以使用异步FIFO来达到同样的目的。

    • 3、格雷码转换

        我们依然继续使用介绍第二种方法中用到的ADC例子,将ADC采样的数据写入RAM时,需要产生RAM的写地址,但我们读出RAM中的数据时,肯定不是一上电就直接读取,而是要等RAM中有ADC的数据之后才去读RAM。这就需要100MHz的时钟对RAM的写地址进行判断,当写地址大于某个值之后再去读取RAM。

            在这个场景中,其实很多人都是使用直接用100MHz的时钟于RAM的写地址进行打两拍的方式,但RAM的写地址属于多bit,如果单纯只是打两拍,那不一定能确保写地址数据的每一个bit在100MHz的时钟域变化都是同步的,肯定有一个先后顺序。如果在低速的环境中不一定会出错,在高速的环境下就不一定能保证了。所以更为妥当的一种处理方法就是使用格雷码转换。

            对于格雷码,相邻的两个数间只有一个bit是不一样的,如果先将RAM的写地址转为格雷码,然后再将写地址的格雷码进行打两拍,之后再在RAM的读时钟域将格雷码恢复成10进制。这种处理就相当于对单bit数据的跨时钟域处理了。

    2.2 单bit信号跨时钟域的处理

    信号跨时钟域,根据两个异步时钟之间的关系可以分为:
    (1)信号从快时钟域到慢时钟域
    (2)信号从慢时钟域到快时钟域

            单bit信号一般采用同步器来做CDC(clock domain crossing)。由于在CDC时,会在源时钟域做寄存器输出,所以信号的变化频率不会超过源时钟的频率,所以这里可用两个时钟间的快慢来分类。

    快时钟域到慢时钟域:

            由于快时钟域信号频率变化快,导致慢时钟域的时钟信号可能采样不到快时钟域下有效的信号的边沿。这时,就需要使用脉冲同步器进行同步。
            脉冲同步器的结构和时序图如下:
    在这里插入图片描述

            首先,脉冲同步器的作用就是:在快时钟域取出一个单时钟周期宽度的脉冲,然后在经过慢时钟域两级同步和后一级触发器打拍,逻辑异或后产生一个慢时钟下单时钟周期宽度的同步脉冲。
            因为慢时钟很有可能采样不到快时钟,所以需要通过快时钟域下的翻转电路,将快时钟域下前后间隔较多个周期的两个有效脉冲进行标定,形成上图所示的Toggle信号脉冲。
            然后,先通过同步电路将Toggle信号进行同步,形成上图所示的A、B信号波形。
            最后用组合电路做A^B,得到慢时钟域下两个有效的单周期脉冲。

    在这里插入图片描述

    1. module asy_1bit_fast2slow(
    2. input clk1, //快时钟
    3. input clk2, //慢时钟
    4. input rstn,
    5. input din,
    6. output dout
    7. );
    8. reg toggle;
    9. reg q1,q2,q3;
    10. //------产生Toggle信号------
    11. always@(posedge clk1 or negedge rstn) begin
    12. if(!rstn)begin
    13. toggle <= 1'b0;
    14. end
    15. else if(din) begin
    16. toggle <= ~toggle;
    17. end
    18. else begin
    19. toggle <= toggle;
    20. end
    21. end
    22. //------同步打拍-------
    23. assign dout = q2 ^ q3; //输出同步后的脉冲信号
    24. always@(posedge clk2 or negedge rstn) begin
    25. if(!rstn)begin
    26. {q3,q2,q1} <= 3{1'b0};
    27. end
    28. else begin
    29. {q3,q2,q1} <= {q2,q1,toggle};
    30. end
    31. end
    32. endmodule

            

    信号从快时钟域到慢时钟域CDC如下图所示:

           当在aclk中生成的信号adat被送到了另一个时钟域bclk中采样,由于采样时间太靠近第二个时钟的上升沿,发生的同步失败。同步失败是由于输出bdat1变为亚稳态,而在bdat1再次被采样时没有收敛到合法的稳定状态。

           如果是电平信号进行CDC,不用考虑时钟快慢,直接用同步器就可以,因为总能被采样到。

           快时钟到慢时钟的(单bit)信号处理,主要问题是信号在快时钟域中,可能会多次改变,这样慢是可能来不及采样导致数据丢失。这个问题被称为信号宽度问题,在CDC检查工具中,如果快时钟的信号宽度不足,就会报出CDC违例。

    快时钟到慢时钟的(单bit)信号处理分为两种:
            (1)采样丢失是被允许的。单bit信号一般不会是这种情况,如果是,直接用同步器同步就行。
            (2)采样丢失不被允许。这样就用其他手段来保证数据不丢失。主要原理是保证快时钟与慢时钟的信号宽度满足一定的条件,使得慢时钟域有足够时间采样到。

    信号宽度的“三时钟沿”要求
            比较安全的宽度是,快时钟域的信号宽度必须是慢时钟域周期的1.5倍以上。也就是要持续3个时钟沿以上(上升沿和下降沿都算)。这个被称为“三时钟沿”要求。

    例子:

    跨时钟域处理从快时钟域到慢时钟域根据信号宽度可以分为两种情况,如第一个图所示,ckl_b则可以采样到signal_a_in,但是如第二个图所示,只有单脉冲,就不能确保可以采样到signal_a_in。这种情况用两级触发器同步是没有用的。

    所以针对第二种情况需要特殊处理,如下所示为针对第二种跨时钟域的处理代码:

    1. //----------------快时钟域到慢时钟域----------------//
    2. module mul_clk(
    3. input clk_a,
    4. input clk_b,
    5. input rst_n,
    6. input pulse_a,
    7. output pulse_b
    8. );
    9. reg signal_a;
    10. reg signal_b;
    11. reg [1:0]signal_a_r;
    12. reg [1:0]signal_b_r;
    13. //----------时钟域A下进行脉冲pulse_a的展宽------------//
    14. always@(posedge clk_a or negedge rst_n)begin
    15. if(!rst_n)
    16. signal_a <= 1'b0;
    17. else if(pulse_a)
    18. signal_a <= 1'b1;
    19. else if(signal_a_r[1])
    20. signal_a <= 1'b0;
    21. else
    22. signal_a <= signal_a;
    23. end
    24. //--------时钟域B下采集时钟域A拓展的脉宽信号signal_a-------//
    25. always@(posedge clk_b or negedge rst_n)begin
    26. if(!rst_n)
    27. signal_b <= 1'b0;
    28. else
    29. signal_b <= signal_a;
    30. end
    31. //-------时钟域B下缓存signal_b信号,生成时钟域B下的脉冲------//
    32. always@(posedge clk_b or negedge rst_n)begin
    33. if(!rst_n)
    34. signal_b_r <= 2'b00;
    35. else
    36. signal_b_r <= {signal_b_r[0],signal_b};
    37. end
    38. assign pulse_b = ~signal_b_r[1] & signal_b_r[0];
    39. //--------时钟域A下采集signal_b_r,反馈到时钟域A控制signal_a拉低------//
    40. always@(posedge clk_a or negedge rst_n)begin
    41. if(!rst_n)
    42. signal_a_r <= 2'b00;
    43. else
    44. signal_a_r <= {signal_a_r[0],signal_b_r[1]};
    45. end
    46. endmodule

    慢时钟到快时钟域:

            慢时钟域到快时钟域的CDC,只需要使用边沿检测同步器即可,用两级触发器打两拍同步信号。

            目标时钟频率必须是源时钟频率1.5倍或者以上,才能算慢时钟到快时钟的CDC。只有满足快1.5倍以上,才能满足“三时钟沿要求”。才能保证快时钟域能够采样到慢时钟域的脉冲。如果目标时钟域只快一点,为保险起见,还是用握手机制。有的设计中为了保险和以后修改的方便,或者不清楚时钟之间的关系,都会按照握手机制来处理。

    如果对于单bit信号来说,慢时钟域到快时钟域使用两级触发器就可以,代码如下图所示:

    1. //---------慢时钟域到快时钟域----------//
    2. module mul_clk(
    3. input clk, //快时钟域时钟
    4. input rst_n,
    5. input pulse_a,
    6. output pulse_b
    7. );
    8. reg [1:0]pulse_r;
    9. always@(posedge clk or negedge rst_n)begin
    10. if(!rst_n)
    11. pulse_r <= 2'b00;
    12. else
    13. pulse_r <= {pulse_r[0],pulse_a};
    14. end
    15. assign pulse_b = pulse_r[1];
    16. endmodule
    1. module asy_1bit_slow2fast(
    2. input clk1, //慢时钟
    3. input clk2, //快时钟
    4. input rstn,
    5. input data,
    6. output dout
    7. );
    8. reg q1,q2,q3;
    9. assign dout = q2 & (~q3);
    10. //------同步打拍-------
    11. always@(posedge clk2 or negedge rstn) begin
    12. if(!rstn)begin
    13. {q3,q2,q1} <= 3{1'b0};
    14. end
    15. else begin
    16. {q3,q2,q1} <= {q2,q1,data};
    17. end
    18. end
    19. endmodule

            data是来自慢时钟域的单比特信号,clk2是快时钟域的时钟。时序图如下所示,经过两级触发器同步两拍后,会产生一个AND(A)信号波形,再经过后一级触发器同步,会产生一个AND(B)的信号,两个信号经过逻辑电路处理,产生一个Output信号脉冲,信号宽度为快时钟域一个时钟周期宽度。

    总结:单比特信号在经过边沿检测同步器同步后,会将慢时钟域下宽频的信号脉冲搬移并缩小为快时钟域下一个时钟周期的同步脉冲。
    使用条件:使用边沿检测同步器进行单比特信号的跨时钟同步是有一定的条件,只有满足条件,才能进行有效同步。

    • 慢时钟域下的单比特信号的脉冲宽度,必须要大于或等于快时钟域下2个时钟周期。这样才能保证慢时钟域的脉冲信号是足够保持到被快时钟域的同步器拿到。

    2.3 多个信号跨时钟的处理

    多个信号CDC策略可以分为以下几种:
    (1)多个信号合并,在可能的情况下,将多个CDC合并为1位的CDC信号
    (2)多周期路径发。使用同步负载信号安全地传递多个CDC位。
    (3)使用格雷码传递多个CDC位
    (4)使用异步FIFO来传递多位信号
    (5)使用DMUX电路结构进行多位信号传

  • 相关阅读:
    易语言软件定制软件开发脚本开发协议软件电脑网站APP应用视频制作工程制作
    2、Kafka进阶提升-生产者
    警告-Ubuntu提示W: Possible missing firmware xxx解决方法
    拓展卡尔曼滤波(Kalman)附Matlab代码
    大事务问题到底要如何解决?
    nginx-proxy反向代理流程
    html+css+js网页设计 旅游 大理旅游7个页面
    【无标题】
    [git] 根据master更新本地分支
    矩阵 m * M = c
  • 原文地址:https://blog.csdn.net/qq_44933149/article/details/126363670