概述
本篇文章仅用于个人学习,如有雷同,我抄他的。
跨时钟域是每个FPGA初学者都会遇到的问题,跨时钟域分情况有以下几种:
单bit跨时钟域
慢时钟域到快时钟域
快时钟域到慢时钟域
多bit跨时钟域
单bit跨时钟域
慢时钟域到快时钟域
首先谈谈单bit数据的跨时钟域问题,当从慢时钟域到快时钟域时,常用方法为打两拍。首先快时钟域是肯定可以采集到慢时钟域的数据的,所以需要解决的就是亚稳态的问题。打两拍的基本原理就是,数据(处于10Mhz时钟下)在跳变过程中不是瞬时的,总有一个跳变时间。如果在clk(处于125Mhz下)的上升沿采集到了数据的跳变过程时,此时的数据是不确定的,可能是1,可能是0,这就导致了亚稳态的产生。具体如下图所示,图片来自以下博客。
解决跨时钟域问题的三大方法_zuokai的博客-CSDN博客_跨时钟域https://blog.csdn.net/weixin_43343190/article/details/82956033?ops_request_misc=&request_id=&biz_id=102&utm_term=%E8%B7%A8%E6%97%B6%E9%92%9F%E5%9F%9F&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-82956033.first_rank_v2_pc_rank_v29&spm=1018.2226.3001.4187
此时Q1的采集就会有很大概率出现亚稳态的问题,但在下个时钟的上升沿就可以采集到一个确定的数值了,此时就可以很大程度上解决亚稳态的问题。顺便记录一个跨时钟域的使能信号的传输方法,具体代码如下。
reg R_data_en ;
reg R_data_en_1 ;
reg R_data_en_2 ;
wire W_data_en ;//125mhz下的使能信号
always@(posedge I_clk_125mhz or I_reset_n)
begin
if (~I_reset_n) begin
R_data_en <= 'b0;
R_data_en_1 <= 'b0;
R_data_en_2 <= 'b0;
end
else begin
R_data_en <= I_data_en ;//I_data_en 是时钟为10mhz下的使能信号
R_data_en_1 <= R_data_en ;
R_data_en_2 <= R_data_en_1;
end
end
assign W_data_en = R_data_en_1 & (!R_data_en);
时序图如下所示,红色表示亚稳态采集的数据是个不确定的值。一般来说,数据延时一个时钟后,R_data_en基本可以满足R_data_en1的建立时间和保持时间的要求。
快时钟域到慢时钟域
而后就是单bit数据的快时钟域到慢时钟域的跨时钟域,慢时钟域想采集到快时钟域的数据是非常困难的,因此我们需要对数据进行展宽。
单bit数据大多数都是使能信号或者标志类信号,此时只需要将信号展宽到慢时钟域能采集到的长度即可,一般来说要超过慢时钟域的一个时钟周期长度。如下图所示,如果是第一种情况,慢时钟很明显可以采集的到,但如果是第二种情况,在慢时钟的上升沿,就采集不到输入信号的变化了。
展宽的方式在网上看到许多种 ,比较常用的是结绳法,反馈法。具体参照以下博客。
单bit控制信号的跨时钟域传输_拉钩上吊一百年的博客-CSDN博客https://blog.csdn.net/qq_42322644/article/details/115725735?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%8D%95bit%20%E8%B7%A8%E6%97%B6%E9%92%9F%E5%9F%9F&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-9-115725735.first_rank_v2_pc_rank_v29&spm=1018.2226.3001.4187
多bit跨时钟域
多bit数据的跨时钟域常用方法之一是使用异步FIFO( First Input First Output),在vivado中有许多的IP核可供使用,其中的FIFO IP核就是非常常用的IP核,FIFO的基本使用方法如以下博客。
Vivado IP核fifo使用指南_Kevin-CSDN博客https://blog.csdn.net/baidu_25816669/article/details/88941458?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163806879416780261961570%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163806879416780261961570&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-88941458.first_rank_v2_pc_rank_v29&utm_term=FIFO+ip&spm=1018.2226.3001.4187 需要注意的几个点是,如果FIFO IP的读写位宽不一致的话,都是先 出/入 的在高位,后出/入 在低位。
跨时钟域有两种实现方案,第一种是边读边写,第二种是分时读写。
1、边读边写:
比如读时钟为100MHz,写时钟为10MHz,便可以让读数据一方进行计数,每计数10个时钟便读出一个数据,反过来,若写时钟为100MHz,读时钟为10MHz,便10个时钟写一个数据。
2、分时读写
分时读写,其实本质就是乒乓操作
FPGA重要的设计思想——乒乓操作_dongdongnihao_的博客-CSDN博客_乒乓操作https://blog.csdn.net/dongdongnihao_/article/details/80037171?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163808144916780357220465%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163808144916780357220465&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-4-80037171.first_rank_v2_pc_rank_v29&utm_term=%E4%B9%92%E4%B9%93%E6%93%8D%E4%BD%9C&spm=1018.2226.3001.4187 基本原理就是有两个存储单元,比较常用的存储单元为双口RAM(Dual RAM),SRAM,SDRAM,FIFO等。第一个存储周期对第一个存储单元进行写操作,第二个存储周期对第二个存储单元进行写操作,并与此同时对第一个存储单元进行读操作。第三个存储周期对第一个存储单元进行写操作,并对第二个存储单元进行读操作,循环往复。
乒乓操作的优点:
通过“输入数据选择单元”和“输出数据选择单元”按节拍、相互配合的切换,将经过缓冲的数据流没有停顿地送到“数据流运算处理模块”进行运算与处理。把乒乓操作模块当做一个整体,站在这个模块的两端看数据,输入数据流和输出数据流都是连续不断的,没有任何停顿,因此非常适合对数据流进行流水线式处理。所以乒乓操作常常应用于流水线式算法,完成数据的无缝缓冲与处理。
当写数据的时钟远慢于读时钟,可以只使用一个存储单元,例如写时钟为10MHz,读时钟为100MHz,每当写入10个数据时,读已经可以读出100个数据了,此时就可以使用一个深度为128的FIFO,读写双方各自计数。我们保持写操作持续不断,每当写数据计数到100时,便开始读数据100个,当读完后便等待下一次写数据计数到100,此时最多同时占用110的深度,仍还有18个空余位置,所以读写操作不会产生冲突导致写数据时产生拥塞,导致数据丢失的问题,其实就等同于乒乓操作中的两个存储单元在同一FIFO中。
如有错漏,后续补充
最后
以上就是无语猫咪为你收集整理的FPGA——浅谈跨时钟域单bit跨时钟域多bit跨时钟域 的全部内容,希望文章能够帮你解决FPGA——浅谈跨时钟域单bit跨时钟域多bit跨时钟域 所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复