//学习笔记//
检测输入信号或FPGA内部逻辑信号的跳变,即上升沿或者下降沿的检测。
设置两个寄存器,对前一状态和后一状态进行寄存,若前后两个状态不同,则检测到了边沿。对于上升沿和下降沿的确定可以用组合逻辑比较来确定。若前一状态D[1]为高电平,后一状态D[0]为低电平,则为下降沿,反之为上升沿。
用Verilog实现的1bit信号边沿检测功能,输出一个周期宽度的脉冲信号。
module test(
input clk,
input rst_n,
input data,
output pos_edge, //上升沿
output neg_edge, //下降沿
output data_edge, //数据边沿
output reg [1:0] D
);
//设置两个寄存器,实现前后电平状态的寄存
//相当于对dat_i 打两拍
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
D <= 2'b00;
end
else begin
D <= {D[0], data}; //D[1]表示前一状态,D[0]表示后一状态(新数据)
end
end
//组合逻辑进行边沿检测
assign pos_edge = ~D[1] & D[0];
assign neg_edge = D[1] & ~D[0];
assign data_edge = pos_edge | neg_edge;
endmodule
tb仿真文件:
`timescale 1ns/1ns
module test_tb;
reg clk;
reg rst_n;
reg data;
wire pos_edge;
wire neg_edge;
wire data_edge;
wire [1:0] D;
test u1(
.clk(clk),
.rst_n(rst_n),
.data(data),
.pos_edge(pos_edge),
.neg_edge(neg_edge),
.data_edge(data_edge),
.D(D)
);
//产生时钟激励
initial clk = 1;
always #10 clk = ~clk;
//输入激励
initial begin
rst_n=0;
data=0;
#100;
rst_n = 1;
#50
data=1;
#201;
data=0;
#201;
data=1;
#101;
data=0;
#200;
$stop;
end
endmodule
波形图:
通过波形图进行分析,可看到data数据中有上升下降沿的变化,因此我们可对其进行检测。
上升沿检测:
看红色方框部分,当检测到上升沿的时候,pos_edge出现一个clk的高脉冲,同时边沿信号也出现一个clk高脉冲。
下升沿检测:
看蓝色方框部分,当检测到下降沿的时候,neg_edge出现一个clk的高脉冲,同时边沿信号也出现一个clk高脉冲。
首先以时钟的上升沿作为参考,然后进行时序分析。
信号打拍:
要边沿信号检测,那么我们需要知道信号前后时刻的电平状态才能进行判断。因此采用两个寄存器来对状态进行存储。
首先会将data进行打拍,先打一拍进行本地同步,在再打一拍用于逻辑运算生成脉冲。打2拍处理后,于是有reg [1:0] D
其中D[0]表示后一状态,D[1]表示前一状态
其中上升沿、下降沿、边沿如下:
红色部分为上升沿
蓝色部分为下降沿
绿色为边沿。
当检测上升沿时,看第一个黑色方块,此时D[0]高电平,D[1]低电平,因此 得到上升沿:assign pos_edge = ~D[1] & D[0];
当检测下降沿时,看第二个黑色方块,此时D[0]低电平,D[1]高电平,因此 得到下降沿: assign neg_edge = D[1] & ~D[0];
数据边沿检测:
上升下降沿进行或运算
assign data_edge = pos_edge | neg_edge;
综上分析可以发现这种方法存在一个潜在风险:当待测信号data是一个异步信号时,输出可能是亚稳态,如果data信号的变化刚好发生在clk时钟的建立时间和保持时间之内,那么第一级寄存器的输出 data[0] 就会进入亚稳态,而data[0] 的亚稳态会立即传递给pos_edge和neg_edge信号,从而使得整个电路的输出进入亚稳态,影响下一级电路的正常工作,甚至导致整个系统崩溃!因此异步信号边沿提取时,应先将异步信号同步化,一般采用多加一级寄存器的方法来解决亚稳态。
亚稳态:指触发器输出无法再某一个规定时间段内达到一个确定的状态(0或1)。
建立时间(setup time)是指在触发器的时钟信号上升沿到来以前,数据稳定不变的时间,如果建立时间不够,数据将不能在这个时钟上升沿被打入触发器;
保持时间(hold time)是指在触发器的时钟信号上升沿到来以后,数据稳定不变的时间,如果保持时间不够,数据同样不能被打入触发器。
Tsu:建立时间
Th:保持时间
Tco:寄存器内部延迟时间
上图pulse信号的变化在 clk时钟的建立和保持时间内,那么pulse_r1可能会进入亚稳态。
一般情况下,亚稳态的决断时间(即进入亚稳态到稳定下来的时间)不会超过一个时钟周期,因此在下一个clk上升沿到来前,pulse_r1已稳定下来(0或1),此时第二级寄存器就会采集到一个稳定的0或1,把亚稳态限制在第二级寄存器之前,保证了整个电路输出的稳定性。
综上所述,在异步信号边沿检测电路中,至少需要采用三级寄存器来实现,来降低亚稳态发生概率,提高系统稳定性。
Verilog代码编写三级寄存器避免亚稳态现象出现,实现异步信号边缘检测
module test(clk, rst_n,pulse,pos_edge,neg_edge,data_edge);
input clk, rst_n;
input pulse;
output pos_edge;
output neg_edge;
output data_edge;
reg pulse_r1, pulse_r2, pulse_r3;
//打三拍来消除亚稳态
always @ (posedge clk or negedge rst_n) //异步
if(!rst_n)
begin
pulse_r1 <= 1'b0;
pulse_r2 <= 1'b0;
pulse_r3 <= 1'b0;
end
else
begin
pulse_r1 <= pulse;
pulse_r2 <= pulse_r1;
pulse_r3 <= pulse_r2;
end
//边沿检测
assign pos_edge = pulse_r2 & ~pulse_r3;
assign neg_edge = ~pulse_r2 & pulse_r3;
assign data_edge = pos_edge | neg_edge;
endmodule
testbench仿真文件
`timescale 1ns/1ns
`define clock_period 20
module test_tb;
reg clk;
reg rst_n;
reg pulse;
wire pos_edge;
wire neg_edge;
wire data_edge;
test u1(
.clk(clk),
.rst_n(rst_n),
.pulse(pulse),
.pos_edge(pos_edge),
.neg_edge(neg_edge),
.data_edge(data_edge)
);
//产生时钟复位激励
initial clk = 1;
always #(`clock_period/2) clk =~clk;
initial begin
rst_n = 0;
#10;
rst_n = 1;
end
//产生输入激励
initial begin
pulse=0;
#(`clock_period*10+1)
pulse=1;
#(`clock_period*10+1)
pulse=0;
#(`clock_period*10+1)
pulse=1;
#(`clock_period*5+1)
pulse=0;
#(`clock_period*200+1)
pulse=0;
#(`clock_period*10)
$stop;
end
endmodule
全局波形图:
可看到我们打了三拍,可避免亚稳态的出现。让根据输入pulse进行了上升下降以及边沿检测。
上升沿检测波形:
下降沿检测:
边沿检测: