跨时钟域方法(同步器、异步FIFO、边沿检测器、脉冲同步器、同步FIFO)
目录
1、跨时钟域方法的原因
2、跨时钟处理的两种思路
3、跨时钟域分类——单比特信号跨时钟
3.1.1慢时钟———快时钟。(满足三边沿准则,有效事件可以被安全采样)
3.1.2慢时钟———快时钟。(不满足三边沿准则,有效事件可以被安全采样)
3.2.1有效事件传输背景下确保有效事件的数量定义一致。(如何确保跨时钟前后单电平对应单事件?)
3.2.1.1边沿检测电路
3.2.2.2脉冲同步器(快时钟--慢时钟)
3.3多有效可控事件背景下使用反馈机制
3.4单bit信号跨时钟方法总结
4、跨时钟域信号的分类——多比特数据信号。
4.6异步FIFO
4.5 同步FIFO
5异步FIFO
5.6.1格雷码
1、跨时钟域方法的原因
异步时钟信号直接传输在信号跳变时违背本地时钟域的时序要求(建立时间约束,保持时间约束),容易产生亚稳态,无法确定亚稳态何时结束以及结束时保持在何种状态上。
2、跨时钟处理的两种思路
- 对代跨时钟的信息先缓存,然后由另一时钟域接口取出 ————异步FIFO
- 速度缓慢、可控的信号(配置信号,使能en、指示flag)我们对其进行一些处理。例如拉长持续时间,然后直接传输过去,亚稳态的问题通过同步器解决。适用于低速信号传输。
3、跨时钟域分类——单比特信号跨时钟
3.1.1慢时钟———快时钟。(满足三边沿准则,有效事件可以被安全采样)
接收时钟的频率是发送时钟的1.5倍以上,跨时钟信号的最小持续时间必然跨越接受时钟说的三个相邻时钟边沿,经过同步器该有效事件可以被安全传输。
3.1.2慢时钟———快时钟。(不满足三边沿准则,有效事件可以被安全采样)
接收时钟的频率小于发送时钟的1.5倍,将有效事件的持续时间拉长满足三边沿准则,然后再经过同步器传输。
always@(posedge clk_a or negedge arst)//(D触发器)(打拍可拉长持续时间)if(!arst)data_reg <=0;elsedata_reg <=data_in;always@(posedge clk_b or negedge brst)//同步器(时钟域为将要同步的时钟域)(两个连续的D触发器)if(!brst)begindata_breg <=0;data_breg2<=0;endelsebegindata_breg <=data_reg;data_breg2<=data_breg2;end
3.2.1有效事件传输背景下确保有效事件的数量定义一致。(如何确保跨时钟前后单电平对应单事件?)
- 脉冲同步电路
- 边沿检测电路
3.2.1.1边沿检测电路
对一个持续电平的上升沿或者下降沿进行检测,并将检测后的电平作为有效事件,就可以做到无论跨时钟输出电平持续多少个cycle,有效检测电平只持续一个cycle,边沿检测常适用于慢时钟到快时钟。
要实现边沿检测,最直接的想法是用两级寄存器,第二级寄存器锁存住某个时钟上升沿到来时的输入电平,第一级寄存器锁存住下一个时钟沿到来时的输入电平,如果这两个寄存器锁存住的电平信号不同,就说明检测到了边沿,具体是上升沿还是下降沿可以通过组合逻辑来实现。如下图所示:(思想:延迟一个寄存器)
//边沿检测电路
//2014/12/10
module edge_cap
(input clk, rst_n,input pulse,output pos_edge,output neg_edge);
reg pulse_r1, pulse_r2;always @ (posedge clk or negedge rst_n)
if(!rst_n) beginpulse_r1 <= 1'b0;pulse_r2 <= 1'b0;end
else beginpulse_r1 <= pulse;pulse_r2 <= pulse_r1;endassign pos_edge = (pulse_r1 && ~pulse_r2) ?1:0;
assign neg_edge = (~pulse_r1 && pulse_r2) ?1:0; endmodule
异步信号同步化
,一般采用多加一级寄存器的方法来减小亚稳态的发生概率,如下图所示:
//异步信号边沿检测电路,三级寄存器实现
//2014/12/08module edge_cap
(input clk, rst_n,input pulse,output pos_edge,output neg_edge);
reg pulse_r1, pulse_r2, pulse_r3;always @ (posedge clk or negedge rst_n)
if(!rst_n) beginpulse_r1 <= 1'b0;pulse_r2 <= 1'b0;pulse_r3 <= 1'b0;end
else beginpulse_r1 <= pulse;pulse_r2 <= pulse_r1;pulse_r3 <= pulse_r2;endassign pos_edge = (pulse_r2 && ~pulse_r3) ?1:0;
assign neg_edge = (~pulse_r2 && pulse_r3) ?1:0; endmodule
3.2.2.2脉冲同步器(快时钟--慢时钟)
对于快时钟域单电平脉冲信号跨时钟到慢时钟域常使用脉冲同步器电路,脉冲同步器在异步时钟域时钟频率彼此差距较大的场景下能节省触发器资源。快时钟域脉冲持续时间无法满足三边沿准则,需要通过翻转电路拉长脉冲电平以保证有效事件被采样,在接收时钟通过边沿检测回复原单电平脉冲。
`timescale 1ns/1nsmodule pulse_detect(input clk_fast , input clk_slow , input rst_n ,input data_in ,output dataout
);reg data_level,data_level1,data_level2,data_level3;//翻转电路
always @(posedge clk_fast or negedge rst_n)if(!rst_n)data_level<=0;elsedata_level<= (data_in)? ~data_level : data_level;always @(posedge clk_slow or negedge rst_n)//同步器if(!rst_n)begindata_level1<=0;data_level2<=0;endelsebegindata_level1<=data_level;data_level2<=data_level1;endalways @(posedge clk_slow or negedge rst_n)// D触发器if(!rst_n)data_level3<=0;elsedata_level3<=data_level2;assign dataout= data_level2^data_level3;endmodule
3.3多有效可控事件背景下使用反馈机制
现有多个连续的有效事件需要进行跨时钟,单个事件的发起时刻是可控的,这时建议使用反馈机制保证各有效事件跨时钟传输的安全性。
3.4单bit信号跨时钟方法总结
- 1.在单有效事件传输背景下,首先要确认是否需要用单周期脉冲表示单有效事件,若没有要求,传输信号满足三边沿准则后可经同步器直接传输
- 2.在单有效事件传输背景下,对于满足三边沿准则的慢时钟域到快时钟域的跨时钟信号可以优先考虑边沿检测电路,其他其他情况下可使用脉冲同步器(快时钟到慢时钟)
- 3.边沿检测电路与脉冲同步器的思路类似,先保证跨时钟信号满足三边沿准则以传递有效状态,然后通过边沿检测获取单周期脉冲,二者的区别在于边沿检测电路的信号事先满足三边沿准则,脉冲同步器的信号需要翻转电路产生长电平,因此也可以考虑将不满足三边沿准则的短脉冲本地打拍取逻辑或输出得到满足三边沿准则的长电平信号再打拍来跨时钟,并在异步时钟域取上升沿检测信号,这种方式代码写起来简单但可能导致资源消耗过多 。(寄存器延迟一个时钟比较。)
- 4.在多有效可控事件传输的背景下,可考虑对以上电路加入反馈控制
- 5.在多有效不可控事件传输的背景下,如发生两有效事件无时钟间隔连发,则上述跨时钟方法无法保证有效状态的传递与有效事件数量的识别,此时只能引入缓存机制,采用如DPRAM或者异步FIFO的方式保证数据的安全传输。
4、跨时钟域信号的分类——多比特数据信号。
FIFO
4.1FIFO定义
FIFO是英文First In First Out的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
- 4.2、FIFO功能
FIFO存储器是系统的缓冲环节,如果没有FIFO存储器,整个系统就不可能正常工作,它主要有几方面的功能:1)对连续的数据流]进行缓存,防止在进机和存储操作时丢失数据;
2)数据集中起来进行进栈和存储,可避免频繁的总线操作,减轻CPU的负担;
3)允许系统进行DMA操作,提高数据的传输速度。这是至关重要的一点,如果不采用DMA操作,数据传输将达不到传输要求,而且大大增加CPU的负担,无法同时完成数据的存储工作。
- 4.3、FIFO分类
FIFO的分类根据FIFO工作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟。在时钟沿来临时同时发生读写操作。异步FIFO是指读写时钟不一致,读写时钟是互相独立的。同步FIFO和异步FIFO如图所示,从图中可以看到,同步FIFO 具有一个独立的时钟端口 clock,因此所有的输入输出信号都同步于 clock 信号。而在异步FIFO 结构中,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写时钟 wrclk,所有与读相关的信号都是同步于读时钟 rdclk。同步 FIFO 常用于同步时钟的数据缓存,异步 FIFO 常用于跨时钟域的数据信号的传递,例如时钟域 A 下的数据 data1 传递给异步时钟域 B,当 data1 为连续变化信号时,如果直接传递给时钟域 B 则可能会导致收非所送的情况,即在采集过程中会出现包括亚稳态问题在内的一系列问题,使用异步 FIFO 能够将不同时钟域中的数据同步到所需的时钟域中。
- 4.4FIFO的几个重要参数
FIFO 的宽度:FIFO 一次读写操作的数据位 N;
FIFO 的深度:FIFO 可以存储多少个宽度为 N 位的数据。
空标志:对于双时钟 FIFO 又分为读空标志 rdempty 和写空标志 wrempty。FIFO 已空或将要空时由 FIFO
的状态电路送出的一个信号,以阻止 FIFO 的读操作继续从 FIFO 中读出数据而造成无效数据的读出。
满标志:对于双时钟 FIFO 又分为读满标志 rdfull 和写满标志 wrfull。FIFO 已满或将要写满时由 FIFO
的状态电路送出的一个信号,以阻止 FIFO 的写操作继续向 FIFO 中写数据而造成溢出。
读时钟:读 FIFO 时所遵循的时钟,在每个时钟的上升沿触发。
写时钟:写 FIFO 时所遵循的时钟,在每个时钟的上升沿触发。
- 4.3、FIFO分类
4.5 同步FIFO
-
模块主要分为读/写指针、读写指针的比较逻辑和RAM存储。
`timescale 1ns/1ns /**********************************RAM************************************/ module dual_port_RAM #(parameter DEPTH = 16,parameter WIDTH = 8)(input wclk,input wenc,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。,input [WIDTH-1:0] wdata //数据写入,input rclk,input renc,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。,output reg [WIDTH-1:0] rdata //数据输出 );reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];always @(posedge wclk) beginif(wenc)RAM_MEM[waddr] <= wdata; endalways @(posedge rclk) beginif(renc)rdata <= RAM_MEM[raddr]; endendmodule /**********************************SFIFO************************************/ module sfifo#(parameter WIDTH = 8,parameter DEPTH = 16 )(input clk , input rst_n ,input winc ,input rinc ,input [WIDTH-1:0] wdata ,output reg wfull ,output reg rempty ,output wire [WIDTH-1:0] rdata );reg [$clog2(DEPTH):0] waddr,raddr;dual_port_RAM #(.DEPTH (DEPTH),.WIDTH (WIDTH))dual_port_RAM (.wclk (clk ),.wenc (wenc ),.waddr (waddr),.wdata (wdata),.rclk (clk ),.renc (renc ),.raddr (raddr),.rdata (rdata));always @(posedge clk or negedge rst_n)//读数据计数加一if(!rst_n)raddr<=0;else if(renc)raddr<=raddr+1'd1;elseraddr<=raddr;always @(posedge clk or negedge rst_n)//写数据计数加一if(!rst_n)waddr<=0;else if(wenc)waddr<=waddr+1'd1;elsewaddr<=waddr;always @(posedge clk or negedge rst_n) //判断空满状态if(!rst_n)beginwfull<=0;rempty<=0;endelse beginwfull<=(waddr==raddr+DEPTH);rempty<=(waddr==raddr);endassign wenc = winc && !wfull;assign renc = rinc && !rempty;endmodule
5.6异步FIFO
- 异步FIFO主要是由双端口存储器、写指针产生逻辑、读指针产生逻辑及空满标志产生逻辑4部分组成。读写操作是由两个完全不同时钟域的时钟所控制。在写时钟域部分,由写指针所产生逻辑生成写端口所需要的写地址和写控制信号;在读时钟域部分,由读指针产生逻辑生成读断口所需要的读地址和读控制信号;在空满标志产生部分,通常是把写指针与读指针相互比较产生空满标志。
1. 双口RAM,用于数据的存储。(RAM中的指针的地址取FIFO中的地址的除地址第一位外的地址,因为FIFO中的第一位是标志位)
2. 数据写入控制器,在wenc信号的使能下,数据写入控制器使RAM读入数据,同时数据写地址指针加一。
3. 数据读取控制器,在renc信号的使能下,数据读出控制器使RAM读出数据,同时数据读地址指针加一。
4. 读指针同步器:使用写时钟的两级触发器采集读指针,输出到数据写入控制器。
5. 写指针同步器: 使用读时钟的两级触发器采集写指针,输出到数据读取控制器。
本题解采用的空满判断的方式是用格雷码的比较来产生空满信号,同时产生的空满信号,会与输入的winc,rinc输入的是能信号,共同控制数据是否写入和读出。
- 异步FIFO主要是由双端口存储器、写指针产生逻辑、读指针产生逻辑及空满标志产生逻辑4部分组成。读写操作是由两个完全不同时钟域的时钟所控制。在写时钟域部分,由写指针所产生逻辑生成写端口所需要的写地址和写控制信号;在读时钟域部分,由读指针产生逻辑生成读断口所需要的读地址和读控制信号;在空满标志产生部分,通常是把写指针与读指针相互比较产生空满标志。
`timescale 1ns/1ns/***************************************RAM*****************************************/ module dual_port_RAM #(parameter DEPTH = 16,parameter WIDTH = 8)(input wclk,input wenc,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。,input [WIDTH-1:0] wdata //数据写入,input rclk,input renc,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。,output reg [WIDTH-1:0] rdata //数据输出 );reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];always @(posedge wclk) beginif(wenc)RAM_MEM[waddr] <= wdata; end always @(posedge rclk) beginif(renc)rdata <= RAM_MEM[raddr]; end endmodule /***************************************AFIFO*****************************************/ module asyn_fifo#(parameter WIDTH = 8,parameter DEPTH = 16 )(input wclk , input rclk , input wrstn ,input rrstn ,input winc ,input rinc ,input [WIDTH-1:0] wdata ,output wire wfull ,output wire rempty ,output wire [WIDTH-1:0] rdata );/**********************addr bin gen*************************/ //RAM读写地址的变化 reg [ADDR_WIDTH:0] waddr_bin; reg [ADDR_WIDTH:0] raddr_bin;parameter ADDR_WIDTH = $clog2(DEPTH);always@(posedge rclk or negedge rrstn)//counter readif(!rrstn)raddr_bin<=0;else if(renc)raddr_bin<=raddr_bin+1'd1;elseraddr_bin<=raddr_bin;always@(posedge wclk or negedge wrstn)//counter writeif(!wrstn)waddr_bin<=0;else if(wenc)waddr_bin<=waddr_bin+1'd1;elsewaddr_bin<=waddr_bin;assign wenc = winc && !wfull; assign renc = rinc && !rempty;/**********************addr gray gen*************************/ //二进制转换为格雷码 wire [ADDR_WIDTH:0] waddr_gray; wire [ADDR_WIDTH:0] raddr_gray; reg [ADDR_WIDTH:0] wptr; reg [ADDR_WIDTH:0] rptr;assign waddr_gray = waddr_bin ^ (waddr_bin>>1);//二进制转换为格雷码 assign raddr_gray = raddr_bin ^ (raddr_bin>>1);//二进制转换为格雷码always @(posedge rclk or negedge rrstn)//打一拍避免冲突与竞争if(!rrstn)rptr<=0;elserptr<=raddr_gray;always @(posedge wclk or negedge wrstn)//打一拍避免冲突与竞争if(!wrstn)wptr<=0;elsewptr<=waddr_gray;/**********************syn addr gray*************************/ //同步器打两拍 reg [ADDR_WIDTH:0] wptr_buff; reg [ADDR_WIDTH:0] wptr_syn; reg [ADDR_WIDTH:0] rptr_buff; reg [ADDR_WIDTH:0] rptr_syn;always@(posedge rclk or negedge rrstn) //同步器:格雷码写地址同步至读时钟域if(!rrstn)beginwptr_buff<=0;wptr_syn<=0;endelsebeginwptr_buff<=wptr;wptr_syn<=wptr_buff;endalways@(posedge wclk or negedge wrstn)// 格雷码读地址同步至写时钟域if(!wrstn)beginrptr_buff<=0;rptr_syn<=0;endelsebeginrptr_buff<=rptr;rptr_syn<=rptr_buff;end/**********************full empty gen*************************/ //空满状态判断 assign wfull = (wptr == {~rptr_syn[ADDR_WIDTH:ADDR_WIDTH-1],rptr_syn[ADDR_WIDTH-2:0]}); assign rempty = (rptr == wptr_syn);/**********************RAM*************************/wire [ADDR_WIDTH-1:0] waddr; wire [ADDR_WIDTH-1:0] raddr;assign waddr = waddr_bin[ADDR_WIDTH-1:0]; assign raddr = raddr_bin[ADDR_WIDTH-1:0];dual_port_RAM #(.DEPTH(DEPTH),.WIDTH(WIDTH) )dual_port_RAM(.wclk (wclk), .wenc (wenc), .waddr(waddr[ADDR_WIDTH-1:0]), //深度对2取对数,得到地址的位宽。.wdata(wdata), //数据写入.rclk (rclk), .renc (renc), .raddr(raddr[ADDR_WIDTH-1:0]), //深度对2取对数,得到地址的位宽。.rdata(rdata) //数据输出 );endmodule
5.6.1格雷码
采用格雷码的原因:单bit翻转
每两个相邻编码之间只有一位是不同的,并且对于N位格雷码,当从最高位编码(对应二进制2^N -1)跳转到最低位编码(对应0)时也只会发生1bit跳转。单bit跳转意味着格雷码在通过二级同步器跨时钟时,输出不会出现不可控的中间状态,只能是正确的更新状态或者保持原来的状态。
二进制码与gray码的转换关系
二进制转换成格雷码: assign gray = (bin >>1)^bin;
格雷码转换成二进制码:
bin[N-1] = gray[N-1];
for(i=0;i<(N-1);i+1)begin
bin[i] = ^(gray[N-1:0]>>i);
end
-
- 4.2、FIFO功能
跨时钟域方法(同步器、异步FIFO、边沿检测器、脉冲同步器、同步FIFO)相关推荐
- 数字IC笔面常考,跨时钟域神器。——异步FIFO(简介及手撕代码)
异步FIFO 写在前面的话 异步FIFO相关知识点 FIFO简介 FIFO结构 应用场景(来源小梅哥 <FPGA 系统设计与验证实战指南> 章节4.4) 相关参数 异步FIFO 内部组成 ...
- 跨时钟域信号处理(二)——异步fifo的Verilog实现(附同步fifo的实现)
需要回答几个问题: 1.什么是异步FIFO,异步FIFO有什么功能? 跨时钟域的数据交换,防止亚稳态. 2.在产生写满与读空信号时需要进行跨时钟域如何做的,且如何能正确指示空满状态? 寄存器打两拍+格 ...
- 跨时钟域电路设计方法
在数字电路设计过程中 ,难免会遇到某个信号需要跨越不同时钟域的情况. 如果对跨时钟域的信号不做妥善的处理,跨越时钟域后,信号可能发生亚稳态,传播亚稳态,导致电路工作异常.并且,由跨时钟域处理不当引发的 ...
- 跨时钟域处理方法总结
目录 跨时钟域处理 1. 异步时序定义 2. 亚稳态 3. 同步策略 方法一:双锁存器 方法二:握手信号(结绳法) 方法三:异步双口RAM+格雷码 跨时钟域处理 为了彻底理解跨时钟域问题,多方搜集资料 ...
- 跨时钟域设计(结绳法,脉冲展宽法)
跨时钟域方法总结 https://www.docin.com/p-1715858862.html 异步FIFO https://blog.csdn.net/darknessdarkness/artic ...
- 亚稳态及信号跨时钟域处理
文章目录 一.亚稳态简介 二.亚稳态窗口 三.平均无故障时间(MTBF) 四.亚稳态产生场景 五.解决亚稳态的技术 5.1 单比特信号跨时钟域 5.1.1 多级同步器 5.1.2 另一种多级同步器 5 ...
- 【数字IC基础】跨时钟域(CDC,Clock Domain Crossing)
文章目录 一.什么是跨时钟域? 二.跨时钟域传输的问题? 2.1 亚稳态(单bit:两级D触发器(双DFF)) 2.2 数据收敛(多bit亚稳态)(格雷码编码.握手协议.异步FIFO.DMUX) 2. ...
- 跨时钟域的亚稳态处理、为什么要打两拍不是打一拍、为什么打两拍能有效?...
转自|https://blog.csdn.net/Hide_in_Code/article/details/126600563 整理|比特波特 个人疑惑 在学习 "跨时钟域的亚稳态的应对措施 ...
- 【Chips】跨时钟域的亚稳态处理、为什么要打两拍不是打一拍、为什么打两拍能有效?
Title: 跨时钟域的亚稳态处理.为什么要打两拍不是打一拍.为什么打两拍能有效? 前言 个人颜色习惯: 黑色加粗:突出显示: 红色:重要: 洋红色:产生的疑问 question: 蓝色:个人思考 或 ...
最新文章
- 从前到后的CAN总线(一)
- java创建医生的对象_基于安卓Android的作物医生App设计开发(MySQL)(含录像)
- linuc和python常用命令是一样的么_Linux常用命令大全(非常全!!!)(2)|简明python教程|python入门|python教程...
- [你必须知道的.NET]第二十三回:品味细节,深入.NET的类型构造器
- 句柄与指针的区别(一)
- ubuntu 14.04 登录 界面 root
- 计算机网络学习笔记(14. OSI参考模型②)
- 根据服务端生成的WSDL文件创建客户端支持代码的三种方式
- len函数实例python_Python通过len函数返回对象长度
- moodle php代码解读_Moodle插件开发笔记
- 从零开始实现Unity光照模型_02_为Shader添加简单的多光源支持_技术美术基础学习记录
- python数据透视表怎么存下来_大数据分析如何利用Python创建数据透视表?
- 三角函数和差公式的推导
- 双温模型 matlab,晶体中的能量传递和双温模型.PDF
- html折叠段落标记,HTML 段落标记“p”与换行标记,标题标记“h”!
- CBNetworking AFN的封装,别出心裁
- 金融类APP上架经验分享
- Eclips 反编译
- 20道jQuery 常见的面试问题和答案
- 基于深度相机的三维重建技术
热门文章
- Eclipse启动Tomcat逐渐变慢
- 【hash】哈希算法、哈希碰撞、一致性哈希
- php新闻系统面试题_php面试题库
- 如何将功能测试用例转为自动化脚本?
- iOS定位库-INTULocationRequest
- DAMP平台logo初版
- 项目-病例步态的分析研究跟进-使用霍尔特双参数指数平滑法来平滑关节数据的过程中的错误处理Error27error C3861: 'cvPoint': identifier not foundd
- RNA 9. SCI 文章中基因表达之 GO 注释
- 如何分析测试结果和评估测试工作的质量
- 电路复习——线性电路的基本分析方法