亚稳态与单比特、多比特信号跨时钟域传输

跨时钟域同步方法
对于1bit信号,一般来说都是控制信号,方法有
a) 如果是慢时钟域到快时钟域,采用两级触发器同步来抑制亚稳态传播,如果快时钟域只要求输出一个时钟周期的有效信号,那么可以采用边沿检测电路;
b) 如果是快时钟域到慢时钟域,需要将快时钟域的信号展宽保证慢时钟可以才到,可以采用计数、状态机、握手协议来完成,但这些的前提都是快时钟域的控制信号是不连续的,一般都能满足(如果不行就采用FIFO);也可以采用窄脉冲检测电路或脉冲同步器。

对于多比特的信号,一般来说是数据信号,方法有
a) 如果是非连续信号(数据变化速率低于接收时钟),可以采用握手协议或者DMUX
b) 如果是连续信号,则必须采用FIFO

1、基础知识
传播延迟(Tpd)
从第一个触发器的输出,传播到第二个触发器的输入所花费的时间;
在这里插入图片描述
解决高传播延迟的方法:
1、降低时钟频率
2、将逻辑分解为多个阶段(流水线)

建立时间(Tsu,setup):在时钟上升沿到达之前,输入到触发器稳定所需的时间。
保持时间(Th,hold):在时钟沿之后,输入到触发器稳定所需的最短时间。

假设Tco表示触发器时钟有效到数据输出的时间;Tpd表示传播延迟,Tsu表示建立时间,不考虑时钟偏斜,那么最小时钟周期为:
Tmin = Tco + Tpd + Tsu;

2、单比特跨时钟域传输

  • 慢时钟 -> 快时钟
    !!! 在快时钟域中“打两拍”
    在这里插入图片描述
  • 快时钟 -> 慢时钟
    !!!展宽信号
    在这里插入图片描述
    在这里插入图片描述
    为了正确保证满足建立时间和保持时间,延长脉冲使之在慢速时钟域中至少占用2个时钟周期。因此应该将100 MHz脉冲扩展到至少8个时钟周期;
module Sync_Pulse(
    input           clka,
    input           clkb,
    input           rst_n,
    input           pulse_ina,
    output          pulse_outb,
    output          signal_outb
);
//-------------------------------------------------------
reg             signal_a;
reg             signal_b;
reg             signal_b_r;
reg             signal_b_rr;
reg             signal_a_r;
reg             signal_a_rr;
//-------------------------------------------------------
//在clka下,生成展宽信号signal_a
always @(posedge clka or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        signal_a <= 1'b0;
    end
    else if(pulse_ina == 1'b1)begin
        signal_a <= 1'b1;
    end
    else if(signal_a_rr == 1'b1)
        signal_a <= 1'b0;
    else 
        signal_a <= signal_a;
end
//-------------------------------------------------------
//在clkb下同步signal_a
always @(posedge clkb or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        signal_b <= 1'b0;
    end
    else begin
        signal_b <= signal_a;
    end
end
//-------------------------------------------------------
//在clkb下生成脉冲信号和输出信号
always @(posedge clkb or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        signal_b_r <= 'b0;
        signal_b_rr <= 'b0;
    end
    else begin
        signal_b_rr <= signal_b_r;
        signal_b_r <= signal_b;
    end
end
assign    pulse_outb = ~signal_b_rr & signal_b_r;
assign    signal_outb = signal_b_rr;
//-------------------------------------------------------
//在clka下采集signal_b_rr,生成signal_a_rr用于反馈拉低signal_a
always @(posedge clka or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        signal_a_r <= 'b0;
        signal_a_rr <= 'b0;
    end
    else begin
        signal_a_rr <= signal_a_r;
        signal_a_r <= signal_b_rr;
    end
end
endmodule

在这里插入图片描述
3、多比特跨时钟域传输(握手同步)

module test(
    input clka,
    input clkb,
    input rst_n,
    input [3:0] data_in,
    input req,
    output reg [3:0] data_out,
    output data_vld
    );

reg en_a;
reg en_a_r,en_a_rr;
reg en_b;
reg en_b_r,en_b_rr;
  
always @(posedge clka or negedge rst_n)begin
    if(~rst_n)begin
        en_a <= 1'd0;
    end
    else if(req)
        en_a <= 1'd1;
    else if(en_a_rr)
        en_a <= 1'd0;
end

always @(posedge clkb or negedge rst_n)begin
    if(~rst_n)begin
        en_b <= 1'd0;
    end
    else
        en_b <= en_a;
end

always @(posedge clkb or negedge rst_n)begin
    if(~rst_n)begin
        en_b_r <= 1'd0;
        en_b_rr <= 1'd0;
    end
    else begin
        en_b_r <= en_b;
        en_b_rr <= en_b_r;
    end
end

assign data_vld = en_b_r && ~en_b_rr;

always @(posedge clkb or negedge rst_n)begin
    if(~rst_n)begin
        data_out <= 4'd0;
    end
    else if(data_vld)
        data_out <= data_in;
end

always @(posedge clka or negedge rst_n)begin
    if(~rst_n)begin
        en_a_r <= 1'd0;
        en_a_rr <= 1'd0;
    end
    else begin
        en_a_r <= en_b;
        en_a_rr <= en_a_r;
    end
end
endmodule

仿真

module tb(

    );

    reg       clka        ;
    reg       clkb        ;
    reg       rst_n          ;
    reg       en         ; //来自于外部的使能信号,脉冲持续一个时钟周期
    reg [3:0] data_in    ; //外部输入信号
    wire [3:0] data_out  ;
    wire       data_vld        ;

    initial begin
        clka = 1'd0;
        forever begin
            #2 clka = ~clka;
        end
    end

    initial begin
        clkb = 1'd0;
        forever begin
            #3 clkb = ~clkb;
        end
    end

    initial begin
        rst_n = 1'd0;
        data_in = 4'd0;
        en = 0;
        @(negedge clka);
        rst_n = 1'd1;
        @(posedge clka);
        en = 1;
        @(posedge clka);
        en = 0;
    end


    always@(posedge clka or posedge rst_n) begin
        if(~rst_n) begin
            data_in <= 4'd0;
        end
        else if(en) begin
            data_in <= $random;
        end
    end
    
test test(
    .clka     (clka     ) ,
    .clkb     (clkb     ),
    .rst_n    (rst_n    ) ,
    .data_in  (data_in  ),
    .req      (en       )       ,
    .data_out (data_out ) ,
    . data_vld( data_vld)
    );
endmodule

在这里插入图片描述
学习链接 https://cloud.tencent.com/developer/article/1801288

  • 2
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值