K7DJ

还在头疼跨时钟域?异步FIFO深度计算与实例分析,帮你搞定!

9 0 0 0

还在头疼跨时钟域?异步FIFO深度计算与实例分析,帮你搞定!

1. 啥是异步FIFO?

2. 为啥要用异步FIFO?

3. 异步FIFO的深度怎么算?

3.1. 背靠背传输模型 (Worst Case)

3.2. 平均速率模型

3.3 其他情况

4. 实例分析

4.1. 背靠背模型计算

4.2 平均速率模型

4.3 结论与验证

5. 总结

附录:一些小技巧

还在头疼跨时钟域?异步FIFO深度计算与实例分析,帮你搞定!

兄弟们,今天咱们聊一个在音频处理、系统设计里绕不开的坎儿——跨时钟域。特别是当你设计的系统里,不同模块的时钟频率不一样,数据传输就容易出幺蛾子。这时候,异步FIFO就闪亮登场了!

不过,异步FIFO可不是随便拿来就用的,它的深度设置可是个技术活。设浅了,数据容易溢出;设深了,又浪费资源。那到底怎么设置才合理呢?别急,今天我就带你好好捋一捋,再结合实际案例,保证你以后再也不怕跨时钟域!

1. 啥是异步FIFO?

先来个灵魂拷问:啥是FIFO?

FIFO,全称First In First Out,先进先出。你可以把它想象成一个水管,数据从一头进去,从另一头出来,先进去的数据先出来,就这么简单。

那啥又是异步FIFO呢?

普通的FIFO,读写操作都用同一个时钟。而异步FIFO,读时钟和写时钟不一样,这就厉害了!它可以连接两个不同时钟域的模块,让它们之间安全可靠地传输数据。

你可以把异步FIFO想象成两个不同国家之间的海关。每个国家都有自己的货币(时钟),海关负责把货物(数据)从一个国家安全地运到另一个国家,并且保证货物不会丢失或者损坏。

2. 为啥要用异步FIFO?

再来个灵魂拷问:为啥要用异步FIFO?直接把两个不同时钟域的模块连起来不行吗?

兄弟,这可不行!你想想,如果两个模块的时钟频率不一样,一个快一个慢,会发生什么?

  • 如果写快读慢:写模块不停地往里塞数据,读模块来不及取走,数据就会像洪水一样溢出来,造成数据丢失。
  • 如果写慢读快:读模块不停地来取数据,写模块供不上货,读模块就会读到错误的数据,或者干脆“空转”。

这两种情况,都会导致系统出错,甚至崩溃!

所以,我们需要一个“缓冲池”,也就是异步FIFO,来协调两个模块之间的速度差异。写模块把数据写到FIFO里,读模块从FIFO里读数据,这样就避免了直接“硬碰硬”,保证了数据传输的可靠性。

3. 异步FIFO的深度怎么算?

终于到了最关键的部分了!异步FIFO的深度怎么算?

别慌,咱们先来分析一下影响FIFO深度的因素:

  • 写时钟频率 (Wclk):写模块的时钟频率。
  • 读时钟频率 (Rclk):读模块的时钟频率。
  • 突发写入数据量 (Burst_length):一次连续写入的数据量。 比如,一次性写入100个数据。
  • 突发写入间隔 (Burst_interval): 两次突发写入之间的最小时间间隔。比如,每1000个时钟周期进行一次突发写入。
  • 时钟频率差异:写时钟和读时钟之间的频率差异。差异越大,FIFO深度要求越高。
  • 裕量 (Margin):为了应对各种不可预测的情况,我们需要留一些裕量。一般建议留20%~50%。

有了这些参数,我们就可以计算FIFO的深度了。这里介绍两种常用的计算方法:

3.1. 背靠背传输模型 (Worst Case)

这种方法考虑的是最坏的情况,也就是写模块以最快的速度连续写入数据,读模块以最慢的速度连续读取数据。这种情况下的FIFO深度计算公式如下:

