Verilog5-单比特信号跨时钟域传输

文章目录

    • 单比特信号跨时钟域传输
      • 1、时钟域
      • 2、亚稳态
      • 3、多级寄存器处理
        • 3.1 信号从B到A(慢到快)
        • 3.2 信号从A到B(快到慢)

单比特信号跨时钟域传输

  • 参考链接:https://www.cnblogs.com/rouwawa/p/7501319.html#4527113

1、时钟域

  • 单时钟域:电路中所有触发器都是用一个全局网络,比如FPGA的主时钟输入
  • 多时钟域:设计中有多个时钟输入

2、亚稳态

  • 含义:触发器的输出无法在某个规定时间内达到一个确定的状态
  • 说明:在建立时间和保持时间定义的时间窗口上,若触发器的数据输入端口发生变化,就会产生时序违规(不满足建立时间、保持时间),从而使得输出为亚稳态(不能设置为逻辑0或逻辑1对应的电平)

Verilog5-单比特信号跨时钟域传输_第1张图片

  • 原因:
    • 不满足 建立时间/保持时间
  • 解决:
    • 1、相位控制:可在一个时钟频率是另一个时钟的数倍,并且其中一个时钟可以由FPGA内部PLL 或 DLL 控制时使用。
    • 2、多级寄存器(打多拍)
      • 适用于:单 bit 信号跨越两个异步时钟域传输
      • 同步电路的第一拍也许会产生亚稳态,但是一般会在第二级及之后的寄存器中稳定下来。
      • 常用:对 单bit 信号 打两拍
    • 3、异步FIFO缓存
      • 适用于:跨时钟域数据传输。写端和读端分别对应两个时钟域,由空/满信号控制着读写过程,实现数据的跨域传输。

3、多级寄存器处理

  • 适用于:单bit信号进行跨时钟域传输
  • 假设A,B是两个时钟域,各自的频率是 clk_a 和 clk_b ,clk_a的频率高于 clk_b,则单bit信号传输分为两种情况

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

Verilog5-单比特信号跨时钟域传输_第2张图片

  • 慢时钟域 到 快时钟域:脉冲信号 pulse_b 相对于快时钟 clk_a 来说是很宽的电平信号,可直接采样
  • 注意:经验设计采集过程必须寄存两拍,第一拍将输入信号同步化,同步化后的输出可能产生亚稳态,需要再寄存一拍,减少亚稳态带来的影响。
    • 一般两级是基本要求,若是高频率设计,则需要增加寄存器级数来大幅降低系统的不稳定性 —— 采用多级触发器来采样来自异步时钟域的信号,级数越多,同步过来的信号越稳定。
    • pulse_b 必须是 clk_b 下的寄存器信号,若 pulse_b 是 clk_b 下的组合逻辑信号,一定要先用 D触发器(DFF)抓一拍,再使用两级DFF 向 clk_a 传递
      • 原因:clk_b 下的组合逻辑信号会有毛刺,在clk_b 下使用时会由 setup/hold 时间保证毛刺不被 clk_b 采到,但由于异步相位不确定,组合逻辑的毛刺却极有可能被 clk_a采到。
