Pulse Synchronization

- 脉冲同步(Pulse Synchronization)是 FPGA 设计中处理跨时钟域信号传输的常见问题和关键细节。
- 由于不同步的时钟域之间可能存在相位差或频率差异,可能会导致亚稳态问题或数据丢失。
- 脉冲同步的主要目标是确保一个时钟域中的脉冲信号能够在另一个时钟域安全接收。
脉冲同步代码实现
module nocdc (
input wire clk_src, // 源时钟域时钟(快时钟)
input wire clk_dst, // 目标时钟域时钟(慢时钟)
input wire rst_n, // 异步复位信号(低电平有效)
input wire pulse_in, // 源时钟域输入脉冲
output reg pulse_out // 目标时钟域输出脉冲
);
// 在源时钟域中对脉冲进行展宽
reg pulse_in_sync;
always @(posedge clk_src or negedge rst_n) begin
if (!rst_n)
pulse_in_sync <= 0;
else
pulse_in_sync <= pulse_in ^ pulse_in_sync; // 展宽脉冲
end
// 双触发同步
reg sync_ff1;
reg sync_ff2;
always @(posedge clk_dst or negedge rst_n) begin
if (!rst_n)begin
sync_ff1 <= 0;
sync_ff2 <= 0;
end
else begin
sync_ff1 <= pulse_in_sync;// 第一级同步触发器
sync_ff2 <= sync_ff1; // 第二级同步触发器
end
end
// 边沿检测
reg sync_ff3;
always @(posedge clk_dst or negedge rst_n) begin
if (!rst_n)
sync_ff3 <= 0;
else
sync_ff3 <= sync_ff2;
end
// 输出脉冲
always @(posedge clk_dst or negedge rst_n) begin
if (!rst_n)
pulse_out <= 0;
else
pulse_out <= sync_ff3 ^ sync_ff2;
end
endmodule
.vt 激励文件
`timescale 1 ps/ 1 ps
module nocdc_vlg_tst;
// 输入信号
reg clk_src; // 源时钟域时钟
reg clk_dst; // 目标时钟域时钟
reg rst_n; // 异步复位信号(低电平有效)
reg pulse_in; // 源时钟域输入脉冲
// 输出信号
wire pulse_out; // 目标时钟域输出脉冲
// 实例化被测模块
nocdc uut (
.clk_src(clk_src),
.clk_dst(clk_dst),
.rst_n(rst_n),
.pulse_in(pulse_in),
.pulse_out(pulse_out)
);
// 时钟生成:源时钟域时钟
initial begin
clk_src = 0;
forever #5 clk_src = ~clk_src; // 100MHz (周期为 10ns)
end
// 时钟生成:目标时钟域时钟
initial begin
clk_dst = 0;
forever #8 clk_dst = ~clk_dst; // 62.5MHz (周期为 16ns)
end
// 测试过程
initial begin
// 初始化信号
rst_n = 0; // 复位信号初始为低电平
pulse_in = 0; // 输入脉冲初始为低电平
#20;
rst_n = 1; // 释放复位信号
// 等待一段时间观察输出
#50;
// 测试用例 2:连续多个脉冲
#30;
pulse_in = 1; // 第一个脉冲
#10;
pulse_in = 0;
#50;
pulse_in = 1; // 第二个脉冲
#10;
pulse_in = 0;
// 等待一段时间观察输出
#100;
// 结束仿真
$stop;
end
endmodule
CG
-
如果输入脉冲过于窄(小于源时钟周期),可能会导致展宽失败。
-
单个脉冲也能进行展宽
-
还可以根据需求选择上升沿或下降沿
module nocdc (
input wire clk_src, // 源时钟域时钟(快时钟)
input wire clk_dst, // 目标时钟域时钟(慢时钟)
input wire rst_n, // 异步复位信号(低电平有效)
input wire pulse_in, // 源时钟域输入脉冲
output reg pulse_out // 目标时钟域输出脉冲
);// 在源时钟域中对脉冲进行展宽 reg pulse_in_sync; always @(posedge clk_src or negedge rst_n) begin if (!rst_n) pulse_in_sync <= 0; else pulse_in_sync <= pulse_in ^ pulse_in_sync; // 展宽脉冲 end // 双触发同步 reg sync_ff1; reg sync_ff2; always @(posedge clk_dst or negedge rst_n) begin if (!rst_n)begin sync_ff1 <= 0; sync_ff2 <= 0; end else begin sync_ff1 <= pulse_in_sync;// 第一级同步触发器 sync_ff2 <= sync_ff1; // 第二级同步触发器 end end // 边沿检测 reg sync_ff3; always @(posedge clk_dst or negedge rst_n) begin if (!rst_n) sync_ff3 <= 0; else sync_ff3 <= sync_ff2; end wire sync_rise_edge = ~sync_ff2 & sync_ff3; // 上升沿检测 wire sync_fall_edge = sync_ff2 & ~sync_ff3; // 下降沿检测 // 输出脉冲 always @(posedge clk_dst or negedge rst_n) begin if (!rst_n) pulse_out <= 0; else pulse_out <= sync_rise_edge; // 还可以根据需求选择上升沿或下降沿 end
endmodule