跨时钟域总结

跨时钟域总结

秋招学习跨时钟域

总结一下吧

异步电路

设计中有两个频率不同的时钟(也可能多个),而有数据在两组时钟之间传输

单bit跨时钟域

慢时钟域数据-> 快时钟域

  • 方法 : 使用两个锁存器 (打两拍)

数据跨时钟域同步过程中,脉冲宽度会改变,不影响同步结果

`timescale 1ns/1ns

//慢时钟数据跨时钟域到快时钟域
module cdc_slow2fast(
    input clk_s     ,
    input pluse_s   ,
    input clk_f     ,
    output pluse_f
);

    reg pluse_s_ff1 ;
    reg pluse_s_ff2 ; 
    //慢时钟下的数据在快时钟下打两拍
    always @(posedge clk_f)begin
        pluse_s_ff1 <= pluse_s ;
        pluse_s_ff2 <= pluse_s_ff1 ;
    end

    assign pluse_f = pluse_s_ff2 ;
endmodule

快时钟域数据 -> 慢时钟域

  • 脉冲展宽+同步

那么将快时钟域的信号进行展宽,但是会出现毛刺

`timescale 1ns/1ns

module cdc_fast2slow(
    input clk_f ,
    input clk_s ,
    input pulse_f,

    output pulse_s
);
    //在快时钟域下打两拍 
    //目的是为了将脉冲信号展宽,方便识别
    reg [2:0] pulse_f_ff;
    always @(posedge clk_f) begin
        pulse_f_ff <= {pulse_f_ff[1:0],pulse_f} ;
    end

    wire pulse_s_w ;
    assign pulse_s_w =  | pulse_f_ff ;//按位或
    
    
    reg pulse_s_ff1;
    reg pulse_s_ff2;
    
    always @(posedge clk_s) begin
        pulse_s_ff1 <= pulse_s_w  ;
        pulse_s_ff2 <= pulse_s_ff1 ;
    end
    assign pulse_s = pulse_s_ff2;
endmodule
  • 方法2 : 脉动电平检测+双触发器同步+边缘检测

    • 对快时钟域的电平设置检测信号(翻转)

    • 将翻转信号进行跨时钟域处理

    • 使用两次寄存器打节拍

    • 将两个寄存器信号做异或

      `timescale 1ns/1ns

      module cdc_fast2slow_new(
      input clk_f ,
      input clk_s ,
      input pulse_f,

      output pulse_s
      

      );
      //标志寄存器: 检测快时钟域中的脉冲信号

      reg  pulse_f_flag = 0;
      
      always @(posedge clk_f) begin
          if(pulse_f)begin
              pulse_f_flag <= ~pulse_f_flag ;
          end else begin
              pulse_f_flag <= pulse_f_flag  ;
          end 
      end
      
      reg pulse_f_ff1;
      reg pulse_f_ff2;
      reg pulse_s_ff3;    //这里的第三拍为了异或操作
      //对标志寄存器做跨时钟域处理
      always @(posedge clk_s) begin
          pulse_f_ff1 <= pulse_f_flag  ;
          pulse_f_ff2 <= pulse_f_ff1 ;
          pulse_s_ff3 <= pulse_f_ff2 ;
      end
      
      assign pulse_s = pulse_s_ff3 ^ pulse_f_ff2;
      

      endmodule

多bit跨时钟域处理

  • 多bit的跨时钟域为什么不能直接打两拍?

每一个寄存器中的数据在进行跨时钟域处理的时候,从源寄存器到目的寄存器之间的延迟可能会出现不同的路径长度,所以延迟也不能控制完全相等。

方法1 : 慢时钟域-> 快时钟域 : 格雷码+同步

采用格雷码。使相邻两个多bit数据传输过程中,只有一个bit发生改变。(多bit变化到单bit变化)降低亚稳态的产生。

格雷码只能在地址或者数值依次增加的情况下使用

数值不是依次增加,那么格雷码相邻的数值不止一个bit发生改变

`timescale  1ns/1ns

//格雷码+同步的方法只适合两种情况
// 1. 多bit的跨时钟域数值(地址or数据)必须依次变化(增大 or 减小) 
// 2. 必须是慢时钟域数据到快时钟域数据