// 这里打了3拍,也就是将pulse_b输入到快时钟 clk_a驱动的触发器组(三个)
always@(posedge clk_a or negedge rst_n)
    begin
        if(rst_n == 1'b0)
            begin
                pulse_a_r1<=1'b0;
                pulse_a_r2<= 1'b0;
                pulse_a_r3<=1'b0;
            end
        else
            begin
                pulse_a_r1<=pulse_b;
                pulse_a_r2<=pulse_a_r1;
                pulse_a_r3<=pulse_a_r2;	//打3拍
            end
    end

assign pulse_a_pos = pulse_a_r2 &(~pulse_a_r3);
assign pulse_a_neg = (~pulse_a_r2) & pulse_a_r3;
assign pulse_a = pulse_a_r2;

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

Verilog5-单比特信号跨时钟域传输_第3张图片

  • 单 bit 信号快时钟域到慢时钟域
    • 传输电平信号 level_a:只有电平信号 level_a 的宽度能被 clk_b 采集到,才可以保证系统正常工作
    • 传输脉冲信号 pulse_a:用一个展宽信号 替代 pulse_a ,实现跨时钟域握手
      • 原理:先把脉冲信号 pulse_a 在快时钟 clk_a 下展宽,变成电平信号 signal_a ,再向 慢时钟 clk_b 传递,当确认 clk_b 已经“看到” 信号同步过去之后,再清除掉 signal_a。
module Sync_Pulse(
    input clk_a,	// 快时钟
    input clk_b,	//慢时钟
    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;
// 在 clk_a下,生成展宽信号 signal_a
    always @(posedge clk_a 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(single_a_r[1] == 1'b1)
                begin
                    signal_a <= 1'b0;	// 定义展宽信号的结束
                end
            else
                signal_a <= signal_a;
        end
    
   // 在慢时钟 clk_b 下同步 signal_a
    always@(posedge clk_b or negedge rst_n)
        begin
            if(rst_n == 1'b0)
                begin
                    signal_b <= 1'b0;
                end
            else
                begin
                    signal_b <= signal_a;	//同步signal_a到慢时钟下的 signal_b
                end
        end
    // 在慢时钟clk_b下生成脉冲信号和输出信号
    always@(posedge clk_b 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};	//将同步后的信号signal_b 传入 signal_b_r中
                end
        end
    assign pulse_outb <= ~signal_b_r[1] &signal_b_r[0];	//生成慢时钟clk_b下的脉冲信号
    assign signal_outb <= signal_b_r[1];				//输出信号
    
    // 在clk_a 下采集signal_b[1],生成signal_a[1],用于反馈拉低 signal_a
    always@(posedge clka or negedge rst_n)	//注意这里是在快时钟域 clka 下
        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]};	//生成反馈信号signal_a_r,用于拉低展宽信号 signal_a
                end
        end
endmodule         
  • 代码说明
    • 在快始终域clk_a下,将脉冲信号 pulse_ina 展宽(上升沿对应 pulse_ina 在clk_a 下的上升沿,下降沿对应 反馈信号signal_a_r的下拉)生成 signal_a 信号 —— 过程1
    • 将 signal_a 在 慢时钟 clk_b 下进行采样得到 signal_b —— 过程2
    • signal_b 在慢时钟 clk_b 下生成反馈信号 signal_b_r,为了防止亚稳态, signal_b_r 为 2bit —— 过程3
    • 然后生成慢时钟下的脉冲信号 pulse_outb ,以及 输出信号 signal_outb —— 过程4,5
    • 再将反馈信号 signal_b_r 传输到 快时钟域 clk_a 下,生成signal_a_r ,用来拉低 展宽信号 signal_a , —— 过程7,1,2
      • 跨时钟域传输,所以将 signal_a_r 也设置为 2bit ,防止亚稳态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RrxZYzaU-1602333581224)(assets/image-20200404092803763.png)]

  • 这种通用代码框架适用于
    • 慢到快,单脉冲
    • 慢到快,长信号传输 (慢到快可以用上面简单的,也可以用这个通用框架)
    • 快到慢,单脉冲
    • 快到慢,长信号传输
  • 设计中牢记五条原则:
    • 1、在全局时钟的跳变沿最可靠
    • 2、来自异步时钟域的输入需要寄存一次以同步化,再寄存一次以减少亚稳态带来的影响
    • 3、不需要用到跳变沿的来自同一时钟域的输入,没有必要对信号进行寄存
    • 4、需要用到跳变沿的来自同一时钟域的输入,寄存一次即可
    • 5、需要用到跳变沿的来自不同时钟域的输入,需要用到3个触发器,前两个用以同步,第3个触发器的输出和第2个触发器的输出经过逻辑门来判断跳变沿

你可能感兴趣的:(Verilog电路设计,verilog)