异步时钟亚稳态 的解决方案——多bit信号

2024-02-01 21:18

本文主要是介绍异步时钟亚稳态 的解决方案——多bit信号,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 1. 时钟偏斜 导致的采样中间值问题
  • 2. Gray码
      • 循环单bit翻转 编码方式
  • 3. 同步使能 valid
      • avalid 最小持续时间 和 最小时间间隔
  • 3. 异步FIFO


FPGA 设计之 跨时钟域(三 - 多比特小结)
FPGA 设计之 跨时钟域(四 - 格雷码)
FPGA 设计之 跨时钟域(六 - 握手)
同步valid&ready握手 与 异步valid&ack握手
《Clock Domain Crossing》 翻译与理解(5)多信号跨时钟域传输
推荐】数字芯片跨时钟域设计经典论文
多bit信号跨时钟域怎么办? – CDC的那些事(4)
菜鸟教程:4.2 Verilog 跨时钟域传输:慢到快

1. 时钟偏斜 导致的采样中间值问题

时钟偏斜:时钟沿信号到达各触发器CK端的时间不同

这会导致多bit信号的每个触发器值变化不是同时的,有的变得快有的变得慢,如果每个bit都没变完,就被异步时钟采样了,就会出现中间值。

单bit信号电平也好,脉冲也好跨时钟域,采样到了就算有点延迟也没关系。
但是多bit信号要求整个变化过程都是恒定的,中间出现了第三个值就可能对功能产生影响。

看图

在这里插入图片描述
红线处adata由000变为111,因为时钟偏斜,该信号每个bit真正开始拉高的时刻不一样。如果异步时钟bclk在不同的时刻采样会对应不同时刻的值,3条绿线分别对应采样到001、101、111。

尽管最终也会采到正确的值,但是中间值的出现会在bclk内存在一拍,思考如何消除这个。

2. Gray码

格雷码,yyds

回到问题,中间值的出现是因为采样的时候各bit变化情况不一,那我让每个时钟沿处 电平变化的触发器个数只有一个不就完事了。

反正二进制计数器是不可能只变1bit,Gray码可以,如下表

Gray码 二进制码
000 000
001 001
011 010
010 011
110 100
111 101
101 110
100 111

由此可见,Gray码的邻位只有1bit翻转,并且数值2^N与0也只有1bit翻转

实际上不一定非得按照Grey码的值来,基于此。

相邻信号只有1bit翻转,且满足"3个沿"条件 可直接 电平同步实现多bit信号的跨时钟域传输。

其实就是将多bit信号跨时钟域问题转化为单bit信号的跨时钟域问题

然后给出一个Gray码与二进制码的转换方式

assign gray = (binary >> 1) ^ binary;				//binary code to gray codeinteger i;
for(i=0;i<DATA_WIDTH;i=i+1)							//gray code to binary codebinary[i] = ^(gray >> i);

循环单bit翻转 编码方式

就是这个多bit信号的变化顺序是从最小值到最大值,然后又转回最小值或者反过来。在这种循环的变化方式下,该如何编码保证相邻状态间只有1bit翻转呢?

例如0,1,2,3,4,5,6,7,0,1,2,…这种。
但如果有中间值突然蹦到其他值,例如0,1,2,3,4,5,0,1,2,3,4,5,6,7,0,…就需要具体问题具体分析了

循环变化,值域个数为2^N时,使用 Gray码

Gray自己就是2^N的值可实现循环变化时的单bit翻转

循环变化,值域个数为偶数但不满足2^N时,使用 带扩展位的Gray码

例如6、10、12这种不满足2^N,就可以在Gray码的基础上加一位扩展位。

例如可取的值有6个,分成两半,一半是扩展位为0的递增Gray码,另一半是扩展位为1的递减Gray码

变化过程如下:

0_000 (0)1_000	(5)				//3个数是扩展位为0的递增Gray码,另外3个数是扩展位为1的递减Gray码↓		    	↑
0_001 (1)	  1_001 (4)↓		    	↑
0_011 (2)1_011 (3)

再如 10

0_000  (0)1_000  (9)↓		    	 ↑
0_001  (1)	   1_001  (8)↓		    	 ↑
0_011  (2)	   1_011  (7)↓		    	 ↑
0_010  (3)	   1_010  (6)↓		    	 ↑
0_110  (4)1_110  (5)

循环变化,值域个数为奇数,可 ×2转化为偶数情形

奇数个数循环的话,可 每2次奇数个数的循环看作是1次偶数个数的循环,例如

个数为5时,则每2个5转化为1个10就变成偶数情形,使用带扩展位的Gray码

第一轮和第二轮的变换过程如下,解码也不难

0_000  (第一轮0)1_000  (第二轮4)↓		    	 		 ↑
0_001  (第一轮1)	       1_001  (第二轮3)↓		    	 		 ↑
0_011  (第一轮2)	  	   1_011  (第二轮2)↓		    	 		 ↑
0_010  (第一轮3)	       1_010  (第二轮1)↓		    	 		 ↑
0_110  (第一轮4)1_110  (第二轮0)

异步FIFO的读写指针就是借助的这种形式。

3. 同步使能 valid

Gray码是简单易行,这里还有另一个思路。

你这个时钟偏斜让每个bit变化时刻不统一嘛,那我等你多bit数据稳定了再采样不就完事了。

那怎么才能确定你这个多bit信号稳定了呢?

一般啊,多bit信号传输 总会配一个1bit有效标志valid,它会与多bit信号时钟对齐,并且传输时为高。

如果时间够用的话,对valid直接打三拍判个沿就可以采样了,打拍也算延迟了。

如下图所示

在这里插入图片描述

avalid拉低表示传输结束,adata没变是用于省电,常见手法

上代码

module data_sync#(DATA_WIDTH = 4)(input					rstn,input 					aclk,input [DATA_WIDTH-1:0]  adata,input 					avalid,input 					bclk,output [DATA_WIDTH-1:0] bdata,output					bvalid);reg bvalid_d1;
reg bvalid_d2;
reg bvalid_d3;
wire bvalid_pl;
reg [DATA_WIDTH-1:0] bdata_r;
reg bvalid_r;always@(posedge clk) beginif(!rstn) beginbvalid_d1 <= 1'b0;bvalid_d2 <= 1'b0;bvalid_d3 <= 1'b0;endelse beginbvalid_d1 <= avalid;bvalid_d2 <= bvalid_d1;bvalid_d3 <= bvalid_d2;end
endassign bvalid_pl = bvalid_d2 && (!bvalid_d3);			//界定bvalid的拉高和拉低always@(posedge clk) beginif(!rstn) bdata_r <= 0;else if(bvalid_pl)bdata_r <= adata;
endalways@(posedge clk) beginif(!rstn) bvalid_r <= 0;else if(bvalid_pl)bvalid_r <= 1'b1;
endassign bdata = bdata_r;
assign bvalid = bvalid_r;endmodule

为什么要做个脉冲,而不是直接在bvalid_d2为高时采样、为低时停止采样呢?
从图中可以看出,bvalid_d2的下降沿时刻对应的avalid已经为低了,即adata可能已经发生了变化。
所以bdata不能持续地驱动,即bdata <= adata;,而只能在脉冲时刻驱动一次

注意bvalid和bdata可根据实际情况调整有效时间,因为多bit信号已经捕获,因此需要持续多长时间需根据具体设计决定

从图中可以看出,bclk采样adata是基于bvalid_pl脉冲,所如果bvalid_pl为高时adata是否有可能变化为新值了?

avalid 最小持续时间 和 最小时间间隔

● 最小持续时间:其实很好计算,从bclk采样到avalid开始,经过了 3 T b c l k 3T_{bclk} 3Tbclk才将adata采样,结合之前讲到的脉冲稳定采样的"3个沿"标准,所以 avalid的最小持续时间为 1.5 T b c l k + 3 T b c l k 1.5T_{bclk}+3T_{bclk} 1.5Tbclk+3Tbclk

● 最小时间间隔:与脉冲跨时钟域问题类似,如果两次脉冲的间隔过小,会让接受时钟域认为是一次脉冲。

同理,对于多bit传输来说,每次传输bvalid拉高,那么两次bvalid为高之间的间隔也不能过小,会让bclk认为是同一次传输,只会产生一个上升沿脉冲,所以也只更新一次数据。

那么bvalid为低的最小间隔是多少呢?其实就是bclk的三个沿,也就是说只要能让bclk采样到avalid为低,就可以产生两次采样脉冲,进而采样两次了。

在这里插入图片描述

