引言
FPGA设计或者ASIC设计中经常存在多个时钟域,那么这些时钟域之间脉冲信号的同步该如何进行设计?快时钟域到慢时钟域的脉冲信号同步与慢时钟域信号到快时钟域信号的同步是不一样的。
本文先给出快时钟域到慢时钟域脉冲信号同步的方法之一:脉冲展宽+3级同步器(或2级同步器亦可)。给出设计和仿真源码。
下篇文章将介绍另一种握手的方法实现脉冲信号从快时钟域到慢时钟域的同步设计。
本文以快时钟域200MHz到慢时钟域80MHz进行说明,但设计源文件同样考虑到模块的参数化设计。
设计源码
// | ======================================================================
// | 作者:Xu Y. B.
// | 时间:2023-02-20
// | 说明:快时钟域——>慢时钟域 单周期脉冲信号同步设计
// | 方法:脉冲展宽 + 3级同步器
// | ======================================================================
`timescale 1ns / 1ps
module CDC_F2S #(
// ====================================== 模块参数 ====================================
parameter P_FAST_CLK_FREQ = 32'd200_000_000,// Unit:Hz
parameter P_SLOW_CLK_FREQ = 32'd50_000_000,// Unit:Hz
parameter P_SYNC_STAGE = 2'd3
)(
// ==================================== 输入输出端口 ==================================
input I_FAST_CLK,
input I_SLOW_CLK,
input I_FAST_RSTN,
input I_SLOW_RSTN,
input I_FAST_PULSE,//单周期
output O_SLOW_PULSE
);
// ==================================== 模块内部参数 ==================================
localparam LP_WIDEN_TIMES = FUNC_CAL_WIDEN_TIMES(P_FAST_CLK_FREQ,P_SLOW_CLK_FREQ);
// ==================================== 模块内部信号 ==================================
reg [LP_WIDEN_TIMES-1:0] R_WIDEN_PULSE;
reg [P_SYNC_STAGE-1:0] R_SYNC;
// ==================================== 模块内部逻辑 ==================================
always @ (posedge I_FAST_CLK)
begin
if(~I_FAST_RSTN)
begin
R_WIDEN_PULSE <= {LP_WIDEN_TIMES{1'b0}};
end
else
begin
R_WIDEN_PULSE <= {R_WIDEN_PULSE[LP_WIDEN_TIMES-2:0],I_FAST_PULSE};
end
end
always @ (posedge I_SLOW_CLK)
begin
if(~I_SLOW_RSTN)
begin
R_SYNC <= {P_SYNC_STAGE{1'b0}};
end
else
begin
R_SYNC <= {R_SYNC[P_SYNC_STAGE-2:0],|R_WIDEN_PULSE};
end
end
assign O_SLOW_PULSE = R_SYNC[P_SYNC_STAGE-2] & ~R_SYNC[P_SYNC_STAGE-1];
// ==================================== 模块内部函数 ==================================
function integer FUNC_CAL_WIDEN_TIMES;
input integer FAST_CLK_FREQ;
input integer SLOW_CLK_FREQ;
begin
if(FAST_CLK_FREQ % SLOW_CLK_FREQ == 0)
begin
FUNC_CAL_WIDEN_TIMES = FAST_CLK_FREQ / SLOW_CLK_FREQ;
end
else
begin
FUNC_CAL_WIDEN_TIMES = FAST_CLK_FREQ / SLOW_CLK_FREQ + 1;
end
end
endfunction
endmodule
仿真源码
// | ======================================================================
// | 作者:Xu Y. B.
// | 时间:2023-02-20
// | 说明:快时钟域——>慢时钟域 单周期脉冲信号同步设计 测试文件
// | 方法:脉冲展宽 + 3级同步器
// | ======================================================================
`timescale 1ns / 1ps
module TB_CDC_F2S();
// ====================================== 模块参数 ====================================
parameter P_FAST_CLK_FREQ = 32'd200_000_000;
parameter P_SLOW_CLK_FREQ = 32'd80_000_000;
parameter P_SYNC_STAGE = 2'd3;
// ==================================== 输入输出端口 ==================================
reg I_FAST_CLK;
reg I_SLOW_CLK;
reg I_FAST_RSTN;
reg I_SLOW_RSTN;
reg I_FAST_PULSE;//单周期
wire O_SLOW_PULSE;
initial I_FAST_CLK = 1'b1;
always #2.5 I_FAST_CLK = ~I_FAST_CLK;
initial I_SLOW_CLK = 1'b0;
always #6.25 I_SLOW_CLK = ~I_SLOW_CLK;
initial
begin
I_FAST_RSTN = 1'b0;
I_SLOW_RSTN = 1'b0;
I_FAST_PULSE = 1'b0;
#103;
I_FAST_RSTN = 1'b1;
#209;
I_SLOW_RSTN = 1'b1;
#208;
@(posedge I_FAST_CLK)
I_FAST_PULSE <= 1'b1;
@(posedge I_FAST_CLK)
I_FAST_PULSE <= 1'b0;
@(posedge O_SLOW_PULSE);
#206;
$finish;
end
CDC_F2S #(
.P_FAST_CLK_FREQ(P_FAST_CLK_FREQ),
.P_SLOW_CLK_FREQ(P_SLOW_CLK_FREQ),
.P_SYNC_STAGE(P_SYNC_STAGE)
) INST_CDC_F2S (
.I_FAST_CLK (I_FAST_CLK),
.I_SLOW_CLK (I_SLOW_CLK),
.I_FAST_RSTN (I_FAST_RSTN),
.I_SLOW_RSTN (I_SLOW_RSTN),
.I_FAST_PULSE (I_FAST_PULSE),
.O_SLOW_PULSE (O_SLOW_PULSE)
);
endmodule
仿真结果
多的就不解释了,能用代码交流的就不说人话哈哈,大家在使用中发现什么问题,在评论区滴滴我~