【CDC跨时钟域信号处理】单bit_快时钟域到慢时钟域

快时钟域到慢时钟域分两种情况:
1、允许采样丢失:直接采用同步器即可。
2、不允许采样丢失:原理是保证快时钟域的信号宽度满足一定的条件,使得慢时钟域有足够的时间采样到。
对于情况2有两种方法解决:①信号展宽+边沿检测②握手,且①比②要优先被选择。因为握手资源消耗较大,一般不用。

方法一

脉冲信号展宽+边沿检测,脉冲信号转换成电平信号再进行边沿检测

  • 电路图:
    在这里插入图片描述
  • 代码:(verilog是描述电路的语言,所以要心中有电路,代码就好写了)
module pulse_detect(
    input              clk_fast    , 
    input              clk_slow    ,   
    input              rst_n       ,
    input               data_in     ,
    output           dataout
);
  reg data_in_fast;
  reg [2:0] data_slow;
  //将脉冲信号在快时钟域展平为电平信号。即展宽脉冲信号。在两次脉冲信号之间为电平信号。
  always@(posedge clk_fast or negedge rst_n)begin
      if(!rst_n)
          data_in_fast<= 0;
      else
          data_in_fast<= data_in ? (~data_in_fast) : data_in_fast;
  end
  //将展宽的脉冲信号在慢时钟域打两拍,并检测边沿。
  always@(posedge clk_slow or negedge rst_n)begin
      if(!rst)
          data_slow <= 3'b0;
      else
          data_slow <= {data_slow[1:0],data_in_fast};
  end   
  
  assign dataout = data_slow[2] ^ data_slow[1]; 
endmodule

  • 波形
    在这里插入图片描述

方法二

握手+边沿

  • 电路图:
    在这里插入图片描述
  • 代码1:
module pulse_detect(
  input         clk_fast  , 
  input         clk_slow  ,   
  input         rst_n    ,
  input        data_in    ,

  output         dataout
);
    //握手方式
    reg fast_req;//fast时钟域的请求信号
    reg slow_ack;//slow时钟域的应答信号
    reg [2:0] slow_req;//slow时钟域的请求信号
    reg [2:0] fast_ack;//fast时钟域的应答信号
    
    //fast时钟域
    
    //将slow时钟域的应答信号打三拍,送到fast时钟域
    always@(posedge clk_fast or negedge rst_n)begin
        if(!rst_n)
            fast_ack <= 3'd0;
        else
            fast_ack <= {fast_ack[1:0],slow_ack};
    end
    
    //生成请求信号fast_req
    always@(posedge clk_fast or negedge rst_n)begin
        if(!rst_n)
            fast_req <= 0;
        else if(data_in)
            fast_req <= 1'b1;
        else
            //快时钟域中没有输入数据时
            //如果慢时钟域应答了,01x,则快时钟域此时不请求,否则,快时钟域的请求信号维持上一时钟的状态
            fast_req <= ((fast_ack[1]) & (~fast_ack[2])) ? 1'b0 : fast_req;        
    end
    
    //slow时钟域
    
    //将fast时钟域的请求信号打三拍,送到slow时钟域
    always@(posedge clk_slow or negedge rst_n)begin
        if(!rst_n)
            slow_req <= 0;
        else
            slow_req <= {slow_req[1:0],fast_req};
    end
    
    //生成应答信号slow_ack
    always@(posedge clk_slow or negedge rst_n)begin
        if(!rst_n)
            slow_ack <= 0;
        else if(slow_req[1] & (~slow_req[2])) 
            //如果快时钟域的请求信号由0变为1,01x,即发出请求信号,则慢时钟域进行应答
            slow_ack <= 1'b1;
        else
            //如果slow请求信号10x,即慢时钟域请求信号无效时,慢时钟域不应答
            //否则慢时钟域应答信号不变
            slow_ack <= (slow_req[2]&(~slow_req[1])) ? 1'b0 : slow_ack;
    end
    //当慢时钟域01x,发出请求信号时,输出为1.
    assign dataout = (~slow_req[2]) & (slow_req[1]);
    
endmodule
  • 代码2:
