首页 > 其他分享 >多bit信号跨时钟域(CDC)处理方法

多bit信号跨时钟域(CDC)处理方法

时间:2024-03-15 15:03:49浏览次数:34  
标签:en CDC 信号 bit data reg 时钟

参考csdn:

(1)跨时钟域处理解析(一)-CSDN博客

(2)FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_多bit同步 skew约束-CSDN博客

(3)跨时钟传输——多比特_多bit跨时钟域-CSDN博客

参考其他:

(1)【数字IC】异步FIFO设计详解(含源码) - 知乎 (zhihu.com)

1.亚稳态问题

        首先是关于在学习跨时钟域上一篇单bit数据跨时钟域的最后提出的问题,对我当时的代码来说,数据打一拍就足够了,多打拍反而会导致数据传输延后一个周期,不能及时接收数据;但是网上查到的代码都选择了打两拍,因此这个问题存疑。

        这个问题的正解确实是为了避免亚稳态的出现。

        首先来解释一下亚稳态这个概念:

        亚稳态是指在设计正常运行期间的某个时间点,信号在一段时间内不会呈现稳定的0 或1 状态。在多时钟设计中,由于建立时间和保持时间可能不满足要求,所以无法避免亚稳态,但可以减小亚稳态的不利影响。

        而解决亚稳态影响,目前设计最主流、也是最常见的方法就是双触发器同步器(打两拍),同步器图示和经过之后的波形如下图所示。对于大多数同步应用,两个触发器同步器足以消除所有可能的亚稳态,它可以避免将第一级的错误继续传递到第二级,但是在保证数据正确传递的同时,必要的牺牲了一点传输的实时性。而我的设计中因为要讲究数据快速传递,所以只打一拍也是足够了的。

2.多bit跨时钟域和单bit的不同

        在时钟域之间传递多bit信号时,简单的同步器并不能保证数据的安全传输。 

        工程师在进行多时钟设计时经常犯的一个错误是将同一事务中所需的多个 CDC 位从一个时钟域传递到另一个时钟域,而忽视了 CDC 位同步采样的重要性。 

        问题是同步到一个时钟的多bit信号会经历小的数据变化偏斜(skews),偶尔会在第二个时钟域的不同时钟上升沿上采样。即使我们可以完美地控制和匹配多个信号的走线长度,上升和下降时间的差异以及芯片上的工艺变化可能会引入足够的偏斜,从而导致对原本精心匹配的走线的采样失败。 

        总结就是:多bit信号的CDC问题主要来自于到达目的时钟域的时间无法控制一致。如果简单将多bit信号拆分成好几个单bit信号,分别采用寄存器来进行传输,那么由于每个寄存器的位置不同,布局布线会导致每个数据到达下一级寄存器的延时不同,可能会采样的中间变化的任何值。

3.多bit跨时钟域的几种解决方法

        (1)多bit信号合并——字面意思,将多bit信号合并成单bit信号,一般只适用于多个控制信号且控制信号之间有一定逻辑关系。合并之后再采用单bit跨时钟域方式进行传递。这种方法最简单,但是不常见,也没什么要多说明的。

        (2)MUX同步器。

        (3)异步FIFO。

        (4)格雷码编码处理——有局限性,只有在数据在相数值间连续变化的情况下才有用,不适用于大多数信号传输或者数据传输的情况,且这个方法在异步fifo中有被包含到,就不单独说明。

        除此之外,我查到的还有握手协议、多周期路径(Multi-Cycle path,MCP)同步法,不过感觉多bit来说,掌握其中两种比较有代表性的就足够了,因此这两种方法就暂时不详细看了。

        下面就2、3方法进行详细讲述。

4. MUX同步器解决多bit跨时钟域

        使用MUX同步器要求被同步的数据跟随一个使能信号,当使能信号有效时,数据才会被同步。MUX同步器应用在慢到快的CDC时,数据长度应该至少为m+1个目标时钟周期,m指的是同步器数量,此处为m=2。

        具体实现代码如下所示

module  mux_sync(clk_a, clk_b, arst_n, brst_n, data_in, data_out, data_en);

    /********************参数定义********************/

    /*********************IO 说明********************/

	input    wire             clk_a   ;//A时钟域时钟(发送域)
	input    wire             clk_b   ;//B时钟域时钟(接收域)
	input    wire             arst_n  ;//A时钟异步复位
	input    wire             brst_n  ;//B时钟异步复位
	input    wire             data_en ;//A时钟域有效信号,高电平有效
	input    wire    [3:0]    data_in ;//A时钟域数据输入
	output   reg     [3:0]    data_out;//B时钟域数据输出   
	/********************** 内部信号声明 **********************/   
    reg   [3:0]    data_in_reg;    //输入数据暂存寄存器
	reg            a_data_en;      
    reg            b_data_en;
	reg            b_date_en_reg;
	/*************************功能定义*************************/
    /*数据暂存*/
	always@(posedge clk_a or negedge arst_n)
	begin
	    if(!arst_n)
		    data_in_reg <= 1'b0;
      	else 
		    data_in_reg <= data_in;
	end
    
	//使能信号在A时钟域用一个D触发器暂存
	always@(posedge clk_a or negedge arst_n) 
    begin
        if(!arst_n)
		    a_data_en <= 1'b0;
		else
            a_data_en <= data_en;
    end	
	
	//使能信号在B时钟域打两拍(两级电平同步器)
	always@(posedge clk_b or negedge brst_n) 
    begin
        if(!brst_n)
		begin
		    b_date_en_reg<= 1'b0;
		    b_data_en <= 1'b0;
		end
		else
		begin
		    b_date_en_reg <= a_data_en;
			b_data_en <= b_date_en_reg;
		end
    end	
	
	/*根据同步到B时钟域的使能信号b_data_en,更新输出。*/
	always@(posedge clk_b or negedge brst_n)
	    begin
        if(!brst_n)
		    data_out <= 4'b0;
		else
		begin
		    data_out <= b_data_en ? data_in_reg : data_out;
		end
    end	
	
endmodule

        上述代码是针对正常慢时钟域到快时钟域的,但如果B时钟域(接收域)的时钟频率时A时钟域(发送域)的时钟频率的几十倍,甚至上百倍。且data_en为脉冲信号时,data_en在在快时钟域打完几拍的时间相对于慢时钟域是非常短暂的,此时慢时钟域中的多bit数据信号可能还处于冒险中间态,则此时选通进入快时钟域的数据就是“毛刺”。

        针对这种情况,可以在接收域使用边沿同步器,检测data_en的下降沿,以保证此时的多比特数据一定是稳定的。

module mux_sync(clk_a, clk_b, arst_n, brst_n, data_in, data_out, data_en);

    /********************参数定义********************/

    /*********************IO 说明********************/

	input    wire             clk_a   ;//A时钟域时钟(发送域)
	input    wire             clk_b   ;//B时钟域时钟(接收域)
	input    wire             arst_n  ;//A时钟异步复位
	input    wire             brst_n  ;//B时钟异步复位
	input    wire             data_en ;//A时钟域有效信号,高电平有效
	input    wire    [3:0]    data_in ;//A时钟域数据输入
	output   reg     [3:0]    data_out;//B时钟域数据输出   
	/********************** 内部信号声明 **********************/   
    reg   [3:0]    data_in_reg;    //输入数据暂存寄存器
	reg            a_data_en;      
    reg            b_data_en;
	reg            b_date_en_reg;
	reg            edge_reg;
	wire           edge_flag;
	/*************************功能定义*************************/
    /*数据暂存*/
	always@(posedge clk_a or negedge arst_n)
	begin
	    if(!arst_n)
		    data_in_reg <= 1'b0;
      	else 
		    data_in_reg <= data_in;
	end
    
	//使能信号在A时钟域用一个D触发器暂存
	always@(posedge clk_a or negedge arst_n) 
    begin
        if(!arst_n)
		    a_data_en <= 1'b0;
		else
            a_data_en <= data_en;
    end	
	
	//使能信号在B时钟域打两拍(两级电平同步器)
	always@(posedge clk_b or negedge brst_n) 
    begin
        if(!brst_n)
		begin
		    b_date_en_reg<= 1'b0;
		    b_data_en <= 1'b0;
		end
		else
		begin
		    b_date_en_reg <= a_data_en;
			b_data_en <= b_date_en_reg;
		end
    end	
	
	//下降沿检测
	always@(posedge clk_b or negedge brst_n)
	begin
	    if(!brst_n)
	        edge_reg <= 1'b0;
		else
		    edge_reg <= b_data_en;
	end
	assign  edge_flag = ~b_data_en & edge_reg;
	
	
	/*根据同步到B时钟域的使能信号b_data_en,更新输出。*/
	always@(posedge clk_b or negedge brst_n)
	begin
        if(!brst_n)
		    data_out <= 4'b0;
		else
		    data_out <= edge_flag ? data_in_reg : data_out;
    end	
	
endmodule

        这个方法感觉很熟悉,和单bit数据跨时钟域处理慢时钟域到快时钟域避免重复采样的方法是基本一致的。只不过不同的是,单bit采用的是读取上升沿,而多bit采用的是读取下降沿,要解决的是输入的多bit数据还没有全部传完,输出就完成打两拍开始采集data,因此选择采样下降沿,保证采集到数据的时候已经完全传输完成,这点没有问题。

        上述这两种代码都是处理慢到快时钟域的,对于快到慢时钟域来说,目前我查到的资料说是保证输入的使能信号和数据周期足够长就可以了。目前先存疑一下,感觉也可以通过单bit方法来实现。

        总结,对于MUX同步器来说,其实本质上还是和单bit有相似之处的,就是将valid信号按照单bit的信号进行处理。

5.异步fifo

        异步fifo可以说是解决多bit跨时钟域最常见的方法了,它相当于将源时钟数据缓存起来,然后目标时钟从缓存中取数据,传输速度较快。

        异步FIFO其主要由六部分组成,整体结构如下所示。

        (1)写数据控制模块:生成写地址指针、生成写数据使能;

        (2)读数据控制模块:生成写地址指针、生成写数据使能;

        (3)格雷码转换模块:将二进制码转换为格雷码;

        (4)格雷码同步模块:将格雷码同步到目标时钟域;

        (5)空满信号生成模块:通过读写指针经格雷码转换、同步后进行比较,生成full & empty信号;

        (6)数据存储模块:利用双口ram实现数据存储。

        关于异步fifo的概念并不难理解,就是一个数据的储存和提取的过程。它的难点主要还是在手搓代码上,看评论我找的链接当中代码还是存在一些小问题,具体代码看那篇知乎链接,我就不再复制粘贴一遍了。

标签:en,CDC,信号,bit,data,reg,时钟
From: https://blog.csdn.net/2401_83129283/article/details/136732392

相关文章

  • RabbitMQ入门
    RabbitMq入门目录RabbitMq入门1.MQ1.1同步调用1.2异步调用1.3MQ技术选型2.RabbitMQ2.1安装2.2收发消息(交换机、队列)2.3数据隔离2.3.1用户管理2.3.2VirtualHost3.SpringAMQP3.1创建项目3.2快速入门3.2.1消息发送3.2.2消息接收3.2.3总结3.3WorkQueues模型3.3.1消费者消息推送限制3......
  • Python实现http接口请求数据后,往RabbitMQ里面插入数据
    python实现http接口请求数据服务后,往RABBITmq里面插入数据importtimeimportrequestsimportpikaimportdatetimebase_url='https://www.okx.com'api_url='/api/v5/market/history-mark-price-candles'#时间颗粒度[1m/3m/5m/15m/30m/1H/2H/4H]time_unit=[......
  • ic基础|时序篇05:多比特的跨时钟域处理(2)
    大家好,我是数字小熊饼干,一个练习时长两年半的ic打工人。我在两年前通过自学跨行社招加入了IC行业。现在我打算将这两年的工作经验和当初面试时最常问的一些问题进行总结,并通过汇总成文章的形式进行输出,相信无论你是在职的还是已经还准备入行,看过之后都会有有一些收获,如果看......
  • 与LDO背道而驰的DCDC
    LDO:低压差线性稳压器,比较常见的芯片为117,LDO的特性就如他的中文名一样,因为他的原理其实就是类似通过控制一个可变电阻来控制电压,从而达到稳压的效果,因此稳定的电压差不能太大否则电流就会过大,所以LDO的稳压器一般发热比较严重,损耗比较高,DCDC:开关稳压器,比较常见的芯片是2596,D......
  • Rabbit算法:轻量高效的加密利器
    Rabbit算法起源:Rabbit算法是由MartinBoesgaard和MetteVesterager提出的一种流密码算法,其设计初衷是为了提供高性能和高度安全性的加密方案。Rabbit算法结合了非线性的置换、置换和异或运算,以及密钥调度算法,使其成为一种优秀的加密算法。Rabbit加密解密|一个覆盖广泛主题......
  • 短链接资源集合 - Bitly, Tinyurl, Cutt, Shorturl, Rebrandly etc
    ShortURLPlatformhttps://t.co/网站权重PA:81,DA:94,SpamScore:N/Ahttps://bitly.com/网站权重PA:77,DA:92,SpamScore:3%https://tinyurl.com/app 网站权重PA:76,DA:94,SpamScore:1%https://cutt.ly/ 网站权重PA:68,DA:92,SpamScore:2%http://ow.ly/......
  • FPGA的时钟IP核知识点
    IP核在我看来就跟stm32中的一些驱动的库函数一样,可以调用快速使用。不用一步一步的自己写底层原理。可以加速设计,快速设计代码。IP核的PLL还有一个MMCM。PLL是锁相环,对时钟进行管理。也是后面使用中很重要的IP核。不同器件需要不同的时钟。时钟管理单元CMT=PLL+MMCM混合时钟管......
  • yii2+rabbitmq实现队列(windows)
    1.安装Erlang官方网站,https://erlang.org/download/otp_versions_tree.html,选择和rabbitmq适配的2.安装RabbitMQ官方网站,windows:https://www.rabbitmq.com/docs/install-windows3.安装下载的Erlang和RabbitMQ 碰到的问题:1.开启rabbitmq服务时dos窗口一闪而逝,看了服务进程......
  • 开源.NET8.0小项目伪微服务框架(分布式、EFCore、Redis、RabbitMQ、Mysql等)
    1、前言为什么说是伪微服务框架,常见微服务框架可能还包括服务容错、服务间的通信、服务追踪和监控、服务注册和发现等等,而我这里为了在使用中的更简单,将很多东西进行了简化或者省略了。年前到现在在开发一个新的小项目,刚好项目最初的很多功能是比较通用的,所以就想着将这些功能......
  • aardio 背景透明的3种方式(透明窗体1 webview2,透明窗体2-win-region-bitmap,透明窗体3-w
    3种透明模式我给起个名字,也好记忆。透明模式1:浏览器模式透明模式2:位图遮罩模式透明模式3:背景透明模式aardio背景透明的3种方式(透明窗体1webview2,透明窗体2-win-region-bitmap,透明窗体3-winform-transparent-color)3种透明窗体,主要分成是否可以穿透,遮罩组件,全部显示。透明......