4、关于边沿检测简单理解二
0赞 (三)三级寄存器
三级寄存器与两级寄存器的区别是信号的同步。异步通信中,比如在STM 和FPGA的SPI通信中,需要先通过一级寄存器将片选信号同步,第二级寄存器进行亚稳态的消除。然后利用第二级寄存器的输出和第三级寄存器的输出进行上升沿或者下降沿的检测。如下图:

r0是将输入信号trigger信号同步的,经过r1消除亚稳态,同时,输出和r2的输出检测上升沿和下降沿(r1的输出已经经过异步同步了,可以被当作同步信号使用)。
always@(posedge clk or negedge rst_n) if(!rst_n) begin trigger_r0 <= 1'b0; trigger_r1 <= 1'b0; trigger_r2 <= 1'b0; end else begin trigger_r0 <= trigger; trigger_r1 <= trigger_r0; trigger_r2 <= trigger_r1; end assign pos_edge = trigger_r1 & ~trigger_r2; assign neg_edge = ~trigger_r1 & trigger_r2

上图为简单的时序图分析。
(四)四级寄存器
四级寄存器具有比较好的滤除毛刺能力。
//---------------------------------------------------------------- reg rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3; //接收数据寄存器,滤波用 wire neg_rs232_rx; //表示数据线接收到下降沿 always @ (posedge clk or negedge rst_n) if(!rst_n) begin rs232_rx0 <= 1'b0; rs232_rx1 <= 1'b0; rs232_rx2 <= 1'b0; rs232_rx3 <= 1'b0; end else begin rs232_rx0 <= rs232_rx; rs232_rx1 <= rs232_rx0; rs232_rx2 <= rs232_rx1; rs232_rx3 <= rs232_rx2; end //下面的下降沿检测可以滤掉<40ns-80ns的毛刺(包括高脉冲和低脉冲毛刺), //这里就是用资源换稳定(前提是我们对时间要求不是那么苛刻,因为输入信号打了好几拍) //(当然我们的有效低脉冲信号肯定是远远大于80ns的) assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0; //接收到下降沿后neg_rs232_rx置高一个时钟周期
上面为特权同学串口接受里面的代码。说的很明白在时间要求不是很苛刻的条件下,用多打几拍来滤除毛刺。我请教过办公室弄FPGA的同事,他在实际的项目中一直都是利用四级寄存器检测边沿的,几乎没遇到过时间要求很苛刻的,一般都够用了。
简单的顶层文件如下:
module edge_tech_design_b ( clk, rst_n, s, neg_edge, pos_edge ); input clk; input rst_n; input s; output neg_edge; output pos_edge; reg a, b, c, d; //延迟一个时钟周期出现跳变 always@(posedge clk or negedge rst_n) if(!rst_n)begin a <= 1'b0; b <= 1'b0; c <= 1'b0; d <= 1'b0; end else begin a <= s; b <= a; c <= b; d <= c; end assign neg_edge = d & c & !b & !a; assign pos_edge = !d & !c & b & a; endmodule
测试文件如下:
`timescale 1ns/1ns `define clk_period 20 module edge_tech_design_b_tb; reg clk; reg rst_n; reg s; wire neg_edge; wire pos_edge; edge_tech_design_b edge_tech_design_b ( .clk(clk), .rst_n(rst_n), .s(s), .neg_edge(neg_edge), .pos_edge(pos_edge) ); initial clk =1; always #(`clk_period/2) clk = ~clk; initial begin rst_n = 1'b0; s = 1'b0; #(`clk_period*10) rst_n = 1'b1; s = 1'b1; #(`clk_period*50) s = 1'b0; #(`clk_period*10) s = 1'b1; #(`clk_period*10) s = 1'b0; #(`clk_period*30) s = 1'b1; #(`clk_period*10) s = 1'b0; #(`clk_period*50) s = 1'b1; #(`clk_period*10) s = 1'b0; #(`clk_period*30) s = 1'b1; #(`clk_period*10) s = 1'b0; #(`clk_period*10) s = 1'b1; #(`clk_period*30) s = 1'b0; #(`clk_period*10) s = 1'b1; #(`clk_period*10) s = 1'b0; #(`clk_period*10) $stop; end endmodule
仿真波形如下:

