亚稳态及信号跨时钟域处理


一、亚稳态简介

  亚稳态的产生:一个信号在一个时钟域变化,并在另一个时钟域被采样,就会导致输出成为亚稳态。
本质上是由于违背了触发器的建立和保持时间产生的;
  亚稳态的危害:导致逻辑判断错误、亚稳态传播(下一级电路同样产生亚稳态)

在这里插入图片描述
  建立时间(Tsu,set up time):时钟有效边沿到来前,要求数据保持稳定的最小时间;
  保持时间(Th, hold time):时钟有效边沿到来后,要求数据保持稳定的最小时间;
  输出延迟值(Tco):规定的时钟到输出的延迟值;
  决断时间(Tmet):亚稳态输出恢复到稳态所超出tco的额外的时间;

  亚稳态导致触发器在原有的输出延迟tco上多出一段决断时间tmet,在这段时间之后,触发器最终由亚稳态转向稳态;
  一般来说,触发器会在一个或两个时钟周期内返回稳态;

二、亚稳态窗口

  具有特定时间长度的窗口,在这段时间内,输入数据与时钟均应该保持不变;
在这里插入图片描述
  亚稳态窗口越大,进入亚稳态的概率越高;


三、平均无故障时间(MTBF)

  单级触发器的平均无故障时间
  MTBF1 = e(tr/τ)/W·fc·fd
  tr : 允许超出器件正常传输延迟时间的解析时间
  τ: 触发器的亚稳态解析时间常数
  W: 亚稳态窗口
  fc: 时钟频率
  fd: 异步信号边沿频率
  两级触发器的平均无故障时间
  MTBF2 = e(tr1/τ)/W·fc·fd × e(tr2/τ)

  若单级同步器的MTBF为40s,则两级同步器的MTBF为40 × 40 = 26.6min
  可见信号经过两级触发器后,平均无故障时间明显增加,这也是多级同步器的原理;


四、亚稳态产生场景

亚稳态产生:违背时序要求
  1.输入信号为异步(中断、复位)
  2.时钟偏移、时钟抖动,高于容限值
  3.信号在两个不同频率或者相同频率但相位、偏移不同的时钟下工作(跨时钟域)
  4.组合逻辑延迟使得触发器的数据输入在亚稳态窗口内发生变化


五、解决亚稳态的技术

5.1 单比特信号跨时钟域

5.1.1 多级同步器

  多级同步器的原理可参考第三节平均无故障时间的计算;
  使用一个完整的时钟周期来降低亚稳态发生的概率(不能解决);
  应用场景:
  单/多比特数据,从慢时钟域进入到快时钟域(频率差2倍),此时不会丢失数据;
  若处理的数据从快时钟域到慢时钟域 ,可能会发生数据丢失(漏采样);
  输出会有Lantency,视级数而定(1级-1Lantency 2级-2Lantency);

module Multiple_stage_synchronizermodule#(
        parameter integer DFF_LEVEL  = 2,
        parameter integer DATA_WIDTH = 1
)(
        input wire                     clk,
        input wire [DATA_WIDTH - 1:0]  din,
        input wire [DATA_WIDTH - 1:0] dout,
        input wire                    nrst
    );

    reg [DATA_WIDTH - 1:0] din_buff [DFF_LEVEL-1:0];
    assign dout = din_buff[DFF_LEVEL-1];
    integer i;

    always @(posedge clk or negedge nrst) begin
        if (~nrst) begin
            // reset
            for(i=0;i<DFF_LEVEL;i=i+1)
            begin
                din_buff[i] <= 'b0;
            end
        end
        else begin
            for(i=1;i<DFF_LEVEL;i=i+1)
            begin
                din_buff[i] <= din_buff[i-1];
            end
                din_buff[0] <= din;
        end
    end
    
endmodule

综合电路
在这里插入图片描述

5.1.2 另一种多级同步器

普通多级同步器存在的问题
  要求异步信号的脉宽必须大于时钟周期(采样不到);
  要求异步信号的时钟域1时钟频率小于时钟域2(漏采);

同步器B模式
  可以从快时钟域采样信号;
  不需要异步信号的脉宽大于时钟周期;
  常用于中断信号、复位信号的同步;

module Multiple_stage_synchronizermoduleB(  
        input     wire      din,
        input     wire    s_clk,
        input     wire       en,
        input     wire     nrst,
        output    wire     dout
    );
    
    wire    Q1_Clr;//µÚÒ»¼¶´¥·¢Æ÷¸´Î»ÐźÅ
    reg     Q1_out,Q2_out,Q3_out;
    assign Q1_Clr = ~din & dout;
    assign dout = Q3_out;
    always@(posedge din,posedge Q1_Clr)
    begin
        if(Q1_Clr)
        begin
            Q1_out <= 1'b0;
        end
        else
        begin
            Q1_out <= 1'b1;
        end
    end
    
    always@(posedge s_clk)
    begin
        if(~nrst)
        begin
            Q2_out <= 1'b0;
            Q3_out <= 1'b0;
        end
        else
        begin
            if(en)
            begin
                Q3_out <= Q2_out;
                Q2_out <= Q1_out;
            end
            else
            begin
                Q3_out <= Q3_out;
                Q2_out <= Q2_out;
            end
        end
    end 
