控制信号(单脉冲信号)的跨时钟域传输问题存在两种情况,一种是从快时钟域到慢时钟域传输,如果用慢时钟强行采样快时钟域内的控制信号,可能存在采样不到信号的情况,而且很大概率采不到信号;另一种情况是从慢时钟域到快时钟域的控制信号传输问题,这种情况,快时钟一定能采样到慢时钟域内的控制信号,但是可能出现亚稳态问题;
下面针对这两种情况进行处理:
快时钟到慢时钟
有两个时钟域A和B,脉冲a在时钟域A中保持一个时钟周期,现要把脉冲A同步到时钟域B中,试用D触发器、与门、或门、非门以及异或门画出电路图实现这个功能。(某发科IC现场笔试题)
先考虑从快时钟域到慢时钟域进行信号传输的问题(脉冲宽度小于一个时钟):
先通过Verilog来实现:(参考链接)
module Sync_Pulse(
input clka,
input clkb,
input rst_n,
input pulse_ina,
output pulse_outb,
output signal_outb
);
//-------------------------------------------------------
reg signal_a;
reg signal_b;
reg signal_b_r;
reg signal_b_rr;
reg signal_a_r;
reg signal_a_rr;
//-------------------------------------------------------
//在clka下,生成展宽信号signal_a
always @(posedge clka or negedge rst_n)begin
if(rst_n == 1'b0)begin
signal_a <= 1'b0;
end
else if(pulse_ina == 1'b1)begin
signal_a <= 1'b1;
end
else if(signal_a_rr == 1'b1)
signal_a <= 1'b0;
else
signal_a <= signal_a;
end
//-------------------------------------------------------
//在clkb下同步signal_a
always @(posedge clkb or negedge rst_n)begin
if(rst_n == 1'b0)begin
signal_b <= 1'b0;
end
else begin
signal_b <= signal_a;
end
end
//-------------------------------------------------------
//在clkb下生成脉冲信号和输出信号
always @(posedge clkb or negedge rst_n)begin
if(rst_n == 1'b0)begin
signal_b_r <= 'b0;
signal_b_rr <= 'b0;
end
else begin
signal_b_rr <= signal_b_r;
signal_b_r <= signal_b;
end
end
assign pulse_outb = ~signal_b_rr & signal_b_r;
assign signal_outb = signal_b_rr;
//-------------------------------------------------------
//在clka下采集signal_b_rr,生成signal_a_rr用于反馈拉低signal_a
always @(posedge clka or negedge rst_n)begin
if(rst_n == 1'b0)begin
signal_a_r <= 'b0;
signal_a_rr <= 'b0;
end
else begin
signal_a_rr <= signal_a_r;
signal_a_r <= signal_b_rr;
end
end
endmodule
本题需要输出的信号其实是pulse_outb,这个信号在时钟域B中持续了一个时钟,通过边沿检测实现的。
经过Quartus生成的RTL原理图如下:
经过Vivado生成的RTL原理图如下:
可见,大同小异。
可是到这里并没有结束,这种电路图和题目要求的还不一样,人家没要求用多路选择器呀,所以需要将反馈后的多路选择器换成需要的器件。
参考图片来源
需要画出的原理图如下:
上面电路的实现,是快时钟域到慢时钟域的问题,我们通过反馈信号进行控制信号的延时来让慢时钟域充分采样得到控制信号,本质上是也是对控制信号的延时。这个延时的具体实现,需要对控制信号的产生逻辑进行处理,来满足延时的要求。
为什么上面的电路能实现,我们来仿真看看:
pulse_ina为快时钟域的控制信号,signal_a为pulse_ina的脉冲展宽信号,signal_b为慢时钟对脉冲展宽信号的采样,signal_b_r,signal_b_rr分别为signal_b的延迟,一拍,二拍。
signal_a_r为反馈信号,同理signal_a_rr是最直接的反馈信号,它决定pulse_ina的脉冲展宽的停止。
pulse_outb为慢时钟的控制脉冲输出,也是最后需要的结果。
给出测试文件:
`timescale 1ns/1ps
module CLK_Fast2Slow_TB();
reg clka;
reg clkb;
reg rst_n;
reg pulse_ina;
wire pulse_outb;
wire signal_outb;
initial begin
clka = 0;
forever
#2 clka = ~clka;
end
initial begin
clkb = 0;
forever
#4 clkb = ~clkb;
end
initial begin
rst_n = 0;
pulse_ina = 0;
# 10
rst_n = 1;
#4
pulse_ina = 1;
#4
pulse_ina = 0;
end
Sync_Pulse INST_CLK_Fast2Slow(
.clka(clka),
.clkb(clkb),
.rst_n(rst_n),
.pulse_ina(pulse_ina),
.pulse_outb(pulse_outb),
.signal_outb(signal_outb)
);
endmodule
慢时钟域到快时钟域
在慢时钟域到快时钟域传输的问题则不必如此麻烦,因为快时钟域总能采样到慢时钟域的脉冲信号,唯一需要注意的是,采样的信号会出现亚稳态的问题,如快时钟域信号的上升沿恰好对应慢时钟域脉冲的变化位置,导致建立时间不满足。
为了解决这个问题,我们只需要用快时钟对慢时钟域脉冲进行两级寄存器同步即可,这样基本就解决了亚稳态的问题了。
参考代码
module Sync_Pulse(
input clkb,
input rst_n,
input pulse_ina,
output pulse_outb
);
reg signal_r;
reg signal_rr;
always @ (posedge clkb or negedge rst_n)
if (!rst_n) begin
signal_r <= 1'b0;
signal_rr <= 1'b0;
end else begin
signal_r <= pulse_ina;
signal_rr <= signal_r;
end
assign pulse_outb = signal_rr;
endmodule
除了上面的参考链接外,在加几个可以参考:
https://mp.weixin.qq.com/s/QoLAV2NBi4_8mQ5bJ_4MAw