下面关于一些零散的知识:
1、
异步时钟的同步化,俗称“慢打一拍,寄存一拍
异步时钟域数据同步,是指如何在两个时钟不同步的数据域之间可靠地进行数据交换的问题。其表现形式有两种:①两个域的时钟同频不同相,②异频
解决这两种形式的方法不尽相同:①、同频不同相问题:用后级时钟对前级数据采样两次,即通常所述的用寄存器打两次。这样的做法是有效地减少了亚稳态的传播,使得后即电路数据都是有效电平。②、异频问题。采用DPRAM或者FIFO来解决。
1.输入信号为什么要寄存
一般来说,在全同步设计中,如果信号来自同一时钟域,各模块的输入不需要寄存。只要满足建立时间,保持时间的约束,可以保证在时钟上升沿到来时,输入信号已经稳定,可以采样得到正确的值。但是如果模块需要使用输入信号的跳变沿(比如帧同步信号),千万不要直接这样哦。
always @ (posedge inputs)
begin
...
end
2.所有信号都需要寄存两拍吗
如果这个输入信号来自异步时钟域(比如FPGA芯片外部的输入),必须寄存两拍。第一拍将输入信号同步化,同步化后的输出可能带来建立/保持时间的冲突,产生亚稳态。需要再寄存一拍,减少(注意是减少)亚稳态带来的影响。
如果这个输入信号来自于同一时钟域且需要用到跳变沿,需要寄存一拍。否则时序报告多半会报clock skew > data delay,造成建立/保持时间的冲突。
总而言之,五条原则:
1.全局时钟的跳变沿最可靠。
2.来自异步时钟域的输入需要寄存一次以同步化,再寄存一次以减少亚稳态带来的影响。
3.不需要用到跳变沿的来自同一时钟域的输入,没有必要对信号进行寄存。
4.需要用到跳变沿的来自同一时钟域的输入,寄存一次即可。
5.需要用到跳变沿的来自不同时钟域的输入,需要用到3个触发器,前两个用以同步,第3个触发器的输出和第2个的输出经过逻辑门来判断跳变沿。
2、
亚稳态
异步时钟域的核心就是要保证下级时钟对上级数据采样的Setup时间和Hold时间。如果触发器的Setup和Hold时间不满足,则可能产生亚稳态。此时触发器的输出在有效时钟沿之后很长的一段时间内处于不确定的状态,最终固定在某一电压值。该值并不一定等于原来数据输入端得数据。
采用两级寄存器采样可以有效地减少亚稳定继续传播的概率。如下图所示,左边为异步输入端,经过了两级的触发器采样,在右边的输

出与clkb同步,而且该输出基本不存在亚稳定问题。其原理是即使第一个触发器的输出端存在亚稳态,在经过一个CLK周期后,第二个触发器的电平仍未稳定的概率很小,因此第二个触发器基本上不会产生亚稳态。理论上,如果在加一级触发器,则输出亚稳态的概率为0.
3、
异步传输和同步传输的区别?
收发两端对时间的精确度要求高低而已.同步要求高,异步没有同步要求那么高.
异步通信”是一种很常用的通信方式.异步通信在发送字符时,所发送的字符之间的时间间隔可以是任意的.当然,接收端必须时刻做好接收的准备(如果接收端主机的电源都没有加上,那么发送端发送字符就没有意义,因为接收端根本无法接收).发送端可以在任意时刻开始发送字符,因此必须在每一个字符的开始和结束的地方加上标志,即加上开始位和停止位,以便使接收端能够正确地将每一个字符接收下来.异步通信的好处是通信设备简单、便宜,但传输效率较低(因为开始位和停止位的开销所占比例较大).
异步通信也可以是以帧作为发送的单位.接收端必须随时做好接收帧的准备.这是,帧的首部必须设有一些特殊的比特组合,使得接收端能够找出一帧的开始.这也称为帧定界.帧定界还包含确定帧的结束位置.这有两种方法.一种是在帧的尾部设有某种特殊的比特组合来标志帧的结束.或者在帧首部中设有帧长度的字段.需要注意的是,在异步发送帧时,并不是说发送端对帧中的每一个字符都必须加上开始位和停止位后再发送出去,而是说,发送端可以在任意时间发送一个帧,而帧与帧之间的时间间隔也可以是任意的.在一帧中的所有比特是连续发送的.发送端不需要在发送一帧之前和接收端进行协调(不需要先进行比特同步). 每个字符开始发送的时间可以是任意的t0 0 1 1 0 1 1 0起始位结束位t每个帧开始发送的时间可以是任意的以字符为单位发送以帧为单位发送帧开始帧结束
“同步通信”的通信双方必须先建立同步,即双方的时钟要调整到同一个频率.收发双方不停地发送和接收连续的同步比特流.但这时还有两种不同的同步方式.一种是使用全网同步,用一个非常精确的主时钟对全网所有结点上的时钟进行同步.另一种是使用准同步,各结点的时钟之间允许有微小的误差,然后采用其他措施实现同步传输.
