FPGA异步时钟设计中的同步策略1 引言基于FPGA的数字系统设计中大都推荐采用同步时序的设计,也就是单时钟系统。
但是实际的工程中,纯粹单时钟系统设计的情况很少,特别是设计模块与外围芯片的通信中,跨时钟域的情况经常不可避免。
如果对跨时钟域带来的亚稳态、采样丢失、潜在逻辑错误等等一系列问题处理不当,将导致系统无法运行。
本文总结出了几种同步策略来解决跨时钟域问题。
2 异步设计中的亚稳态触发器是FPGA设计中最常用的基本器件。
触发器工作过程中存在数据的建立(setup)和保持(hold)时间。
对于使用上升沿触发的触发器来说,建立时间就是在时钟上升沿到来之前,触发器数据端数据保持稳定的最小时间。
而保持时间是时钟上升沿到来之后,触发器数据端数据还应该继续保持稳定的最小时间。
我们把这段时间成为setup-hold时间(如图1所示)。
在这个时间参数内,输入信号在时钟的上升沿是不允许发生变化的。
如果输入信号在这段时间内发生了变化,输出结果将是不可知的,即亚稳态(Metastability)。
一个信号在过渡到另一个时钟域时,如果仅仅用一个触发器将其锁存,那么采样的结果将可能是亚稳态。
这也就是信号在跨时钟域时应该注意的问题。
如图2所示。
信号dat经过一个锁存器的输出数据为a_dat。
用时钟b_clk进行采样的时候,如果a_dat正好在b_clk的setup-hold时间内发生变化,此时b_ dat就既不是逻辑"1",也不是逻辑"0",而是处于中间状态。
经过一段时间之后,有可能回升到高电平,也有可能降低到低电平。
输出信号处于中间状态到恢复为逻辑"1"或逻辑"0"的这段时间,我们称之为亚稳态时间。
触发器进入亚稳态的时间可以用参数MTBF(Mean Time Between Failures)来描述,MTBF即触发器采样失败的时间间隔,表示为:其中fclock表示系统时钟频率,fdata代表异步输入信号的频率,tmet代表不会引起故障的最长亚稳态时间,C1和C2分别为与器件特性相关的常数。
如果MTBF很大,就认为这个设计在实际工作中是能够正常运行的,不会因为亚稳态导致整个系统的失效。
当触发器处于亚稳态,且处于亚稳态的时间超过了一个时钟周期,这种不确定的状态还会影响到下一级的触发器,最终导致连锁反应,从而使整个系统功能失常。
3 同步策略在异步设计中,完全避免亚稳态是不可能的。
因此,设计的基本思路应该是:首先尽可能减少出现亚稳态的可能性,其次是尽可能减少出现亚稳态并给系统带来危害的可能性。
以下是根据实际工作总结出来的几种同步策略。
3.1 双锁存器法为了避免进入亚稳态,应当使参数MTBF尽可能大。
通常采用的方法是双锁存器法,即在一个信号进入另一个时钟域之前,将该信号用两个锁存器连续锁存两次(如图3所示)。
理论研究表明这种设计可以将出现亚稳态的几率降低到一个很小的程度,但这种方法同时带来了对输入信号的一级延时,需要在设计时钟的时候加以注意。
对于上面的双锁存器法,如果a_clk的频率比b_clk的频率高,将可能出现因为dat 变化太快,而使b_clk无法采样的问题。
即在信号从快时钟域向慢时钟域过渡的时候,如果信号变化太快,慢时钟将可能无法对该信号进行正确的采样,所以在使用双锁存器法的时候,应该使原始信号保持足够长的时间,以便另一个时钟域的锁存器可以正确地对其进行采样。
3.2 结绳法由于双锁存器法在快时钟域向慢时钟域过渡中可能存在采样失效的问题,我们引入了一种安全的跨时钟域的方法:结绳法。
结绳法适合任何时钟域的过渡(clk1,clk2的频率和相位关系可以任意选定),如图4所示。
图4中的_clk1表示该信号属于clk1时钟域,_clk2的信号表示该信号属于clk2时钟域。
在两次src_req_clk1之间被src_vld_clk1结绳(Pluse2Toggle)。
将src_vld-clk1用双锁存器同步以后,该信号转换为dst_req_clk2(Toggle2Pluse)。
同理,用dst_vld_clk2将dat_req_clk2结绳,dst_vld_clk2表明在clk2时钟域中,src_dat_clk1已经可以进行正确的采样了。
最后将dst_vld_clk2转换为dst_ack_clk1(Synchronizer and Toggle2Pluse)。
dst_ack_clk表明src_dat_clk1已经被clk2正确采样了,此后clk1时钟域就可以安全地传输下一个数据了。
可以看出,结绳法的关键是将信号结绳以后,使其保持足够长的时间,以便另一个时钟可以正确采样。
图5描述了结绳法的具体实现,主要包括3个基本单元:Pluse2Toggle、Synchronizer和Toggle2Pluse。
Pluse2Toggle模块负责将两个脉冲信号结绳,即将单脉冲信号延长;Synchronizer 模块用双锁存器法将得到的信号过渡到另一个时钟域;Toggle2Pluse模块与Pluse2Toggle功能相对,即将延长的脉冲信号还原为单脉冲,这里用到了异或门。
整体的设计思想就是用Pluse2Toggle将信号延长,用Synchronizer过渡,再用Toggle2Pluse 还原,以保证另一个时钟域可以正确采样,而接收方用相反的流程送回响应信号。
结绳法可以解决快时钟域向慢时钟域过渡的问题,且适用的范围很广。
但是结绳法实现较复杂,在设计要求较高的场合应该慎用。
4 结束语本文主要把FPGA异步时钟设计中产生的问题,原因以及解决问题所采用的同步策略做了详细的分析。
其中双锁存器法比较适用于只有少数信号跨时钟域;结绳法比较适用快时钟域向慢时钟过渡的情况。
所以,在实际的应用中,应根据自身设计的特点选择适当的同步策略。
基于FPGA的时序及同步设计数字电路中,时钟是整个电路最重要、最特殊的信号。
第一, 系统内大部分器件的动作都是在时钟的跳变沿上进行, 这就要求时钟信号时延差要非常小, 否则就可能造成时序逻辑状态出错.第二, 时钟信号通常是系统中频率最高的信号.第三, 时钟信号通常是负载最重的信号, 所以要合理分配负载。
出于这样的考虑在FPGA这类可编程器件内部一般都设有数量不等的专门用于系统时钟驱动的全局时钟网络。
这类网络的特点是:一、负载能力特别强, 任何一个全局时钟驱动线都可以驱动芯片内部的触发器; 二是时延差特别小; 三是时钟信号波形畸变小, 工作可靠性好。
因此, 在FPGA设计中最好的时钟方案是: 由专用的全局时钟输入引脚驱动单个主时钟去控制设计项目中的每一个触发器。
CPLD/FPGA都具有专门的全局时钟引脚,它直接连到器件中的每一个寄存器。
这种全局时钟提供器件中最短的时钟到输出的延时。
同步设计时, 全局时钟输入一般都接在器件的时钟端, 否则会使其性能受到影响。
对于需要多时钟的时序电路, 最好选用一个频率是它们的时钟频率公倍数的高频主时钟。
各个功能模块要使用统一的复位电路。
在使用带时钟的触发器、计数器等有复位端的库器件时, 一般应尽量使用有同步复位的器件。
注意复位时保证各个器件都能复位, 以避免某些寄存器的初始状态不确定而引起系统工作不可靠。
时钟设计过程中,不可缺少的要涉及到数据的建立时间和保持时间的概念,深刻理解这两个概念有助于我们设计出优良饿时钟网络。
异步信号输入总是无法满足数据的建立保持时间,所以建议大家把所有异步输入都先经过双触发器进行同步化。
在许多应用中只将异步信号同步化还是不够的,当系统中有两个或两个以上非同源时钟的时候,数据的建立和保持时间很难得到保证,我们将面临复杂的时间问题,那么这个时候怎么办呢?最好的方法是将所有非同源时钟同步化,那么又怎么样将非同源时钟同步化呢?我们可以使用带使能端的D触发器,并引入一个高频时钟(频率高于系统中的所有源时钟),便可以达到使系统中所有源时钟同步的效果。
如下面的这个例子:系统有两个不同源时钟,一个为3MHz,一个为5MHz,不同的触发器使用不同的时钟。
为了系统稳定,假设我们引入一个20MHz时钟,那么这个20MHz的时钟怎么才能将3M和5M时钟同步化呢?20M的高频时钟将作为系统时钟,输入到所有触发器的的时钟端。
3M_EN 和5M_EN将控制所有触发器的使能端。
即原来接3M时钟的触发器,接20M时钟,同时3M_EN 将控制该触发器使能,原接5M时钟的触发器,也接20M时钟,同时5M_EN 将控制该触发器使能。
这样我们就可以将任何非同源时钟同步化。
在通常的FPGA设计中对时钟偏差的控制主要有以下几种方法:1、控制时钟信号尽量走可编程器件的的全局时钟网络。
在可编程器件中一般都有专门的时钟驱动器及全局时钟网络,不同种类、型号的可编程器件,它们中的全局时钟网络数量不同,因此要根据不同的设计需要选择含有合适数量全局时钟网络的可编程器件。
一般来说,走全局时钟网络的时钟信号到各使能端的延时小,时钟偏差很小,基本可以忽略不计。
2、若设计中时钟信号数量很多,无法让所有的信号都走全局时钟网络,那么可以通过在设计中加约束的方法,控制不能走全局时钟网络的时钟信号的时钟偏差。
3、异步接口时序裕度要足够大,局部同步电路之间接口都可以看成是异步接口,比较典型的是设计中的高低频电路接口、I/O接口,那么接口电路中后一级触发器的建立-保持时间要满足要求,时序裕度要足够大。
4、在系统时钟大于30MHz时,设计难度有所加大,建议采用流水线等设计方法。
5、要保证电路设计的理论最高工作频率大于电路的实际工作频率。
复位和置位信号处理:在设计时应尽量保证有一全局复位信号,或保证触发器、计数器在使用前已经正确清零状态。
在设计寄存器的清除和置位信号时,应尽量直接从器件的专用引脚驱动。
另外,要考虑到有些器件上电时,触发器处于一种不确定的状态,系统设计时应加入全局复位/Reset。
这样主复位引脚就可以给设计中的每一个触发器馈送清除或置位信号,保证系统处于一个确定的初始状态。
需要注意的一点是:不要对寄存器的置位和清除端同时施加不同信号产生的控制,因为如果出现两个信号同时有效的意外情况,会使寄存器进入不定状态。