异步fifo为什么读空了?

本文转载自: FPGA的现今未微信公众号

问题背景

在一个跨异步时钟的设计中,数据需要从A时钟域同步到B时钟域,AB时钟是同频但是不同源的异步时钟,比如都是100M,A时钟为接口时钟,B时钟来自PLL输出的时钟。

数据同步的时候,采用的是异步FIFO的方案,即100M的接口时钟写入数据,100M的PLL时钟读出数据。写入的时候采用整包写入,即一个数据报文写入的时候不会断续,同样,根据后继模块的需要,读出一个完整报文的时候也不能出现断续,要整包读,所以读出的方案采用非空即读。

问题现象

在上板测试中,经过状态、统计等信息发现B时钟域处理报文的过程中,出现了畸形报文,然后被丢弃了,导致后续模块没有收到报文。

定位分析

1、首先怀疑是不是A时钟域写入的报文就是一个异常报文,通过检测,没有发现异常;

2、确认了该异步FIFO没有出现上溢出和下溢出的情况;

3、通过抓取信号,发现FIFO的读使能出现了一拍的断续,从设计的角度这是不应该存在的。因为考虑到FIFO的读写都是100M时钟,写入是整包写入,非空即读的话应该也是整包输出,不应该断续。如果断续了,后继模块会认为这是一个畸形包。

4、进一步抓取FIFO的空信号,发现读了一拍数据后,空信号确实拉高了。如下图所示:

问题根因

通过上述的定位和分析,问题原因基本确定了,虽然读写都是100M的时钟,但是不同源,当读出一个数据后,因为异步FIFO地址同步需要时间,读时钟域有可能没有来得及“看到”写时钟域地址的变化,导致读时钟域认为FIFO空了。这是由异步FIFO本身的特性决定的。

解决方案

知道了问题原因,解决就方便了,对于这个问题,有2种解决方案。

方案1、利用整包计数器,即当fifo中有一个完成的报文数据以后再开始读取FIFO,这样可以保证FIFO在读取一个完成报文的时候不会读空。

方案2、将非空即读,修改成将空的时候再读,比如将空的水限为8,那就是等FIFO中有8个数据后再读。

上述2种方案,其实都是为了等待一个延时,即等待写时钟写入一定量的数据后才开始读数据,保证读出一个报文的时候是连续的。整包计数器的方案需要缓存一个整包,对FIFO的空间大小有要求,比如能完成的存放一个最大的报文。而方案2,不关注最大报文长度,只需要一个很小的FIFO,比如深度为32,就可以完成上述的异步时钟域转换。上述两种方案经过实际测试,都是可行的。

最新文章

最新文章