endmodule

综合电路
在这里插入图片描述

5.2 多比特信号跨时钟域处理

5.2.3 握手协议

  应用于单比特或多比特信号的跨时钟域处理上;
  发送端在dout数据准备好后,拉高dqvldo信号;
  接收端在可以接收数据时拉高ready信号,当检测到dqvldi与ready信号同时为高时,立即取走数据,并拉低ready信号;
  发送端在接收到ready信号为低时,拉低dqvld信号;
在这里插入图片描述发送端:

module Handshake_M#(
    parameter integer DATA_WIDTH = 8
    )(
        input  wire                             m_clk,
        input  wire                              nrst,
        input  wire [DATA_WIDTH - 1 : 0]          din,
        input  wire                          dinvalid,
        output wire [DATA_WIDTH - 1 : 0]         dout,
        input  wire                            readyi,
        output wire                              wren,
        output wire                            dqvldo
    );

    reg [DATA_WIDTH - 1 : 0]     dout_o;
    reg                         dqvld_o;
    reg                           wr_en;

    //inner signals connect 
    assign dout = dout_o;
    assign dqvldo = dqvld_o;
    assign wren = wr_en;

    always@(posedge m_clk)
    begin
        if(~nrst)
        begin
            dout_o <= 'b0;
        end
        else begin
            if(wr_en&dinvalid)
                dout_o <= din;
            else begin
                dout_o <= dout_o;
            end
        end
    end

    always @(posedge m_clk ) begin
        if (~nrst) begin
            // reset
            dqvld_o <= 1'b0;
            wr_en <= 1'b1;
        end
        else
        begin
            if((wr_en == 1'b1) && (dqvld_o == 1'b0)&(dinvalid==1'b1))
            begin    
                dqvld_o <= 1'b1;
                wr_en <= 1'b0;
            end
            else if((wr_en == 1'b0) && (dqvld_o == 1'b1) && (readyi == 1'b1))
            begin
                dqvld_o <= 1'b0;
                wr_en <= 1'b1;
            end
        end
    end


endmodule

接收端:

module Handshake_S#(
    parameter integer DATA_WIDTH = 8
    )(
        input  wire                         s_clk,
        input  wire                          nrst,
        input  wire [DATA_WIDTH - 1 : 0]      din,
        input  wire                       doutvalid,
        output wire [DATA_WIDTH - 1 : 0]     dout,
        output  wire                        readyo,
        input wire                          dqvldi
    );

    wire r_en;
    reg [DATA_WIDTH - 1 : 0] dout_o;
    reg                      ready_o;

    assign r_en = dqvldi & readyo & doutvalid;

    //inner signal connect
    assign dout = dout_o;
    assign readyo = ready_o;

    always @(posedge s_clk) begin
        if (~nrst) begin
            // reset
            ready_o <= 1'b1;
        end
        else
        begin
            if((readyo & dqvldi)||(doutvalid == 1'b0))
            begin
                ready_o <= 1'b0;
            end
            else begin
                ready_o <= 1'b1;
            end
        end
    end

    always @(posedge s_clk)
    begin
        if(~nrst)
        begin
            dout_o <= 'b0;
        end
        else begin
            if(r_en)
            begin
                dout_o <= din;
            end
            else begin
                dout_o <= dout_o;
            end
        end
    end

endmodule

握手协议的三种握手情况
  1.valid信号与ready信号同时有效:立即完成传输
测试程序

`timescale 1ns / 1ps
module cdc_test(

    );
        
         parameter integer DATA_WIDTH = 8;

        reg                           clk;
        reg                          nrst;
        reg [DATA_WIDTH - 1 : 0]      m_din;
        reg                        dinvalid;
        wire [DATA_WIDTH - 1 : 0]    dout;
        wire [DATA_WIDTH - 1 : 0]    s_dout;
        wire                         ready;
        wire                         wren;
        wire                        dqvld;


        initial begin
            clk = 0;
            forever begin
                #1 clk = ~clk;
            end
        end

        initial begin
            nrst = 0;
        #2  nrst = 1;
        end

        always @(posedge clk ) begin
            if (~nrst) begin
                // reset
                m_din <= 'b0;
                dinvalid <= 1'b0;
            end
            else if (wren) begin
                dinvalid <= 1'b1;
                m_din <=m_din + 1'b1;
            end
        end

    Handshake_M#(
    .DATA_WIDTH (DATA_WIDTH)
    )Handshake_M_inist0(
        . m_clk(clk),
        .  nrst(nrst),
        .   din(m_din),
        . dinvalid(dinvalid),
        .  dout(dout),
        .readyi(ready),
        . wren(wren),
        .dqvldo(dqvld)
    );

    Handshake_S#(
    .DATA_WIDTH (DATA_WIDTH)
    )Handshake_S_inist0(
        . s_clk(clk),
        .  nrst(nrst),
        .   din(dout),
        .  dout(s_dout),
        . readyo(ready),
        . dqvldi(dqvld)
    );

endmodule

在这里插入图片描述2.ready信号先有效,valid信号后有效
在这里插入图片描述3.valid信号先有效,ready信号后有效
在这里插入图片描述

5.2.4 FIFO

可以看之前FIFO的文章《各种FIFO硬件设计(FIFO概念、异步、同步、非2次幂深度FIFO)》

5.2.5 FIFO实现握手协议

  握手协议也可以看成一个深度的FIFO
  所以也可以通过FIFO来实现;
  输入端readyo产生条件
  FIFO非满(FIFO可以继续写入,允许数据进入)
  输出端valido产生条件
  FIFO非空(FIFO中有数据,可以继续读出)
  FIFO写使能 wr_en产生条件
  FIFO非满且输入数据有效信号validi有效;
  FIFO读使能rd_en产生条件
  FIFO非空且来自下一级的readyi信号有效;

module Handshake_fifo#(
    parameter integer DATA_WIDTH = 8
    )(
        input wire                       clk_w,
        input wire                       clk_r,
        input wire                        nrst,
        input wire  [DATA_WIDTH-1:0]       din,
        input wire                      validi,
        input wire                      readyi,
                    
        output wire                     valido,
        output wire                     readyo,
        output wire [DATA_WIDTH-1:0]      dout
    );

     //BLOCK RAM address width 
        parameter   integer RAM_ADDR_WIDTH = 5;
        //FIFO true depth
        parameter   integer FIFO_DATA_DEPTH = 1;
        //FIFO degth's margin
        parameter   integer FIFO_DATA_DEPTH_MARGIN = 2;
        //FIFO compensate depth,(FIFO_DATA_DEPTH+FIFO_DEPTH_COMPLE) must be the data of power 2
        parameter   integer FIFO_DEPTH_COMPLE = 0;
        parameter   integer FIFO_DATA_WIDTH = 8;


    wire fifo_full;
    wire fifo_empty;
    wire wr_en;
    wire rd_en;

    assign  valido = ~fifo_empty;
    assign  readyo = ~fifo_full;
    assign  wr_en = (~fifo_full) & validi;
    assign  rd_en = readyi & (~fifo_empty);

    Asynchronous_FIFO_npow2#(
        //BLOCK RAM address width 
        . RAM_ADDR_WIDTH (RAM_ADDR_WIDTH),
        //FIFO true depth
        . FIFO_DATA_DEPTH(FIFO_DATA_DEPTH),
        //FIFO degth's margin
        . FIFO_DATA_DEPTH_MARGIN(FIFO_DATA_DEPTH_MARGIN),
        //FIFO compensate depth,(FIFO_DATA_DEPTH+FIFO_DEPTH_COMPLE) must be the data of power 2
        . FIFO_DEPTH_COMPLE(FIFO_DEPTH_COMPLE),
        . FIFO_DATA_WIDTH (FIFO_DATA_WIDTH)
    )Asynchronous_FIFO_npow2_inist0(
       .              nrst(nrst),
       .             clk_w(clk_w),
       .             wr_en(wr_en),
       .            wrdata(din),
       .         fifo_full(fifo_full),
 
       .             clk_r(clk_r),
       .             rd_en(rd_en),
       .            rddata(dout),
       .        fifo_empty(fifo_empty)
    );

endmodule
module cdc_test(

    );
        
         parameter integer DATA_WIDTH = 8;

       reg                       clk_w;
       reg                       clk_r;
       reg                        nrst;
       reg  [DATA_WIDTH-1:0]       din;
       reg                      validi;
       reg                      readyi;
                    
       wire                     valido;
       wire                     readyo;
       wire [DATA_WIDTH-1:0]      dout;

       initial begin
            nrst = 0;
            #2 nrst = 1;
            clk_w = 0;
            clk_r = 0;
            forever begin
               #1 clk_w = ~clk_w;
                  clk_r = ~clk_r;
            end
       end

       initial begin
            readyi = 1;
            din = 0;
            forever begin
                #10 din = din + 1;
                    validi = 1;
                #10 validi = 0;
            end
       end

     Handshake_fifo#(
       .DATA_WIDTH (DATA_WIDTH)
    )Handshake_fifo_inist0(
        .   clk_w( clk_w),
        .   clk_r( clk_r),
        .    nrst(  nrst),
        .     din(   din),
        .  validi(validi),
        .  readyi(readyi),
                    
        .  valido(valido),
        .  readyo(readyo),
        .    dout(  dout)
    );

endmodule

在这里插入图片描述


六、总结

技术适用场景同步信号位宽例子
普通多级同步器慢到快的数据同步单/多低速外设与高速CPU
多级同步器B型快到慢的数据同步或慢到快的数据同步外部中断信号、复位信号
FIFO快到慢的数据同步或慢到快的数据同步高速总线与低速总线之间的缓冲(AXI与UART,并->串)
握手协议快到慢的数据同步或慢到快的数据同步AXI数据传递(每个通道的数据均以握手协议传播)
使用FIFO实现的握手协议快到慢的数据同步或慢到快的数据同步
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PPRAM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值