本文主要讨论了两方面的内容。第一,慢时钟域对快时钟域脉冲信号的采集;第二,边沿检测过程中需要注意的细节。慢时钟域对快时钟域脉冲信号的采集
首先来看一幅时序图,如图1所示。快时钟域clka中有脉冲信号dina,如果慢时钟域clkb中直接对脉冲信号dina进行采样,将无法正确采集到该脉冲。
图1 直接跨时钟域采样脉冲信号
一般情况下,对于慢时钟域过渡到快时钟域,可以采用边沿检测技术完成信号的过渡;而对于快时钟域过渡到慢时钟域或两个时钟域的时钟相差不大时,可以用存储器完成信号的过渡,如双端口RAM、异步FIFO或外部存储器(SDRAM、DDR等)等等。
不过,在这里我要介绍的一种方法是人为延长快时钟域的脉冲信号,使其可以被慢时钟域的时钟采集到,如图2所示。在快时钟域clka中,当脉冲信号dina到来时,对dina信号进行人为延长获得脉冲信号dina_temp,使得dina_temp的脉冲时间大于慢时钟域clkb的周期,即Tdina_temp > Tclkb。为了增加采样的稳定性,可以使dina_temp的脉冲时间大于慢时钟域clkb的周期的2倍,即Tdina_temp > 2*Tclkb。
图2 人为延长脉冲信号使其可以被正确采样
补充:对快时钟域clka中的脉冲信号延长后,就可以在时钟域clkb中采用边沿检测技术采集到输入的脉冲信号了。
边沿检测中需要注意的细节
很多人看到这个标题的时候,都会想边沿检测不是很简单的吗?有什么需要注意的?它是很简单,只要对输入信号进行两级缓存,然后通过判断前后两级的逻辑来决定信号的上升沿或下降沿。但你们有没有想过当系统复位时应该给寄存器赋什么值?估计很多人都没有想过吧,管它三七二十一,一律赋0(或1)。那恭喜你,你已经掉进陷阱了。什么陷阱?误判的陷阱。举个例子,检测一个信号的上升沿,见如程序清单1所示:
程序清单1
/******************************************Copyright********************************************
** CrazyBird
**
**----------------------------------------File Infomation--------------------------------------
** FileName : edge_detection.v
** Author : CrazyBird
** Data : 2015-10-25
** Version : v1.0
** Description : the rising edge detection of signal
**
************************************************************************************************/
// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module edge_detection
(
input clk,
input rst_n,
input din,
output pos_flag
);
//------------------------------------
// Two levels of cache on the signal
reg din_r1;
reg din_r2;
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
din_r1 <= 1'b0;
din_r2 <= 1'b0;
end
else
begin
din_r1 <= din;
din_r2 <= din_r1;
end
end
//------------------------------------
// rising edge detect
assign pos_flag = din_r1 & ~din_r2;
endmodule
//*****************************************End File**********************************************
这是一个超级简单的信号上升沿检测,相信很多人也是这样写。但你这样设计出来的东西是不稳定的。为什么?从理论上分析,当复位后,din_r1和din_r2d的值都为1'b0。如果输入信号din为1'b1,在时钟上升沿到来时,din的值会被锁进din_r1即din_r1=1'b1,而din_r1前一时刻的值被锁进din_r2即din_r2=1'b0。此时,并没有信号的上升沿到来,而pos_flag的值为1'b1,从而导致第一次上升沿是误判的。也可以从仿真波形中体现出来,如图3所示。
图3 仿真波形
为了避免误判情况的出现,我们采取措施:对于信号上升沿检测,复位后寄存器应都赋值为1'b1。修改后的代码如程序清单2所示:
程序清单2
/******************************************Copyright********************************************
** CrazyBird
**
**----------------------------------------File Infomation--------------------------------------
** FileName : edge_detection.v
** Author : CrazyBird
** Data : 2015-10-25
** Version : v1.0
** Description : the rising edge detection of signal
**
************************************************************************************************/
// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module edge_detection
(
input clk,
input rst_n,
input din,
output pos_flag
);
//------------------------------------
// Two levels of cache on the signal
reg din_r1;
reg din_r2;
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
din_r1 <= 1'b1;
din_r2 <= 1'b1;
end
else
begin
din_r1 <= din;
din_r2 <= din_r1;
end
end
//------------------------------------
// rising edge detect
assign pos_flag = din_r1 & ~din_r2;
endmodule
//*****************************************End File**********************************************
仿真结果如图4所示:
图4 上升沿正确检测
同样,对于下降沿检测,复位时应将寄存器都赋值为1'b0,大家可自行验证。
总结一下,上升沿检测,复位时寄存器应赋值为1'b1;下降沿检测,复位时寄存器应赋值为1'b0。
**文/crazybird **
来源:AET电子技术应用