上图就表明了avalid的持续时间和间隔时间的极限情况。

可见同步使能的方法对使能持续时间和间隔时间都有限制,只要某一个限制不满足就会丢失adata,这也说明aclk的adata变化较为频繁,可采用异步FIFO解决。

实际上可采用握手的方法为avalid和adata展宽,然后使用同步使能的方法,但是握手非常耗费时间,不如直接上FIFO。

3. 异步FIFO

这个异步FIFO就行啊,一端写、一端读,读写时钟不一样。

但是异步FIFO实际上并未解决数据信号跨时钟域问题,而是把问题转化成多bit读写指针的跨时钟域问题了。

所以对于读写指针而言,需要电平同步 + Grey码的方式进行处理,同时读写逻辑也并不关注读写指针的变化过程,因此快采慢的多采样问题和慢采快的漏数问题都不会产生影响。

因此,full和empty标志并不能实时反应当前时刻FIFO的真实状态,但这种错误并不会造成满写和空读的问题。

详情见异步FIFO设计

这篇关于异步时钟亚稳态 的解决方案——多bit信号的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/668490

相关文章

javax.net.ssl.SSLHandshakeException:异常原因及解决方案

《javax.net.ssl.SSLHandshakeException:异常原因及解决方案》javax.net.ssl.SSLHandshakeException是一个SSL握手异常,通常在建立SS... 目录报错原因在程序中绕过服务器的安全验证注意点最后多说一句报错原因一般出现这种问题是因为目标服务器

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

全屋WiFi 7无死角! 华硕 RP-BE58无线信号放大器体验测评

《全屋WiFi7无死角!华硕RP-BE58无线信号放大器体验测评》家里网络总是有很多死角没有网,我决定入手一台支持Mesh组网的WiFi7路由系统以彻底解决网络覆盖问题,最终选择了一款功能非常... 自2023年WiFi 7技术标准(IEEE 802.11be)正式落地以来,这项第七代无线网络技术就以超高速

Java死锁问题解决方案及示例详解

《Java死锁问题解决方案及示例详解》死锁是指两个或多个线程因争夺资源而相互等待,导致所有线程都无法继续执行的一种状态,本文给大家详细介绍了Java死锁问题解决方案详解及实践样例,需要的朋友可以参考下... 目录1、简述死锁的四个必要条件:2、死锁示例代码3、如何检测死锁?3.1 使用 jstack3.2

html 滚动条滚动过快会留下边框线的解决方案

《html滚动条滚动过快会留下边框线的解决方案》:本文主要介绍了html滚动条滚动过快会留下边框线的解决方案,解决方法很简单,详细内容请阅读本文,希望能对你有所帮助... 滚动条滚动过快时,会留下边框线但其实大部分时候是这样的,没有多出边框线的滚动条滚动过快时留下边框线的问题通常与滚动条样式和滚动行

Oracle修改端口号之后无法启动的解决方案

《Oracle修改端口号之后无法启动的解决方案》Oracle数据库更改端口后出现监听器无法启动的问题确实较为常见,但并非必然发生,这一问题通常源于​​配置错误或环境冲突​​,而非端口修改本身,以下是系... 目录一、问题根源分析​​​二、保姆级解决方案​​​​步骤1:修正监听器配置文件 (listener.

MySQL版本问题导致项目无法启动问题的解决方案

《MySQL版本问题导致项目无法启动问题的解决方案》本文记录了一次因MySQL版本不一致导致项目启动失败的经历,详细解析了连接错误的原因,并提供了两种解决方案:调整连接字符串禁用SSL或统一MySQL... 目录本地项目启动报错报错原因:解决方案第一个:第二种:容器启动mysql的坑两种修改时区的方法:本地

安装centos8设置基础软件仓库时出错的解决方案

《安装centos8设置基础软件仓库时出错的解决方案》:本文主要介绍安装centos8设置基础软件仓库时出错的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录安装Centos8设置基础软件仓库时出错版本 8版本 8.2.200android4版本 javas

Java空指针异常NullPointerException的原因与解决方案

《Java空指针异常NullPointerException的原因与解决方案》在Java开发中,NullPointerException(空指针异常)是最常见的运行时异常之一,通常发生在程序尝试访问或... 目录一、空指针异常产生的原因1. 变量未初始化2. 对象引用被显式置为null3. 方法返回null