同一个时钟域是根据同一个时钟原点
一个锁相环PLL产生多个时钟,相位倍数都是可控的,他们之间为同步时钟
不同锁相环PLL产生的时钟,即使频率相同,也是异步时钟,他们之间的相位关系是不可控的
双锁存器同步法
一个信号进入另一个时钟域之前,将该信号用两个触发器所存两次,最后得到的结果就可以避免亚稳态问题。(降低亚稳态出现的概率)
优点:结构简单,易于实现,面积占用很小
缺点:增加了两级触发器延迟。
快时钟域转到慢时钟域时,易造成慢时钟域采样丢失(还未来得及采样,数据就变化了)
适用条件:
常用于慢时钟域到快时钟域
CLK_slow 的周期 > clk_fast 的周期+ 路径延迟 确保可被CLK_fast采样到
data数据变化时间间隔 > CLK_slow 的周期 + 2*clk_fast 的周期 + 路径延时 确保所有变化都被采样到
边沿检测同步电路
慢时钟到快时钟的单bit信号的跨时钟域信号处理,主要采用边沿检测同步电路。可以检测输入信号的上升沿,也可以检测下降沿。
慢时钟下一个有效时间等于慢时钟域的一个时钟周期,在快时钟域的角度下,这一个时钟周期可能在快时钟域下持续几个时钟周期。但实际上,这个脉冲在慢时钟域上只持续一个周期。因此,用快时钟域去检查有限脉冲的翻转边沿是最准确的。
边沿检测同步器的功能是将慢时钟域下一个时钟周期宽的脉冲,搬移并缩小为快时钟域下的一个时钟脉冲。
适用条件:输入数据的宽度必须比一个接受时钟周期加上一个同步触发器的hold时间要长,更安全的就是两个同步周期宽度。(保证慢时钟域的脉冲足够保持到快时钟的同步器拿到)
脉冲同步器
对于快时钟域到慢时钟域,通常采用脉冲同步器进行同步。
module sync_pulse(
input in_rst_n,
input in_clk,
input in_pulse,
output out_rst_n,
output out_clk,
output out_pulse
);
reg R_in_change;
always @ (posedge in_clk or negedge in_rst_n)
if(!in_rst_n)
R_in_change <= 0;
else if(in_pulse)
R_in_change <= ~R_in_change;
reg [2:0] R_out_change;
always @ (posedge out_clk or negedege out_rst_n)
if(!out_rst_n)
R_out_change <= 3'b000;
else
R_out_change <= {R_out_change[1:0],R_in_change};
assign out_pulse = R_out_change[1] ^ R_out_change[2];
endmodule
基本功能: 从某个时钟域取出一个单时钟宽度脉冲,然后在新的时钟域下建立另一个单时钟宽度的脉冲。
快时钟域比慢时钟域频率高,因此慢时钟域去接去采样快时钟域下的脉冲,很有可能采不到。因此通过反转电路将快时钟域前后间隔多个时钟周期的两个有效脉冲进行标定,形成toggle波形。通过同步信号到慢时钟域下,最后通过异或逻辑门得到慢时钟域下两个有效的单周期脉冲信号。
限制:
输入脉冲之间的最小间隔必须等于两个同步器时钟周期
如果输入脉冲相互过近,则新时钟域下的时钟脉冲也紧密相连,结果是输出脉冲宽度比同一个时钟周期宽
当输入脉冲时钟周期大于两个同步器时钟,这个问题更加严重
结绳法
信号从快时钟域到慢时钟域过度时,慢时钟域可能无法对变化太快的信号进行正确采样。
上述同步器对两个时钟之间的关系要求严格
原理:将快时钟域信号的脉冲周期延长,等到慢时钟域采样后在解绳,还原为原来的时钟脉冲宽度
利用数据的边沿作为时钟(图为上升沿)脉冲可以无限延长,直到可以采集到数据,然后复位
数据作为输入信号,当数据上升沿时(0->1) ,寄存器的输入1将稳定在高电平等待CLKB采样。当CLKB采样完成后 寄存器4会输出高电平,若此时输入DIN_clkA为低电平那么即可完成复位开始下一次采样。
需要注意:如果DIN_CLKA变化较快,持续时间短语三个clkb,即din_cllka频率大于3个clkb,那么变化将无法采到
在慢时钟采样快时钟的时候,适合采样数据比较少的控制信号。Ta > 3Tb
结绳反馈
多bit信号的跨时钟域处理
多bit指示信号
多个控制信号跨时钟域仅仅通过简单的同步器同步是不安全的
如果两个信号有小的偏斜(Skew)将导致在不同的周期下起作用
解决方法,将两个信号在原时钟域下合成一个信号;如果遇到不能合并的信号,加入零一个控制信号,确保稳定后进行采样
多bit数据流跨时钟域处理
与指示信号不同:
数据流大多具有连续性,即背靠背传输
数据流要求具有较快的传输速度
解决方法:SRAM FIFO
FIFO 与普通存储器区别:没有外部读写地址(使用简单)
缺点:只能顺序写入数据,顺序读出数据
用途:异步FIFO读写分别采用不同的时钟
对于不同宽度的数据接口也可用FIFO
常见参数:
FIFO宽度:FIFO一次读写的数据位
FIFO深度:FIFO一次可以存储多少N位的数据(宽度为N)
当读写指针相等时,表示FIFO为空
当读写地址再次相等时,表示FIFO满
区分空满状态:在地址中加一个额外的位当读写指针增加并越过最后一个FIFO地址时就额外位加1,其他位回0,相等时判断额外位,若不同说明写指针多折回一次
前提:读指针被传递到写时钟域,写指针被传递到读时钟域
传输读写指针之前需要将指针转换成格雷码,格雷码能有限降低亚稳态出现概率
格雷码判断空满标志
需满足以下三点:
读写指针最高位MSB不相等
读写指针次高位不相等
读写指针其余位相等
FIFO深度设置
假设FIFO的写时钟为100MHZ,读时钟为80MHZ。在FIFO输入侧,每100个写时钟,写入80个数据;读数据侧,每个时钟读走一个数据。
请问如何设置FIFO深度可以保证不溢出
重载满足
假设写入时为最差情况,即背靠背。即在160*(1/100)微纳秒内写入160个数据。一下为写入160burst数据的时间及算法方法:
burst_cycle * twclk = burst_cycle / fwclk = 160/100
在这个时间内能读出数据的个数:
160/100 *80 个数据
深度 depth = burst - data_numread = 160 - 160/100*80 =32
当深度为2的n次幂,格雷码可较好的满足需求
若非2的n次幂,格雷码则不适用,可
若深度为偶数,按照格雷码编码,并再此基础上进行修改
若为奇数,可自行设计逻辑,或者查找表,以实现指针只跳变一次
若无特别需求,可选2的n次幂,牺牲空间减少设计复杂度。