本篇着重讲解单bit信号由快时钟域到慢时钟域的转化。
对于跨时钟域信号的处理,方法我们都知道:
单bit:两级触发器同步(适用于慢到快)
多bit:采用异步FIFO,异步双口RAM 加握手信号 格雷码转换
对于多bit信号来说我们想要跨时钟域处理直接使用fifo就可以了。如果对于单bit信号来说,慢时钟域到快时钟域使用两级触发器就可以,代码如下图所示:
//---------慢时钟域到快时钟域----------//
module mul_clk(
input clk, //快时钟域时钟
input rst_n,
input pulse_a,
output pulse_b
);
reg [1:0]pulse_r;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
pulse_r <= 2'b00;
else
pulse_r <= {pulse_r[0],pulse_a};
end
assign pulse_b = pulse_r[1];
endmodule
波形仿真:
跨时钟域处理从快时钟域到慢时钟域根据信号宽度可以分为两种情况,如第一个图所示,ckl_b则可以采样到signal_a_in,但是如第二个图所示,只有单脉冲,就不能确保可以采样到signal_a_in。这种情况用两级触发器同步是没有用的。
所以针对第二种情况需要特殊处理,如下所示为针对第二种跨时钟域的处理代码:
//----------------快时钟域到慢时钟域----------------//
module mul_clk(
input clk_a,
input clk_b,
input rst_n,
input pulse_a,
output pulse_b
);
reg signal_a;
reg signal_b;
reg [1:0]signal_a_r;
reg [1:0]signal_b_r;
//----------时钟域A下进行脉冲pulse_a的展宽------------//
always@(posedge clk_a or negedge rst_n)begin
if(!rst_n)
signal_a <= 1'b0;
else if(pulse_a)
signal_a <= 1'b1;
else if(signal_a_r[1])
signal_a <= 1'b0;
else
signal_a <= signal_a;
end
//--------时钟域B下采集时钟域A拓展的脉宽信号signal_a-------//
always@(posedge clk_b or negedge rst_n)begin
if(!rst_n)
signal_b <= 1'b0;
else
signal_b <= signal_a;
end
//-------时钟域B下缓存signal_b信号,生成时钟域B下的脉冲------//
always@(posedge clk_b or negedge rst_n)begin
if(!rst_n)
signal_b_r <= 2'b00;
else
signal_b_r <= {signal_b_r[0],signal_b};
end
assign pulse_b = ~signal_b_r[1] & signal_b_r[0];
//--------时钟域A下采集signal_b_r,反馈到时钟域A控制signal_a拉低------//
always@(posedge clk_a or negedge rst_n)begin
if(!rst_n)
signal_a_r <= 2'b00;
else
signal_a_r <= {signal_a_r[0],signal_b_r[1]};
end
endmodule
仿真代码:
`timescale 1ns/1ns
module mul_clk_tb;
// reg clk;
// reg rst_n;
// reg pulse_a;
//
// wire pulse_b;
//
// mul_clk mul_clk_inst(
// .clk (clk ), //快时钟域时钟
// .rst_n (rst_n ),
// .pulse_a (pulse_a ),
// .pulse_b (pulse_b )
//);
reg clk_a;
reg clk_b;
reg rst_n;
reg pulse_a;
wire pulse_b;
mul_clk mul_clk_inst(
.clk_a (clk_a ),
.clk_b (clk_b ),
.rst_n (rst_n ),
.pulse_a (pulse_a ),
.pulse_b (pulse_b )
);
initial clk_a = 0;
always#10 clk_a = ~clk_a;
initial clk_b = 0;
always#30 clk_b = ~clk_b;
initial begin
rst_n = 0;
pulse_a = 0;
#200;
rst_n = 1;
#200;
pulse_a = 1;
#30;
pulse_a = 0;
#500;
$stop;
end
endmodule
波形仿真: