1. 亚稳态原理
- 亚稳态是指触发器无法在某个规定的时间段内到达一个可以确认的状态。
- 在同步系统中,输入总是与时钟同步,因此寄存器的setup time和hold time是满足的,一般情况下是不会发生亚稳态情况的。
- 在异步信号采集中,由于异步信号可以在任意时间点到达目的寄存器,所以无法保证满足目的寄存器Tsu和Th的要求,从而出现亚稳态
2. 异步信号用于边沿检测时出现亚稳态的波形分析
以外部按键key按下时是否出现下降沿为例:
按键未按下时为高电平,按下后为低电平,我们需要通过检测下降沿来判断按键是否按下,但由于亚稳态的存在,异步信号有可能检测不到,因此此处将分情况进行讨论。
2.1 未使用两级同步时正常情况与亚稳态情况
1. 如果外部信号转变发生在建立保持时间之外(非时间上升沿处),则在外部信号变化的下一个时钟沿处,下降沿信号能被正常检测到。
2. 如果外部信号转变发生在建立保持时间之内,出现了亚稳态现象,则在亚稳态结束后最终输入与输出有两种情况,输出不确定的0或1。
2.2 出现亚稳态后的两种情况
1. 对于情况一,如果亚稳态最终稳定在高电平,则可以正常检测到下降沿
2. 对于情况一,如果亚稳态最终稳定在低电平,那么将不能检测到下降沿信号
2.3 使用一级/两级同步后的波形分析
1. 由于亚稳态持续时间小于一个时钟周期,使用一级同步后便可检测到下降沿,比原先的下降沿晚了一个时钟周期。
2. 一般情况下,使用二级同步后可将单bit的亚稳态发生概率降低99%,所以一般会使用二级同步。
3. 按键消抖的代码修改(使用两级同步降低亚稳态的影响)
module key_filter(clk,rstn,key,
// key_p_flag,
// key_r_flag,key_flag,key_state
);input clk;input rstn;input key;
// output reg key_p_flag;
// output reg key_r_flag;output reg key_flag;output reg key_state;//两级同步reg[1:0] sync_key;always@(posedge clk)sync_key <= {sync_key[0], key}; //key为D1,sync <= {Q2,Q1}不看取值,只看位置。//key存于sync[0], sync[0]存于sync[1]//边沿检测reg [1:0] r_key;always@(posedge clk)r_key <= {r_key[0], sync_key[1]}; //r_key <= {Q4,Q3}//此处用了四个寄存器,比两级同步还多一级。//对于边沿检测,只用一个寄存器即可,我们用了两个//加上两级同步的两个寄存器,共四个寄存器。// reg [1:0] r_key;
// always@(posedge clk)begin
// r_key[0] <= key;
// r_key[1] <= r_key[0];
// endwire nedge_key;wire pedge_key;assign nedge_key = (r_key == 2'b10);assign pedge_key = (r_key == 2'b01);reg [1:0]state;reg [19:0] cnt;always@(posedge clk or negedge rstn)if(!rstn)beginstate <= 0;cnt <= 0;
// key_p_flag <= 0;
// key_r_flag <= 0;key_flag <= 0;key_state <= 1;endelsecase(state)0: begin
// key_r_flag <= 0;key_flag <= 0;if(nedge_key == 1) beginstate <= 1;endelsestate <= 0;end 1:beginif((pedge_key == 1) && (cnt < 1000000 - 1))beginstate <= 0;cnt <= 0;endelse if((pedge_key == 0) && (cnt >= 1000000 - 1))beginstate <= 2;
// key_p_flag <= 1'd1;key_flag <= 1'd1;key_state <= 0;cnt <= 0;endelsecnt <= cnt + 1'd1;end2:begin
// key_p_flag <= 0;key_flag <= 0;if(pedge_key == 1)state <= 3;elsestate <= 2;end3:beginif((nedge_key == 1) && (cnt < 1000000 - 1))beginstate <= 2;cnt <= 0;endelse if((nedge_key == 0) && (cnt >= 1000000 - 1))beginstate <= 0;
// key_r_flag <= 1;key_flag <= 1'd1;key_state <= 1;cnt <= 0;endelsecnt <= cnt + 1'd1;endendcaseendmodule