每日一摘:跨时钟域

假如设计有两个输入时钟,如图所示,一个时钟给接口1使用,另一个时钟给接口2使用,因此这里就会存在跨时钟域的问题。

 跨时钟域的的处理:

1、单bit:两级D触发器同步

2、多bit:采用异步fifo,异步双口RAM

3、加握手信号

4、格雷码转换


 多级寄存器处理:①慢到快②快到慢

①慢到快:输入信号从时钟频率慢同步到时钟频率快

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

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;        //打了两拍,成功把时钟域clk_b的信号同步到时钟域clk_a

②快到慢:输入信号从时钟频率快同步到时钟频率慢

 如果输入的单bit信号从快时钟clk_a同步到慢时钟clk_b,那么存在两种不同的情况:输入信号是电平信号level_a、输入信号是脉冲信号pulse_a。

实际上,在一般情况下只有电平信号level_a的宽度才能被clk_b采集到,并保证系统正常工作。同理,脉冲信号pulse_a的宽度不够,因此需要用一个展宽信号来替代pulse_a,实现跨时钟域的握手。主要原理就是先把脉冲信号pulse_a在clk_a下展宽,变成电平信号signal_a,再向clk_b传递,当确认clk_b已经“看见”信号同步过去之后,再清掉signal_a。

//Synchronous
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     [1:0]   signal_b_r;
reg     [1:0]   signal_a_r;

//-------------------------------------------------------
//在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_r[1] == 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 <= 2'b00;
    end
    else begin
        signal_b_r <= {signal_b_r[0], signal_b};
    end
end

assign    pulse_outb = ~signal_b_r[1] & signal_b_r[0];
assign    signal_outb = signal_b_r[1];   //打了两拍,成功把时钟域clk_a的信号同步到时钟域clk_b

//-------------------------------------------------------
//在clka下采集signal_b[1],生成signal_a_r[1]用于反馈拉低signal_a
always @(posedge clka or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        signal_a_r <= 2'b00;
    end
    else begin
        signal_a_r <= {signal_a_r[0], signal_b_r[1]};
    end
end

endmodule
原文地址:https://www.cnblogs.com/FPGAer/p/14121554.html