赞
踩
为了彻底理解跨时钟域问题,多方搜集资料,做个简单整理备忘。主要参考了如下几个资源:
- https://zhuanlan.zhihu.com/p/45186793 跟IC君一起学习集成电路
- https://www.cnblogs.com/PG13/p/10329678.html 新芯时代
- 格雷码 https://www.cnblogs.com/zhuruibi/p/8988044.html
- 主要参考来源:“ASIC 中的异步时序设计” 王夏泉 华中科技大学
异步时序设计指的是在设计中有两个或以上的时钟, 且时钟之间是同频不同相或不同频率的关系。而异步时序设计的关键就是把数据或控制信号正确地进行跨时钟域传输。
每一个触发器都有其规定的建立(setup)和保持(hold)时间参数, 在这个时间参数内, 输入信号在时钟的上升沿是不允许发生变的。 如果在信号的建立时间中对其进行采样, 得到的结果将是不可预知的,即亚稳态。
触发器进入亚稳态的时间可以用参数 MTBF(mean time between failures)来描述, MTBF即触发器采样失败的时间间隔,其公式描述如下:
其中:
对于一个典型的 0.25µm 工艺的 ASIC 库中的一个触发器,我们取如下的参数:
tr = 2.3ns, τ = 0.31ns, T0 = 9.6as, f=100MHZ, a = 10MHZ, MTBF = 2.01 days
也就是说触发器以100MHZ工作,我们用10MHZ的频率去不停地采它的数据,则每两天就可能采集到一次亚稳态(个人理解,如有误请指正)。如果使用单锁存器同步:
b的时钟上升沿采集a的数据时很可能采到亚稳态数据。
为了避免亚稳态,应该使得MTBF尽量大。采用双触发器可以改善这一问题:
当使用了双触发器以后, b_dat2 的MTBF由以下公式可以得出:
注意问题1
时钟域B两级同步的寄存器跟时钟域A的输出寄存器之间不能有组合逻辑。组合逻辑电路各个输入信号的不一致性以及组合逻辑内部路径的延时时间不一样,运算后的信号存在毛刺如图(2),我们无法预先知道CLKB 的上升沿何时会到来,CLKB 采样到的信号就无法预知。
因此,要想CLKB 能采到稳定的信号,时钟域A的信号必须是经过CLKA 敲过,在一个时钟周期内是稳定的信号,如图(3)所示:
注意问题2
Clock-gating enable 信号没有经过异步处理:
在下图中a_in 信号经过CLKA的DFF敲过,再送到两级DFF 同步器处理,完全没毛病。但是F2的使能信号EN是从时钟域A来的,当EN信号变化的时候,由于时钟域不一样,无法保证使能之后的CLKB信号采样数据时满足setup/hold time 要求,这时F2输出信号也就变得无法预测了。因此对clk gating的信号也要做处理。
如果a_clk的频率比b_clk频率高,将可能会出现因为dat变化太快而使b_clk无法采到的问题。即在信号从快时钟域向慢时钟域过渡的时候, 如果信号变化太快, 慢时钟将可能无法对该信号进行正确采样, 如下图所示。 所以在使用双锁存器法的时候, 应该使原始信号保持足够长的时间, 以便另一个时钟域的锁存器可以正确的对其进行采样。
下面介绍一种“结绳法”,适合任何时钟域的过渡:
其中标明_clk1 的信号表示该信号属于 clk1 时钟域, 同理标明_clk2 的信号表示该信号属于 clk2 时钟域。在两次src_req_clk1 之间被 src_vld_clk1“ 结绳” (pluse2toggle),在将src_vld_clk1 用双锁存器同步以后, 将该信号转换为 dst_req_clk2(toggle2pluse)。同理,用dst_vld_clk2 将 dst_req_clk2“结绳”, dst_vld_clk2 表明在 clk2 时钟域中, src_dat_clk1 已经可以进行正确采样了。 最后将 dst_vld_clk2 转换为 dst_ack_clk1(synchronizer and toggle2pluse), dst_ack_clk1 表明 src_dat_clk1 已经被 clk2 正确采样了, 此后 clk1 时钟域就可以安全地传输下一个数据了。 可以看出,“结绳法” 关键是将信号结绳以后, 使其保持了足够长的时间,以便另一个时钟可以正确地采样。
电路图如下:
上图描述了握手协议的完整流程,其中三角带横线的符号是异或门。同时给出了两个脉冲之间结绳信号(vld信号)的产生方法。
下图是一种更加直观的描述:
脉冲信号一般是通过上升沿采样实现的。
处理多bit数据的跨时钟域,一般采用异步双口RAM。假设我们现在有一个信号采集平台,ADC芯片提供源同步时钟60MHz,ADC芯片输出的数据在60MHz的时钟上升沿变化,而FPGA内部需要使用100MHz的时钟来处理ADC采集到的数据(多bit)。
在这种类似的场景中,我们便可以使用异步双口RAM来做跨时钟域处理。先利用ADC芯片提供的60MHz时钟将ADC输出的数据写入异步双口RAM,然后使用100MHz的时钟从RAM中读出。
但我们读出RAM中的数据时,肯定不是一上电就直接读取,而是要等RAM中有ADC的数据之后才去读RAM。这就需要100MHz的时钟对RAM的写地址进行判断,当写地址大于某个值之后再去读取RAM。
在这个场景中,其实很多人都是使用直接用100MHz的时钟对RAM的写地址进行打两拍的方式,但RAM的写地址属于多bit,如果单纯只是打两拍,那不一定能确保写地址数据的每一个bit在100MHz的时钟域变化都是同步的,肯定有一个先后顺序。如果在低速的环境中不一定会出错,在高速的环境下就不一定能保证了。所以更为妥当的一种处理方法就是使用格雷码转换。
格雷码简介
在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码(Gray Code),另外由于最大数与最小数之间也仅一位数不同,即“首尾相连”,因此又称循环码或反射码。格雷码(Gray Code)又称Grey Code、葛莱码、格莱码、戈莱码、循环码、反射二进制码、最小差错码等。
格雷码有多种编码形式
十进制数 | 4位自然二进制码 | 4位典型格雷码 | 十进制余三格雷码 | 十进制空六格雷码 | 十进制跳六格雷码 | 步进码 |
---|---|---|---|---|---|---|
0 | 0000 | 0000 | 0010 | 0000 | 0000 | 00000 |
1 | 0001 | 0001 | 0110 | 0001 | 0001 | 00001 |
2 | 0010 | 0011 | 0111 | 0011 | 0011 | 00011 |
表中典型格雷码具有代表性。若不作特别说明,格雷码就是指典型格雷码,它可从自然二进制码转换而来。
二进制格雷码的生成方法有很多,具体可自行搜索或见:
https://www.cnblogs.com/zhuruibi/p/8988044.html
回到刚才的问题,多比特利用双寄存器打两拍在高速场合不再适用,而使用格雷码可以将这种多比特变为单比特传输(格雷码每次变化只有一位会变)如果先将RAM的写地址转为格雷码,然后再将写地址的格雷码进行打两拍,之后再在RAM的读时钟域将格雷码恢复成10进制。这种处理就相当于对单bit数据的跨时钟域处理了。
异步FIFO
使用异步双口ram的场合其实用异步fifo也是一样的。
使用场景:在有大量的数据需要进行跨时钟域传输, 并且对数据传输速度要求比较高的场合 。
一个异步 FIFO 一般由如下部分组成:
1. Memory, 作为数据的存储器;
2. 写逻辑部分,主要负责产生写信号和地址;
3. 读逻辑部分,主要负责产生读信号和地址;
4. 地址比较部分,主要负责产生 FIFO 空、满的标志。
异步FIFO代码可以参考我的另一篇文章:
https://blog.csdn.net/darknessdarkness/article/details/104726798
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。