最近研究了下,慢信号同步到快速时钟域的办法,也就是使用同步器。下面详细分析下。
1. 最开始我是采用下面的电路,当a信号变为高时,q1在快速时钟域的上升沿采集到a的值,此时q1为1,q2是采集上次的q1的值,上次q1的值为初始化0,所以当前时钟,q2还是为0。此时通过下面的组合逻辑电路,就会输出为1.当下一个快速时钟域的时钟上升沿到来时,q2的值变成了采样到的a的值,为1.此时通过组合电路的输出变为0.这样就把a的采样搬移到了快时钟域上,且数据宽度为1个时钟周期。
通过仿真,我们可以看到在第一次采样到a的高电平时,out就已经开始输出了,且输出为一个时钟周期高电平。且已经被同步到快速时钟域。
查看综合出来的电路,发现产生了2个D触发器。
always@(posedge clk or negedge rest_n)
begin
if(!rest_n)
begin
q1<=0;
q2<=0;
end
else
begin
q1<=a;
q2<=q1;
end
end
assign out = q1&(~q2);
2. 但是在网上查了下,发现大家在建立同步器电路时,打的节拍不一样。有的打了2个节拍,那下面我们就要弄清楚,打节拍和同步电路到底有什么关系?到底该打几拍?下面先以打两拍为例进行仿真,然后从仿真上发现和上面方案的差异。
下面的数据经过了2个触发器同步,当第一个时钟上升沿来时,数据被q1更新,当第2个时钟上升沿来时,a数据被传输到q2输出,此时out立刻开始输出。通过仿真可以看出来,当a数据变化后,经过了1个时钟周期后,out才开始变化。而上面的方案在第一个时钟沿来时就开始输出。
always@(posedge clk or negedge rest_n)
begin
if(!rest_n)
begin
q1<=0;
q2<=0;
q3<=0;
end
else
begin
q1<=a;
q2<=q1;
q3<=q2;
end
end
assign out = q2&(~q3);
3.我们继续增加寄存器级数。查看仿真有何不同。发现经过2个时钟周期后,out才开始变化。
always@(posedge clk or negedge rest_n)
begin
if(!rest_n)
begin
q1<=0;
q2<=0;
q3<=0;
q4<=0;
end
else
begin
q1<=a;
q2<=q1;
q3<=q2;
q4<=q3;
end
end
assign out = q3&(~q4);
总结:通过以上仿真发现,由于我们的组合电路out = q3&(~q4);q4是最后一个寄存器,q3是倒数第二个寄存器,所以,在q3前面有几级寄存器,采集到的a数据就要经过几个时钟周期才可以到达q3的D,也就导致out输出的数据变化要慢几个时钟周期。
上面的方案1,只有2级D触发器,他的延时最少,但是它有一个问题,就是在复位按键松开的时候,如果松开复位按键的时候,a刚好为1,则q1的D为1,此时松开复位按键,q1会有不稳态出现,导致后面的组合逻辑的输出出现异常结果。
上面的方案2,按下复位按键时,q1和q2、q3的输出都为0,当松开复位按键时,q2的D和Q,q3的D和Q都是0,此时就算有不稳态,导致把D的值错误锁存,但是由于此刻的D和Q都为0,就算锁存错误,则结果还是为0,并不会输出1.所以方案2结合了异步复位同步释放的功能,很好的过滤了不稳态。
上面的方案3,则就有点不必要了,只增加了时钟的浪费。
所以综上所述,同步电路选择方案2更合理。通过从电路安全和响应速度两个方面综合考虑,采用3个触发器更加合理。