FIFO_depth = Burst_length - (Burst_length * Rclk / Wclk) + Margin

这个公式的含义是:

  1. Burst_length:写模块一次突发写入的数据量。
  2. (Burst_length * Rclk / Wclk):在写模块突发写入期间,读模块能够读取的数据量。
  3. Burst_length - (Burst_length * Rclk / Wclk):在写模块突发写入期间,FIFO中累积的数据量。即,写数据量-读数据量=FIFO中剩余的数据量
  4. + Margin:加上裕量。

这个公式计算出来的FIFO深度是比较保守的,可以保证在最坏情况下也不会发生数据溢出。但是,在实际应用中,往往不需要这么大的深度。

3.2. 平均速率模型

这种方法考虑的是数据的平均写入速率和平均读取速率。计算公式如下:

FIFO_depth = (Burst_length / Burst_interval) * (Wclk - Rclk) * (Burst_interval / Wclk) + Margin
FIFO_depth = Burst_length * (1 - Rclk/Wclk) + Margin

该公式是基于背靠背传输模型推导得出。

这个公式计算出来的FIFO深度比背靠背模型要小一些,更接近实际需求。但是,它要求数据的写入和读取是比较均匀的,不能有长时间的突发写入或者突发读取。

3.3 其他情况

上面两个公式计算的都是写快读慢的情况。如果是读快写慢,需要保证FIFO不会被读空即可. 这种情况下不需要太大的FIFO深度。

4. 实例分析

光说不练假把式,咱们来个实例分析。

假设有一个音频处理系统,ADC(模数转换器)以48kHz的采样率(Wclk)向FPGA输出音频数据,FPGA内部的音频处理模块以50kHz的时钟频率(Rclk)处理数据。每次突发写入128个数据(Burst_length),每500个时钟周期发生一次突发(Burst_interval)。

现在,我们需要在ADC和FPGA之间加一个异步FIFO,来保证数据传输的可靠性。那么,FIFO的深度应该设置为多少呢?

4.1. 背靠背模型计算

FIFO_depth = 128 - (128 * 50000 / 48000) + (128 * 0.2)  ≈ 19

我们向上取整,按照背靠背传输模型, FIFO深度至少要设置为20。

4.2 平均速率模型

FIFO_depth = 128 * (1- 48000/50000) + (128 * 0.2) = 30.72

我们向上取整,按照平均速率模型,FIFO深度至少要设置31。

4.3 结论与验证

综合考虑两种计算方法,并留有裕量,我们可以将FIFO深度设置为32。 实际上两种计算结果差异较大,这是因为两个时钟的频率非常接近. 如果差距变大,那么背靠背传输模型的计算结果也会更大。

在实际应用中,我们还需要通过仿真或者实际测试来验证FIFO深度的设置是否合理。如果发现FIFO经常溢出或者空闲,就需要调整FIFO的深度。

5. 总结

异步FIFO是跨时钟域设计的必备神器,但是FIFO深度的设置需要仔细考虑。本文介绍了两种常用的FIFO深度计算方法,并通过一个实例进行了分析。希望这篇文章能帮助你更好地理解异步FIFO,并在实际设计中灵活运用。

记住,理论结合实践才是王道!多动手,多思考,你也能成为跨时钟域设计的高手!

附录:一些小技巧

  • 在设计异步FIFO时,尽量使用成熟的IP核,避免自己从头开始写代码。
  • 使用格雷码进行跨时钟域的地址/指针传输,可以减少亚稳态的发生概率。
  • 在仿真时,要特别注意异步FIFO的复位和初始化。
  • 如果FIFO深度较大,可以考虑使用块RAM来实现。
  • 在实际测试中,可以使用逻辑分析仪来观察FIFO的状态。

好了,兄弟们,今天的分享就到这里。如果你还有什么问题,或者有什么心得体会,欢迎在评论区留言交流!

Apple

Comment

打赏赞助
sponsor

感谢您的支持让我们更好的前行