锁存器出现亚稳态
(1)在其中一个输入端输入的脉冲太短。
(2)两个端口输入同时有效,或两输入有效相差足够短。
(3)在使能输入的边缘处,输入信号不稳定。
触发器出现亚稳态
(1)建立/保持时间内输入信号不稳定。
(2)时钟脉冲太窄。
(3)异步信号对时钟有效沿是随机的,易产生亚稳态。异步信号包括:不被时钟控制的信号;或被不同时钟域的时钟同步的信号。
触发器进入亚稳态的时间可以用参数MTBF(Mean Time Between Failures)来描述,MTBF即触发器采样失败的时间间隔,表示为:
其中fclock表示系统时钟频率,fdata代表异步输入信号的频率,tmet代表不会引起故障的最长亚稳态时间,C1和C2分别为与器件特性相关的常数。如果MTBF很大,就认为这个设计在实际工作中是能够正常运行的,不会因为亚稳态导致整个系统的失效。
亚稳态的处理方法
(1)亚稳态不能避免。
(2)尽可能降低亚稳态的影响。
(3)高速数字电路依赖于同步器产生的从亚稳态事件中恢复的缓冲时间。
常见的同步电路解决方案
(1)两级DFF(传单信号)
(2)FIFO(传有一定位宽的信号bus)
(3)握手信号(对于FIFO的深度要求比较大,需要引入握手信号)
总结一下
1、有关系的时钟之间传单bit数据,理论上只需要源数据保持足够长的时间(clk2的两个周期)即可;
2、无关系的时钟之间传单bit数据,必须要使用同步器;
3、不管有无关系的时钟进行单bit传输,脉冲同步器都可以解决这个问题;
4、多bit传输只能使用握手机制或者异步fifo;
5、低频采高频,为防止数据不丢失,应当让源数据变慢,多保持一些周期;高频采低频则不需要,但是高频采低频得到的结果可能带有很多冗余。
下面主要讲应用于传输的异步信号是单信号时常用的两级DFF方案。
跨时钟域传输信号主要引起的问题就是亚稳态。处理跨时钟域的数据有单bit和多bit之分,而打两拍的方式常见于处理单bit数据的跨时钟域问题。打两拍本质就是定义两级寄存器对数据进行延拍。流程如下图所示:
两级寄存器的原理:两级寄存是一级寄存的平方,两级并不能完全消除亚稳态危害,但是提高了可靠性减少其发生概率。总的来讲,就是一级概率很大,三级改善不大。
信号同步的要求:
为了使同步工作能正常进行,从某个时钟域传来的信号应先通过原时钟域上的一个触发器,然后不经过两个时钟域间的任何组合逻辑直接进入同步器的第一个触发器中。这一要求非常重要,因为同步器的第一级触发器对组合逻辑所产生的毛刺非常敏感。如果一个足够长的毛刺正好满足建立-保持时间的要求则同步器的第一级触发器会将其放行,给新时钟域的后续逻辑送出一个虚假的信号。
同步器的类型取决于异步输入信号的脉
冲宽度是大于时钟周期还是小于时钟周期。
低速时钟域 —> 高速时钟域;
高速时钟域 —> 低速时钟域;
在电平同步器中,跨时钟域的信号在新时钟域中要保持高电平或低电平两个时钟周期以上。同步之后的信号是电平的形式,而该电平所维持的时钟周期个数是其在跨时钟域期间被上升沿检测到的次数。这种同步器是所有同步器电路的核心。
原理图
时序图
代码
module sync(
input async_in, bclk, rst,
output sync_out
);
reg bdat1, bdat2;
always @(posedge bclk or posedge rst) begin
if (rst) begin
bdat1 <= 1'b0;
bdat2 <= 1'b0;
end
else begin
bdat1 <= async_in;
bdat2 <= bdat1;
end
end
assign sync_out = bdat2;
endmodule
module sync(
input async_in, bclk, rst,
output sync_out
);
reg bdat1, bdat2, bdat3;
always @(posedge bclk or posedge rst) begin
if (rst) begin
bdat1 <= 1'b0;
bdat2 <= 1'b0;
bdat3 <= 1'b0;
end
else begin
bdat1 <= async_in;
bdat2 <= bdat1;
bdat3 <= bdat2;
end
end
assign sync_out = bdat2&~bdat3; //rising edge
endmodule
原理图
不产生亚稳态时的时序图
会产生亚稳态时的时序图
代码
module sync_h2lck(
input async_in, bclk, rst,
output sync_out
);
reg q1, q2, q3;
wire async_rst;
assign async_rst = !async_in && sync_out;
always @(posedge async_in or posedge async_rst) begin
if (async_rst) begin
q1 <= 1'b0;
end
else begin
q1 <= 1'b1;
end
end
always @(posedge bclk or posedge rst) begin
if (rst) begin
q2 <= 1'b0;
q3 <= 1'b0;
end
else begin
q2 <= q1;
q3 <= q2;
end
end
assign sync_out = q3;
endmodule