快时钟到慢时钟的同步问题

同步器在慢时钟域clk_a信号同步入快时钟域clk_b时工作的很好,但是反过来的话,会存在快时钟采样不到慢时钟域内的输入脉冲的问题。举一个很简单的例子,其中clk_a是快时钟,clk_b是要进入的慢时钟,快时钟下的pluse_a信号脉冲很窄,则位于慢时钟的两个相邻跳变沿之间,会导致信号丢失或者容易出现亚稳态。

通常的解决方法是将pluse_a进行拓宽,就是在快时钟域内先进行脉冲展宽,展宽到快时钟内能采样到为止;展宽之后的信号在快时钟域clk_b下用两级寄存器同步下就好了,再用上升沿检测检测到同步后的信号得到一个时钟clk_b周期的脉冲,表示同步完成。

其中有一个问题是在快时钟域的拓宽的信号在什么时候拉低呢?这里需要一个反馈信号,反馈信号有效时,拉低拓宽信号,其中反馈信号的目的是告诉快时钟域已经采集到了有效信号,可以将拓展信号拉低。

可以看到其中中间信号是两个,一个在signal_a是在快时钟下的拓宽信号,signal_b是在慢时钟下的扩宽信号,将signal_b进行打拍,得到扩宽输出的有效电平信号和电压信号,当clk_a时钟检测到signal_b打拍后呈现有效信号,则将表明反馈信号有效,置signal_a为0,原博主的好像有问题,我修改了一下,如果有错误,希望指出。

module tclk(
	input clk_a,  //快
	input clk_b,  //慢
	input rst_n,
	input pulse_a_in,
	
	output pulse_b_out,
	output lev_b_out
    );
    reg signal_a;  //快时钟的扩宽信号
    reg signal_b;
    reg pulse_r1;
    reg pulse_r2;
    reg signal_b_a1;
    reg signal_b_a2;

    
	always@(posedge clk_a or negedge rst_n)
	begin
  	if(!rst_n)
  		signal_a <= 1'b0;
  	else if(pulse_a_in == 1'b1)
  		signal_a <= 1'b1;///检测到快时钟域的有效输入信号,进行同步拓宽
  	else if(signal_b_a2 == 1'b1)    //采样到慢时钟域的同步后的有效信号后,停止拓宽
  		signal_a <= 1'b0; 
  	else
  		signal_a <= signal_a;
	end
	
	//将慢脉冲clkb对扩宽后的信号进行采样
	always@(posedge clk_b or negedge rst_n)
	begin
  		if(!rst_n)
  			signal_b<= 1'b0;
  		else 
  			signal_b<=signal_a;
	end


	//将采样后的信号signal_b打两拍,解决亚稳态的问题
	always@(posedge clk_b or negedge rst_n)
	begin
  		if(!rst_n)
   		begin
   			pulse_r1<= 1'b0;
   			pulse_r2<= 1'b0;
   		end
  		else
   		begin
   			pulse_r1<= signal_b;
   			pulse_r2<=pulse_r1;
   		end
	 end

 //用于给signal_a反馈的拉低信号signal_b1_a2是清除clka下的脉冲拓宽信号标志信号。
 //把它同步回clka时钟域后再使用。
 
	always @ (posedge clk_a or negedge rst_n)
 	begin
     	if (rst_n == 1'b0) begin
         	signal_b_a1 <=  1'b0 ;
         	signal_b_a2 <=  1'b0 ;
     	end
     	else begin
         	signal_b_a1 <= pulse_r2 ;
         	signal_b_a2 <=  signal_b_a1 ;
     	end
 	end
 	
  	//输出电平信号与脉冲信号
 	assign pulse_b_out=pulse_r1&(~pulse_r2);
 	assign lev_b_out=pulse_r2;
endmodule
module tb_CDC_practice();
    reg clk_a,clk_b,rst_n;
    reg pulse_a_in;
    wire pulse_b_out, lev_b_out;
    always
        begin
            #10 clk_a = ~clk_a;
        end

    always
        begin
            #30 clk_b = ~clk_b;
        end
        
        
    initial begin
        clk_a = 1'b1;
        clk_b = 1'b1;
        pulse_a_in = 1'b0;
        rst_n = 1'b1;
        #10;
        rst_n = 1'b0;
        #30;
        rst_n = 1'b1;
        #5
        pulse_a_in = 1'b1;
        #15
        pulse_a_in = 1'b0;
    end
    
    CDC_Practice tb_CDC_Practic(
        .clk_a(clk_a),
        .clk_b(clk_b),
        .rst_n(rst_n),
        .pulse_a_in(pulse_a_in),
        .pulse_b_out(pulse_b_out),
        .lev_b_out(lev_b_out)
    );
endmodule
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值