一.什么是亚稳态?
百度百科给出的解释:
亚稳态是指触发器无法在某个规定时间段内达到一个可确认的状态。当触发器进入亚稳态时,对于该单元的输出无法预测,且无用的输出电平会沿着信号通道在各级触发器级联式传播
只要系统中有异步元件,亚稳态就是无法避免的,亚稳态通常发生在异步信号传输,跨时钟域信号传输以及复位信号电路(异步复位信号,)等设计中。产生亚稳态后,触发器的输出端Q在稳定下来之前可能是毛刺、振荡、固定的某一电压值,所以降低亚稳态发生的概率成为了FPGA设计中需要重视的一个注意事项。
二、从理论分析上解释什么是亚稳态
触发器的建立时间Tsu和保持时间Th在时钟上升沿左右定义了一个时间窗口,如果触发器数据输入端口上的数据在这个时间窗口内发生变化(或者数据更新),而不是保持稳定,那么就会产生时序违规。存在这个时序违规是因为违反了建立时间要求和保持时间要求,此时触发器内部的一个节点(一个内部节点或者要输出到外部节点)可能会在一个电压范围内浮动,无法稳定在逻辑0或者逻辑1状态。
换句话说,如果数据在上述窗口中被采集,触发器中的晶体管不能可靠地设置为逻辑0或者逻辑1对应的电平上。所以此时的晶体管并未处于饱和区对应的高或者低电平,而是在稳定到一个确定电平之前,徘徊在一个中间电平状态(这个中间电平或许是一个正确值,又或许不是)。如图所示,这就是所谓的亚稳态。其中Tmet称为决断时间的振荡时间段,如果当Tmet的时间长到大于一个时钟周期后,那么第二级寄存器就会采集到亚稳态,当振荡结束回到稳定状态时,稳定的值是随机的。
三、 复位电路中的亚稳态
异步复位电路的复位信号要满足恢复时间和去除时间,也就是说异步信号在时钟上升沿前的变化要空留异步信号一定的恢复时间,在时钟上升沿后变化要空留出时钟信号解除有效的时间,从而接受复位信号的有效。
同步复位电路也会产生亚稳态,只是几率小于异步复位电路
四、 亚稳态发生的概率
概率 = (建立时间+保持时间)/时钟周期
随着clk频率的增加,亚稳态发生的几率是增加的。为系统采用100M时钟对一个外部信号进行采集,采集时钟周期为10ns,那采集产生亚稳态的概率为:1ns/10ns = 10%;同理采用300M时钟对一个外部信号进行采集,那产生亚稳态的概率为:1ns/3.3ns = 30%。
五、亚稳态的消除
有亚稳态产生,我们就要对亚稳态进行消除,常用对亚稳态消除有三种方式:
(1) 对异步信号进行同步处理;
(2) 采用FIFO对跨时钟域数据通信进行缓冲设计;
(3) 对复位电路采用异步复位、同步释放方式处理。
5.1 对异步信号进行同步处理
将异步信号通过打拍的方式,也就是在以输入的时钟域的信号边沿信号为有效信号,对异步信号进行采集同步,又分为单比特数据和多比特数据 。
5.1.1.单比特数据/单一信号
通常对于单比特数据使用紧密相连的触发器进行同步,也称作打拍,通常是边沿同步器完成
慢时钟到快时钟。实现代码如下(三拍)其中clk_b是慢时钟,clk_a是快时钟,pulse_b从慢时钟跨到快时钟。
module tclk(
input clk_a,
input rst_n,
input pulse_b,
output pulse_a
);
reg pulse_r1;
reg pulse_r2;
reg pulse_r3;
wire pulse_a_pose;//上升沿
wire pulse_a_nege;//下降沿
always@(posedge clk_a or negedge rst_n)
begin
if(!rst_n)
begin
pulse_r1<=1'b0;
pulse_r2<=1'b0;
pulse_r3<=1'b0;
end
else
begin
pulse_r1<=pulse_b;
pulse_r2<=pulse_r1;
pulse_r3<=pulse_r2;
end
end
assign pulse_a_pose = pulse_r2&( ~pulse_r3);//pulse_b上升沿检测,是指上升沿保持一个clk_a周期
assign pulse_a_nege =(~pulse_r2)& pulse_r3;//pulse_b下降沿检测
assign pulse_a = pulse_r2;
endmodule
————————————————
版权声明:本文为CSDN博主「神奇艾尔斯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37864715/article/details/106837083
上面的同步器在慢时钟域信号同步入快时钟域时工作的很好,但是反过来的话,可能就工作不正常了。举一个很简单的例子,其中clk_b是要进入的慢时钟,clk_a是快时钟,快时钟下的pluse_a信号脉冲很窄,则位于慢时钟的两个相邻跳变沿之间,会导致信号丢失或者容易出现亚稳态。这时就需要将pluse_a进行拓宽。 可以看到其中中间信号是两个,一个在signal_a是在快时钟下的拓宽信号,signal_b是在慢时钟下的扩宽信号,将signal_b进行打拍,得到扩宽输出的有效点平信号和电压信号,当clk_a时钟检测到signal_b打拍后呈现有效信号,则将表明反馈信号有效,置signal_a为0,原博主的好像有问题,我修改了一下,如果有错误,希望指出。
module tclk(
input clk_a, //快
input clk_b, //慢
input rst_n,
input pulse_a,
output pulse_b_out,
output lev_b_out
);
reg signal_a;
reg signal_b;
reg signal_b_a1;
reg signal_b_a2;
reg pulse_r1;
reg pulse_r2;
always@(posedge clk_a or negedge rst_n)
begin
if(!rst_n)
signal_a <= 1'b0;
else if(pulse_a)
signal_a <= 1'b1;///检测到快时钟域的信号,产生一个展宽标志
else if(signal_b_a2)
signal_a <= 1'b0; //原博主是1,我觉得是0才能达到反馈电路的作用
end
//将脉冲信号作用到clkb
always@(posedge clk_b or negedge rst_n)
begin
if(!rst_n)
signal_b<= 1'b0;
else
signal_b<=signal_a;
end
//signal_b打两拍
always@(posedge clk_b or negedge rst_n)
begin
if(!rst_n)
begin
pulse_r1<= 1'b0;
pulse_r2<=pulse_r1;
end
else
begin
pulse_r1<= signal_b;
pulse_r2<=pulse_r1;
end
end
//产生反馈拉低signal_a的信号signal_b1_a2用来反馈回clka时钟域,清除clka下的脉冲展宽信号。这里不能直接使用signal_b_b1,因为signal_b_b1是clkb时钟域下的信号,所以要把它同步回clka时钟域后再使用。
always @ (posedge clk_a or negedge rst_n)
begin
if (rst_n == 1'b0) begin
signal_b_a1 <= 1'b0 ;
signal_b_a2 <= 1'b0 ;
end
else begin
signal_b_a1 <= signal_b ;
signal_b_a2 <= signal_b_a1 ;
end
end
//输出电平信号与脉冲信号
assign pulse_b_out=pulse_r1&(~pulse_r2);
assign lev_b_out=pulse_r1;
/// _r1是打过两拍的,基本可用。_b2是打过三拍的,当然更加保险。 这样写的意思是说:如果你的设计不需要用到同步过去的_puls信号,而且认为打两拍已经足够,_r2这个寄存器就可以节省掉不需要了。
endmodule
————————————————
版权声明:本文为CSDN博主「神奇艾尔斯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37864715/article/details/106837083
5.1.2 多位宽数据同步
当多位宽数据进行同步时,如果该数据各 bit 位都可以看作电平信号,即相对一段时间内各 bit 位数据均可以保持不变以至于能被慢时钟采集到,可以消耗一些触发器资源对多位宽数据进行简单的延迟打拍同步。但如果数据变化速率过快,就不能再使用延迟打拍采样的方法。因为此时数据各 bit 位不再是电平信号,变化的时间也参差不齐,用异步时钟进行打拍采样,可能会采集到因路径延迟不同而导致的错误数据。解决此类异步问题的常用方法是采用异步 FIFO (First In First Out)。
5.2 采用FIFO对跨时钟域数据通信进行缓冲设计
我的博客实现了异步FIFO,链接如下https://blog.csdn.net/qq_41624212/article/details/124257150