(转)FPGA时序问题一例——异步接口和毛刺敏感电路保护
原文链接:http://blog.ednchina.com/riple/41367/message.aspx
一、出问题的异步接口介绍 riple
下图是主机(PC机)以MDMA的方式访问IDE硬盘设备的时序图,这里采用FPGA设计的是设备端的接口。 riple
DIOR-/DIOW-信号由主机驱动,“读/写”数据在“DIOR-/DIOW-”信号的上升沿被“主机/FPGA”采样。注意,DIOR-/DIOW-信号是用负逻辑表示的,图中下降沿对应物理信号的上升沿。 riple
图中tD=70ns,tK=25ns,tG和tH分别是20ns和10ns。 riple
该接口看似简单,读出数据时由FPGA对主机的控制信号DIOR-和片选信号译码后驱动,采用组合逻辑实现;写入数据被FPGA在DIOW-上升沿采样,用于数据输入。时序问题就出现在数据写入接口上。 riple
数据写入接口的处理是这样的: riple
- 总线数据在DIOW-上升沿被FPGA采样,FPGA内部采用DIOW-上升沿触发的寄存器组暂存采样数据。这是一个相对于本地时钟的异步操作。 riple
- 采用50MHz时钟对DIOW-信号进行两级同步,同步后的信号提取上升沿对应的同步脉冲。这是一个异步信号变同步信号的操作。 riple
- 在DIOW-上升沿同步脉冲有效时,暂存的数据被写入同步FIFO中。这是一个同步操作。 riple
这样一来,采用“先暂存,再写入”的方式,原本与FPGA片内50MHz时钟异步的数据就变为同步的了。 riple
二、时序问题的表现 riple
该接口的问题表现为数据错误,即采用“先写后读”方式进行连续的1个扇区数据传输校验会出现读写数据不一致的现象。 riple
通过察看出错时存储介质上的数据,发现数据错误出现在写入阶段,读出阶段没有问题。 riple
该数据错误有三个显著的特点: riple
举个例子:原本是15、16、17、18的数据序列(1),出错后变成15、17、17、18数据序列(2)。 riple
这里有一个问题,同样是数据重复,可不可以认为序列(2)的错误模式等同于15、16、16、18数据序列(3)的错误模式呢?不可以。 riple
其实,序列(3)和序列(2)是截然不同的。序列(3)的错误模式是已经出现的数据16覆盖了将要出现的数据17,导致16、16、18的不连贯;序列(2)的错误模式是将要出现的数据17覆盖了已经出现的数据16,导致15、17、17的不连贯。 riple
所以,序列(2)模式是该时序问题的第三大特点。 riple
由于我最初认为错误模式是序列(3)类型的,找错了方向,没能找到导致问题出现的原因。 riple
三、时序问题的定位 riple
我的一名同事发现并指出了序列(2)与序列(3)错误模式的差异,并指出这样一个矛盾:在数据写入过程中,接口电路只有“预知”将要写入的数据才会出现序列(2)的错误模式,而“预知”是不可能出现在数字电路中的。 riple
在此基础上,我反复思考了导致“预知”现象背后的原因。 riple
首先,“预知”是不可能发生的,在这个不合理的现象背后一定有合理的原因。其次,这样一个成熟的接口电路在逻辑上不会出现“预知”现象,一定是我对该接口进行的处理导致了该现象。再次,该现象随机出现,而且孤立,所以不可能是逻辑问题,应该是接口时序问题,而且是偶然事件导致的。 riple
那么,是什么样的偶然事件在怎样的时序下导致一个正常的电路出现不正常的行为呢?先定义两个概念。 riple
从总线数据被暂存到暂存的数据被写入FIFO存在一定的时间间隔——数据暂存时间。暂存时间的长度由两级同步电路的形式唯一确定,取值为2~3个同步时钟周期。 riple
从DIOW-的上升沿到上升沿的时间间隔——采样周期。Write DD(15:0)在DIOW-的上升沿被采样,采样周期由MDMA协议规定,但是实际电路运行时会出现“不遵守”规定的现象,毛刺就是一种违规现象。 riple
理论上,采用“先暂存,再写入”的方式是没有问题的。这样处理本质上是流水线方式,只要暂存时间小于采样周期即可保证电路正确运行,即使总线数据在采样时刻之后很快发生变化,电路也不会出错。在本例中采用周期为20ns的时钟对DIOW-进行两级同步,暂存时间为40~60ns,而采样周期是100~120ns,符合上述要求。 riple
但是,如果在某些情况下采样周期发生了变化,缩小到小于暂存时间(40~60ns),那么暂存的数据就会被更新,如果此时总线上的数据已经被下一个采样周期的数据驱动,就会出现“预知”数据的现象。 riple
由于采样周期仅决定于FPGA看到的DIOW-的上升沿,造成采样周期变小的可能原因是DIOW-信号的毛刺。这样看来,该数据采样电路的数据正确性对DIOW-的毛刺是敏感的。 riple
那么,毛刺有没有可能符合上述条件:发生在DIOW-上升沿之后的40~60ns之内,并且恰好同时总线上的数据已经被新数据驱动了呢? riple
我们回到先前对该接口处理的说明上来。由于各个南桥芯片的设计不同,该接口给出的时序图与真实情况有些差异,特点如下: riple
- 图中Write DD(15:0)的“X”区域是有确定值的。在我们调试的主板上,在DIOW-的上升沿之后20ns时Write DD(15:0)就更新为下一个写入周期的数据了,即在下一个写入周期的下降沿之前,新的数据已经出现在总线上了。 riple
- 图中给出的tD与tK的比例有误,实际是3:1的关系。低电平持续时间tD与高电平持续时间tK之和为一个采样周期100~120ns,也就是说,从当前写入周期DIOW-的上升沿到下一个写入周期DIOW-的下降沿只有25~30ns的时间。 riple
根据特点1,只要毛刺出现在DIOW-的上升沿之后20ns到40~60ns的时间范围内,就会确定发生“预知数据”的时序问题;根据特点2,在这一时间间隔内,唯一可能引发DIOW-信号毛刺的事件是发生在DIOW-的上升沿之后25~30ns处的DIOW-信号的下降沿跳变。 riple
上图是该电路的时序仿真波形,在两个时间光标之间的波形就是暂存数据受到DIOW-信号下降沿毛刺影响后改变的情况,该毛刺最终导致数据序列(2)错误模式的发生。 riple
四、时序问题的解决 riple
解决该问题可以从两方面入手: riple
- 缩短暂存时间,使其小于20ns。 暂存数据在DIOW-的上升沿之后20ns到40~60ns的时间范围内是不安全的,缩小甚至消除这一时间间隔可以有效地保护暂存数据。 riple
- 消除DIOW-信号毛刺对数据采样的影响。 riple
在跨时钟域信号处理中,对DIOW-信号进行两级同步处理是可靠和标准的做法,代价是2~3个时钟周期的延时。当同步时钟周期为20ns时,40~60ns的时延是不可避免的。只有当时钟周期小于6.67ns时,同步带来的时延才会小于20ns,才能消除不安全的数据暂存时间。 riple
所以,解决该问题的根本方法是采用150MHz(6.67ns)的时钟进行第一次数据同步,在暂存数据的安全时间内把暂存数据转存到150MHz时钟域内,然后把转存的数据同步到50MHz的时钟域内。 riple
用150MHz的时钟对DIOW-信号进行采样会导致同一时间间隔内获得更多的采样点,增加了采样到DIOW-信号毛刺的概率,采样到的毛刺会被同步电路放大成同步脉冲,该脉冲仍然会导致错误的数据被同步到50MHz时钟域内。 riple
所以,采用150MHz时钟进行第一次采样需要增加滤除毛刺的电路,使采样到的毛刺不能通过该滤波电路,从而消除毛刺的影响。 riple
修改后的电路如下图: riple
时序仿真波形如下图。可以看到,虽然DD_temp被DIOW-下降沿处的毛刺破坏了,但是同步到150MHz和50MHz时钟域的数据没有受到影响;从图中还可以看出毛刺滤除电路的作用,和高频时钟更容易把毛刺放大的现象: riple
五、避免和解决该问题的方法归纳 riple
- 在发生递增数据传输错误时,需要区分是序列(2)还是序列(3)错误类型,序列(2)是具有“预知”数据特点的错误类型,很难得。 riple
- 发生错误的电路是跨时钟域数据捕获的一种处理方法,有一定的实用性,在跨时钟域处理方式上也是规范的,虽然第一层数据暂存对毛刺具有一定的敏感性。 riple
- 修改后的电路采用提高采样时钟频率、缩短数据暂存时间的方式保护了对毛刺敏感的数据,代价是增加了一层数据存储。 riple
- 滤除毛刺的电路的正确性还有待商榷,虽然应用起来很有效,但是有违反跨时钟域处理方式的嫌疑。 riple
- 滤除毛刺的电路主要用来滤除DIOW-信号的下降沿毛刺,对于上升沿毛刺没有滤除效果。上升沿毛刺在该电路中不会引发数据错误。 riple
- 在采用该滤除毛刺的电路时,必须考虑被过滤信号的电平持续长度与同步时钟周期的比例关系。比如该例中,如果采用20ns时钟进行滤波,就会把DIOW-信号25ns的高电平滤除;采用6.67ns时钟,只会滤除长度小于13.3~20ns的高电平信号,DIOW-正常工作的25ns高电平是安全的。 riple
- 在硬盘的IDE接口上,出现这样的毛刺是不应该的,导致该毛刺出现的原因很可能是外部电路设计上的问题。在该问题出现的电路中,从主板的IDE接口到FPGA经过了三种媒质:80线IDE排线、转接用PCB、40线排线。而正常应用中,从主板IDE接口到FPGA只应该经过80线IDE排线一种媒质。 riple
- 采用其他芯片(通过情况复杂的外部电路)传递过来的信号作为时钟,利用其跳变沿作为触发信号是有一定风险的,需要考虑毛刺导致的错误触发造成的影响。 riple