module gray_cdc(
    input clk_s,
    input clk_f,
    input [3:0] data_in,
    
    output [3:0] data_out 
);

    //二进制2格雷码
    wire [3:0] gray_data;
    assign  gray_data = (data_in>>1) ^ data_in ;

    //跨时钟域处理
    reg [3:0] gray_data_ff1;
    reg [3:0] gray_data_ff2;

    //格雷码2二进制
    reg [3:0] out_data;

    //跨时钟域处理
    always @(posedge clk_f ) begin
        gray_data_ff1 <= gray_data ;
        gray_data_ff2 <= gray_data_ff1 ;
        
    end
    //格雷码2二进制
    integer i;
    always @(*) begin
        out_data[3] <= gray_data_ff2[3];
        for(i=2;i>=0;i=i-1) begin
            out_data[i] = (gray_data_ff2[i] ^ out_data[i+1]);
        end
    end
    assign data_out =out_data; 


endmodule

方法2 : 快时钟域 -> 慢时钟域 : Dmux

格雷码+同步的方法只适合数值依次变化(累加or累减),并且是慢时钟域到快时钟域。

当快时钟域源数据向慢时钟域传输,数据可能被慢时钟域遗漏。

因此在Dmux方法中,需要快时钟域数据在快时钟域下保持几个时钟周期:满足源数据有足够时间传向目的数据

  • 条件:支持多bit跨时钟域处理(支持跳变的多bit数据),DMUX在源端的clk信号必须维持好几个目的断时钟周期时间(3-4个)

    module dmux_cdc #(
    parameter tx_clk = 100,
    parameter rx_clk = 50 ,
    parameter DATA_WIDTH = 8
    )
    (
    input clk_f ,
    input clk_s ,
    input rst_n ,
    input [DATA_WIDTH-1:0] data_in ,
    input valid_in ,

      output [DATA_WIDTH-1 :0] data_out,
      output valid_out
    

    );
    reg [DATA_WIDTH-1:0] data_in_ff1;
    reg valid_in_ff1;

      //在快时钟域打一拍
      always @(posedge clk_f or negedge rst_n)begin
          if(!rst_n)begin
              data_in_ff1 <= 'd0;
              valid_in_ff1 <= 'd0;
          end else begin
              data_in_ff1 <= data_in;
              valid_in_ff1 <= valid_in ;
          end
      end
    
      reg valid_in_ff2;
      reg valid_in_ff3;
    
      //valid信号在慢时钟域打两拍
      always @(posedge clk_s)begin
          if(!rst_n)begin
              valid_in_ff2<= 'd0;
              valid_in_ff3<= 'd0;
          end else begin
              valid_in_ff2<= valid_in_ff1 ;
              valid_in_ff3<= valid_in_ff2 ;
          end
      end
    
      //选择器(MUX)
      reg [DATA_WIDTH-1 : 0] data_out_ff1;
      reg valid_out_ff1;
      
      always @(posedge clk_s)begin
          if(!rst_n)begin
              data_out_ff1<= 'd0;
              valid_out_ff1 <= 'd0;
          end else if(valid_in_ff3) begin
              data_out_ff1 <= data_in_ff1;
              valid_out_ff1 <= 'd1;
          end else begin
              data_out_ff1 <= data_out_ff1;
              valid_out_ff1 <= 'd0;
          end
      end
      assign data_out = data_out_ff1;
      assign valid_out = valid_out_ff1 ;
    

    endmodule

相关推荐
redcocal2 小时前
地平线秋招
python·嵌入式硬件·算法·fpga开发·求职招聘
思尔芯S2C17 小时前
高密原型验证系统解决方案(下篇)
fpga开发·soc设计·debugging·fpga原型验证·prototyping·深度调试·多fpga 调试
坚持每天写程序17 小时前
xilinx vivado PULLMODE 设置思路
fpga开发
redcocal1 天前
地平线内推码 kbrfck
c++·嵌入式硬件·mcu·算法·fpga开发·求职招聘
邹莉斯3 天前
FPGA基本结构和简单原理
fpga开发·硬件工程
悲喜自渡7213 天前
易灵思FPGA开发(一)——软件安装
fpga开发
ZxsLoves3 天前
【【通信协议ARP的verilog实现】】
fpga开发
爱奔跑的虎子3 天前
FPGA与Matlab图像处理之伽马校正
图像处理·matlab·fpga开发·fpga·vivado·xilinx
机器未来3 天前
基于FPGA的SD卡的数据读写实现(SD NAND FLASH)
arm开发·嵌入式硬件·fpga开发
贾saisai4 天前
Xilinx系FPGA学习笔记(八)FPGA与红外遥控
笔记·学习·fpga开发