CDC单bit数据跨时钟域处理(慢到快&&快到慢)
一.慢时钟域到快时钟域
1.1 基础知识点
------后者为本时钟域,从慢时钟域来的信号是本时钟域的异步信号;慢到快首先能够保证慢时钟的脉冲序列或电平能够被快时钟采到,但是不一定能满足本时钟域的建立时间和保持时间,由此可能会导致电路出现不确定状态:亚稳态,甚至是亚稳态的传播,因此需要加入两级同步器进行同步,减少亚稳态发生概率。
------如果两级同步器第一级不满足其建立保持时间,则Register1输出很可能产生不确定的抖动状态,但是大概率会在第二个Register2的建立时间之前稳定下来,以至于电路实现同步时序的效果。典型0.25um ASIC≈2.01(day)出现亚稳态,使用双寄存器法后,平均9.57*10^9年才出现亚稳态,MTBF(一个衡量亚稳态的公式,越大越不容易出现亚稳态)足够大。
------本处只是打两拍直接承接慢时钟域信号,如果只需检测脉冲信号即还原单时钟域脉冲,则在register2和CDC_SF_out后接一个与门,其中CDC_SF_out端口输出要加个非门,既能有效检测脉冲并还原单时钟脉冲信号。
1.2 Verilog实现及仿真验证
1.21 Verilog实现
`timescale 1ns/1ps
module CDC_SF
(
input clk_s, //slow
input clk_f, //fast
input rst_n,
input CDC_SF_in,
output reg CDC_SF_out
);
//************Register definition***************
reg Register_a;
reg Register_1;
reg Register_2;
//*************clk_s circutry********************
always@( posedge clk_s or negedge rst_n ) begin
if( !rst_n )
Register_a <= 0;
else
Register_a <= CDC_SF_in;
end
//*************clk_f circutry********************
//打两拍
always@( posedge clk_f or negedge rst_n ) begin
if( !rst_n ) begin
Register_1 <= 0;
Register_2 <= 0;
end
else begin
Register_1 <= Register_a;
Register_2 <= Register_1;
end
end
//clk_2 Clock recive steady data input
always@( posedge clk_f or negedge rst_n ) begin
if( !rst_n )
CDC_SF_out <= 0;
else
CDC_SF_out <= Register_2;
end
endmodule
1.22 testbench
`timescale 1ns/1ps
`define clock_period 20
module CDC_SF_tb();
//parameter definition
reg clk_s;
reg clk_f;
reg rst_n;
reg CDC_SF_in;
wire CDC_SF_out;
//DUT
CDC_SF CDC_SF0
(
.clk_s(clk_s),
.clk_f(clk_f),
.rst_n(rst_n),
.CDC_SF_in(CDC_SF_in),
.CDC_SF_out(CDC_SF_out)
);
//Clock
initial begin
clk_s = 1;
clk_f = 1;
end
always#(`clock_period/2) begin
clk_s = ~clk_s;
end
always#(`clock_period/4) begin
clk_f = ~clk_f;
end
//Siginal generation
initial begin
rst_n = 0;
CDC_SF_in = 0;
#(`clock_period*10 + 1);
rst_n = 1;
#(`clock_period/2);
CDC_SF_in = 1;
#(`clock_period*10);
$stop;
end
initial begin
$vcdpluson;
end
endmodule
1.23 仿真结果
如图1所示,从慢时钟域clk_s传到快时钟域clk_f后在快时钟域打两拍,然后输出给CDC_SF_out作为稳态数据。
图1
二.快到慢的两种实现方法
2.1 基础知识点
-----同样是跨时钟域信号同步类型,即需满足当前时钟域的建立保持时间,但快到慢的CDC将更加的苛刻,比如快时钟一个周期的脉冲不加处理下在慢时钟域很可能漏采,则需要扩宽脉冲宽度,对应方案有翻转电路法和结绳法,另还有兼容慢到快以及快到慢锁存器法(电平检测法),但容易受毛刺影响,少用或者不用锁存器法这种方法;
-----翻转电路基本功能:从本时钟域取出一个单时钟宽度脉冲,然后在新的时钟中建立另一个单时钟宽度的脉冲。但是输入脉冲时间必须至少保持两个接收时间宽度,否则无法恢复脉冲。
2.2 Verilog示例1(时域延长翻转电路法)及其仿真
2.21 Verilog实现
module CDC_FS(
input clk_f, //fast
input clk_s, //slow
input rst_n,
input CDC_FS_in,
output CDC_FS_out
);
//parameter definition
reg toggle;
reg register_1;
reg register_2;
reg register_3;
//*************************Main*******************************
//Return circuit
always@( posedge clk_f or negedge rst_n ) begin
if( !rst_n )
toggle <= 0;
else if( CDC_FS_in == 1 )
toggle <= ~toggle;
else
toggle <= toggle;
end
//Two state later
always@(posedge clk_s or negedge rst_n) begin
if( !rst_n ) begin
register_1 <= 0;
register_2 <= 0;
end
else begin
register_1 <= toggle;
register_2 <= register_1;
end
end
//Reback and output
always@( posedge clk_s or negedge rst_n ) begin
if( !rst_n )
register_3 <= 0;
else
register_3 <= register_2;
end
assign CDC_FS_out = register_2^register_3;
endmodule
2.22 testbench
`timescale 1ns/1ps
`define clock_period 20
module CDC_FS_tb();
//parameter definition
reg clk_f;
reg clk_s;
reg rst_n;
reg CDC_FS_in;
wire CDC_FS_out;
//DUT
CDC_FS CDC_FS0
(
.clk_f(clk_f),
.clk_s(clk_s),
.rst_n(rst_n),
.CDC_FS_in(CDC_FS_in),
.CDC_FS_out(CDC_FS_out)
);
//Clock
initial begin
clk_f = 1;
clk_s = 1;
end
always#(`clock_period/2) begin
clk_s = ~clk_s;
end
always#(`clock_period/4) begin
clk_f = ~clk_f;
end
//Siginal generation
initial begin
rst_n = 0;
CDC_FS_in = 0;
#(`clock_period*10 + 1);
rst_n = 1;
#(`clock_period/2);
CDC_FS_in = 1;
#(`clock_period/2);
CDC_FS_in = 0;
#(`clock_period*2);
CDC_FS_in = 1;
#(`clock_period/2);
CDC_FS_in = 0;
#(`clock_period*10);
$stop;
end
initial begin
$vcdpluson;
end
endmodule
2.23 仿真结果
-----如下图2所示,快时钟域的两个脉冲信号在慢时钟域(本)恢复成了两个脉冲信号,即恢复成功。
图2
2.3 Verilog示例2(结绳法待补充)
-----脉冲同步过程为结绳和解绳过程。
三.握手通信方法(兼容快到慢和慢到快)
-----如RS232串口通信方式,收发双方根据统一的波特率进行传输,实现数据的有效传送,但如果每次传输为多bit数据,那么延迟较大,不推荐以上单bit传输方式:打拍、锁存器法、翻转电路法和结绳法。