module Sync_Pulse (
                input  src_clk,
                input  dst_clk,
                input  rst_n,
                input  src_pulse,
   
                output  dst_pulse
                  );
  
    reg req_state_dly1, req_state_dly2,dst_req_state,src_sync_req;
    reg ack_state_dly1,src_sync_ack;
    wire dst_sync_ack;
     
    always @ (posedge src_clk or negedge rst_n) begin
            if (rst_n == 1'b0)
                src_sync_req <= 1'b0;
            else if (src_pulse)           
                src_sync_req <= 1'b1;
            else if (src_sync_ack)           
                src_sync_req <= 1'b0;
            else;
     end
    
   
    always @ (posedge dst_clk or negedge rst_n) begin
            if (rst_n == 1'b0)
            begin
                req_state_dly1 <= 1'b0;
                req_state_dly2 <= 1'b0;
                dst_req_state <= 1'b0;
            end else begin
                req_state_dly1 <= src_sync_req;
                req_state_dly2 <= req_state_dly1;        
                dst_req_state <= req_state_dly2;
             end
    end
    
    assign dst_sync_ack = req_state_dly2;
    
    always @ (posedge src_clk or negedge rst_n) begin
            if (rst_n == 1'b0) begin
                    ack_state_dly1 <= 1'b0;
                    src_sync_ack <= 1'b0;
            end
            else begin
                     ack_state_dly1 <= dst_sync_ack;
                     src_sync_ack <= ack_state_dly1;
            end
     end
 
    assign  dst_pulse =   dst_req_state & (~req_state_dly2);
 
endmodule

对上述代码增加同步失败的指示信号

module handshake_pulse_sync
(
        input src_clk , //source clock
        input src_rst_n, //source clock reset (0: reset)
        input src_pulse , //source clock pulse in
       
        output src_sync_fail , //source clock sync state: 1 clock pulse if sync fail.
        input dst_clk , //destination clock
        input dst_rst_n , //destination clock reset (0:reset)
        output dst_pulse //destination pulse out
);
        //INTER DECLARATION        
        wire dst_pulse ;
        wire src_sync_idle ;
        reg src_sync_fail ;
        reg src_sync_req ;
        reg src_sync_ack ;
        reg ack_state_dly1, ack_state_dly2 ;
        reg req_state_dly1, req_state_dly2 ;
        reg dst_req_state ;
        reg dst_sync_ack ;
              
        assign src_sync_idle = ~(src_sync_req | src_sync_ack );
        
        //report an error if src_pulse when sync busy ;
        always @(posedge src_clk or negedge src_rst_n) begin
            if(src_rst_n == 1'b0)
                    src_sync_fail <= 1'b0 ;
            else if (src_pulse & (~src_sync_idle))
                    src_sync_fail <= 1'b1 ;
            else
                    src_sync_fail <= 1'b0 ;
        end
        
        
        //set sync req if src_pulse when sync idle ;
        always @(posedge src_clk or negedge src_rst_n) begin
                if(src_rst_n == 1'b0)
                        src_sync_req <= 1'b0 ;
                else if (src_pulse & src_sync_idle)
                        src_sync_req <= 1'b1 ;
                else if (src_sync_ack)
                        src_sync_req <= 1'b0 ;
        end
                
        always @(posedge src_clk or negedge src_rst_n) begin
                if(src_rst_n == 1'b0) begin
                        ack_state_dly1 <= 1'b0 ;
                        ack_state_dly2 <= 1'b0 ;
                        src_sync_ack <= 1'b0 ;
                end
                else begin
                        ack_state_dly1 <= dst_sync_ack ;
                        ack_state_dly2 <= ack_state_dly1 ;
                        src_sync_ack <= ack_state_dly2 ;
                end
        end
        
        always @(posedge dst_clk or negedge dst_rst_n) begin
                if(dst_rst_n == 1'b0) begin
                        req_state_dly1 <= 1'b0 ;
                        req_state_dly2 <= 1'b0 ;
                        dst_req_state <= 1'b0 ;
                end
                else begin
                        req_state_dly1 <= src_sync_req ;
                        req_state_dly2 <= req_state_dly1 ;
                        dst_req_state <= req_state_dly2 ;
                end
        end
        
        //Rising Edge of dst_state generate a dst_pulse;
        assign dst_pulse = (~dst_req_state) & req_state_dly2 ;
        //set sync ack when src_req = 1 , clear it when src_req = 0 ;
        
        always @(posedge dst_clk or negedge dst_rst_n) begin
                if(dst_rst_n == 1'b0)
                        dst_sync_ack <= 1'b0;
                else if (req_state_dly2)
                        dst_sync_ack <= 1'b1;
                else
                        dst_sync_ack <= 1'b0;
        end
endmodule

电路分析:
将src时钟域的脉冲信号打一拍之后,在dst时钟域内打三拍进行同步,其中第二拍的结果作为dst时钟域的应答信号,第二拍和第三拍的结果做边沿检测,以保证在dst时钟域输出接收到的脉冲信号。

其中第二拍的应答信号,在src时钟域经过两级同步作为src的应答信号,当输入脉冲信号时,src的请求信号有效。当src的应答信号有效时,请求信号无效。

缺点:上述操作无法检测到脉冲连续输入时产生的错误,即无法检测同步失败。如:在当前脉冲信号同步过程中又发出了新的脉冲信号的情况。

快时钟域至少展宽脉冲宽度到大于慢时钟域的周期长度。

  • 4
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
处理时钟时钟的多bit信号跨时钟域问题时,有几种方法可以选择。其中一个常用的方法是使用同步器和边沿检测。 首先,使用同步器来将时钟的信号转换为时钟的信号。同步器可以确保在时钟中正确采样到时钟的信号。对于允许采样丢失的情况,只需要简地使用同步器即可。 然而,对于不允许采样丢失的情况,可以采用两种方法来解决。第一种方法是信号展宽边沿检测,这意味着在时钟的信号之前或之后添加一些额外的延时来确保在时钟中能够正确检测到边沿。这种方法相对简,但可能会引入一定的延迟。 第二种方法是使用握手。在这种情况下,时钟的信号在传输到时钟之前,需要进行握手操作以确保数据的正确性。然而,握手操作可能会消耗较大的资源,因此一般情况下不常使用。 综上所述,针对时钟时钟的多bit信号跨时钟域处理,常见的方法包括使用同步器和边沿检测。同步器可以将时钟的信号转换为时钟的信号,而边沿检测则可以在时钟的信号前后添加延时以保证在时钟中能够正确检测到边沿。这些方法可以根据具体的应用需求选择使用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【CDC跨时钟域信号处理bit_时钟时钟](https://blog.csdn.net/weixin_50952710/article/details/128204972)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [【CDC跨时钟域信号处理bit_时钟时钟](https://blog.csdn.net/weixin_50952710/article/details/128139489)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值