跨时钟域处理之单比特信号(1)
1.跨时钟域的基本概念:
单比特信号需要从时钟域a同步到时钟域b中,由于ab时钟域的时钟可能不同,就需要进行跨时钟域处理。
亚稳态:
每一个触发器都有其规定的建立(setup)和保持(hold)时间参数, 在这个时间参数内, 输入信号在时钟的上升沿是不允许发生变的。 如果在信号的建立时间中对其进行采样, 得到的结果将是不可预知的,即亚稳态。
触发器进入亚稳态的时间可以用参数 MTBF(mean time between failures)来描述, MTBF即触发器采样失败的时间间隔,其公式描述如下:
M
T
B
F
=
e
t
r
/
τ
T
0
f
a
MTBF= \frac{e^{t_{r}/\tau }}{T_{0} fa}
MTBF=T0faetr/τ
- tr = 分辨时间(时钟沿开始)
- τ,T0 = 触发器参数
- f = 采样时钟频率
- a = 异步事件触发频率
2.从慢时钟到快时钟域
源时钟就是慢时钟,目的时钟就是快时钟,将源时钟域(慢)内的单比特信号同步到另一个目的时钟域(快),我们默认单比特脉冲信号在源时钟域内已经被本地时钟控制的寄存器同步(例如DFF1),这是因为经过时钟同步后信号不仅与时钟保持同步,而且有利于时序优化(时序路径为两个时钟元件之间的数据路径,使用触发器同步,无疑将长的数据路径截短,有利于时序通过),这也是我们推荐的一种设计习惯;
信号从慢时钟域同步到快时钟域,在目的时钟域是一定能采样到的,只不过可能会出现亚稳态的结果,针对这种场景下出现的亚稳态,我们的处理方式是两级寄存器同步,也就是通常我们说的使用目的寄存器对源时钟域的脉冲信号”打两拍“!
//单比特的跨时钟域传输;慢时钟域到快时钟域
module cdclf(
input rest_n,
input clkf,
input clkl,
input indata,
output outdata
);
//定义参数
reg inq1;
reg outq1;
reg outq2;
//将数据进行同步;
always@(posedge clkl or negedge rest_n)
begin
if(!rest_n)
inq1<=1'd0;
else
inq1<=indata;
end
//同步到快时钟域,进行打拍
always@(posedge clkf or negedge rest_n)
begin
if(!rest_n) begin
outq1<=1'd0;
outq2<=1'd0;
end
else begin
outq1<=inq1;
outq2<=outq1;
end
end
assign outdata=outq2;
endmodule
module cdclf_tb();
//例化
cdclf cdclf_inst(
.rest_n(rest_n),
.clkf(clkf),
.clkl(clkl),
.indata(indata),
.outdata(outdata)
);
//
reg rest_n;
reg clkf;
reg clkl;
reg indata;
wire outdata;
//
initial
begin
rest_n=1'd0;
clkf=1'd0;
clkl=1'd0;
indata=1'd0;
#100 rest_n=1'd1;
#25 indata=1'd1;
#10 indata=1'd0;
end
always #5 clkf=~clkf;//快时钟
always #10 clkl=~clkl;//慢时钟
endmodule
仿真结果:
2.从快时钟到慢时钟域
从快时钟到慢时钟,单比特信号可能会被慢时钟采样不到,具体情况可以看代码和仿真。在源时钟域,先检测到上升沿,然后通过反馈回来的信号进行控制,这样可以解决脉冲宽度小于目的时钟的情况。
module cdcfl(
input clkl,
input clkf,
input indata,
input rest_n,
output outdata
);
//参数定义
reg indata1;
reg outq1;
reg outq2;
reg inq1;
reg inq2;
//
reg indff1;
reg indff2;
wire ind;
//对脉冲信号进行上升沿检测
always@(posedge clkf or negedge rest_n)
begin
if(!rest_n) begin
indff1<=1'd0;
indff2<=1'd0;
end
else begin
indff1<=indata;
indff2<=indff1;
end
end
assign ind=({indff1,indff2}==2'b10)?1'b1:1'b0;
//源时钟域
always@(posedge clkf or negedge rest_n)
begin
if(!rest_n)
indata1<=1'd0;
else if(ind)
indata1<=1'd1;
else if(inq2)
indata1<=1'd0;
end
//目标时钟域
always@(posedge clkl or negedge rest_n)
begin
if(!rest_n)begin
outq1<=1'd0;
outq2<=1'd0;
end
else begin
outq1<=indata1;
outq2<=outq1;
end
end
//反馈信号
always@(posedge clkf or negedge rest_n)
begin
if(!rest_n) begin
inq1<=1'd0;
inq2<=1'd0;
end
else begin
inq1<=outq2;
inq2<=inq1;
end
end
assign outdata= outq2;
endmodule
`timescale 1ns / 1ps
// Company:
// Engineer:
//
// Create Date: 10:10:45 05/20/2021
// Design Name: cdcfl
// Module Name: E:/fpga/project/cdcfl/sim/cdcfltb.v
// Project Name: cdcfl
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: cdcfl
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
module cdcfltb;
// Inputs
reg clkl;
reg clkf;
reg indata;
reg rest_n;
// Outputs
wire outdata;
// Instantiate the Unit Under Test (UUT)
cdcfl uut (
.clkl(clkl),
.clkf(clkf),
.indata(indata),
.rest_n(rest_n),
.outdata(outdata)
);
initial begin
// Initialize Inputs
clkl = 0;
clkf = 0;
indata = 0;
rest_n = 0;
// Wait 100 ns for global reset to finish
#100;
rest_n=1;
// Add stimulus here
#20
indata=1;
#10
indata=0;
end
always #10 clkl=~clkl;
always #5 clkf=~clkf;
endmodule
这是脉冲宽度为25ns;这个宽度可以时钟打拍的方式,但是为了全面性。第一种还是比较保险。