
引言
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
仿真结果

多的就不解释了,能用代码交流的就不说人话哈哈,大家在使用中发现什么问题,在评论区滴滴我~



















