跨时钟域脉冲信号处理——脉冲同步器

一、同步器——快时钟域到慢时钟域

脉冲同步器的基本原理:

  1. 将src_clk时钟域的输入脉冲转换为src_clk时钟域的电平信号src_state
  2. 对src_state电平信号进行打拍(打两拍)同步到dst_clk时钟域
  3. 对dst_clk时钟域的电平信号进行检测,产生dst_clk时钟域脉冲

电路如下:

在这里插入图片描述
代码如下:

module pulse_sync(src_clk, src_rst_n, src_pulse, dst_clk, dst_rst_n, dst_pulse);
  input       src_clk;         //source clock
  input       src_rst_n;       //source reset
  input       src_pulse;       //source pulse in

  input       dst_clk;         //destination clock
  input       dst_rst_n;       //destination reset
  output      dst_pulse;       //destination pulse out

//Internal singles
  reg      src_state;
  reg      state_delay1;
  reg      state_delay2;
  reg      dst_state;
  wire     dst_puase;

//==============MODULE MAIN CODE=========================
//1.输入脉冲转成电平信号,确保时钟B可以采到
  always@(posedge src_clk or negedge src_rst_n)begin
    if(src_rst_n==0)
      src_state <= 0;
    else if(src_pulse)
      src_state <= ~src_state;  
  end

//2.//源时钟域的src时钟下电平信号转成时钟dst下的脉冲信号
  always@(posedge dst_clk or negedge dst_rst_n)begin
    if(dst_rst_n)begin
      state_delay1 <= 0;
      state_delay2 <= 0;
      dst_state <= 0;
    end
    else begin
      state_delay1 <= src_state;
      state_delay2 <= state_delay1;
      dst_state <= state_delay2;
    end
  end

  assign dst_pulse = dst_state^state_delay2;

endmodule

二、握手——快时钟域到慢时钟域

   从上一部分的设计原理中,我们可以发现该同步器的控制传递是单向的,即仅从源时钟域到目的时钟域,目的时钟域并没有状态反馈。假设存在如下应用:

  • 源时钟域中的第一个脉冲和第二个脉冲间隔过短,第一个脉冲未完成同步,第二脉冲又将状态清空,导致最终脉冲同步丢失。

   要解决以上同步问题,需要引入异步握手机制,保证每个脉冲都同步成功,同步成功后再进行下一个脉冲同步。握手原理如下:

  • sync_req: 源时钟域同步请求信号,高电平表示当前脉冲需要同步;
  • sync_ack: 目的时钟域应答信号,高电平表示当前已收到同步请求;
    在这里插入图片描述
     完整同步过程分为以下4个步骤:

(1) 同步请求产生;当同步器处于空闲(即上一次已同步完成)时,源同步脉冲到达时产生同步请求信号sync_req;
  (2) 同步请求信号sync_req同步到目的时钟域,目的时钟域产生脉冲信号并将产生应答信号sync_ack;
  (3) 同步应答信号sync_ack同步到源时钟域,源时钟域检测到同步应答信号sync_ack后,清除同步请求信号;
  (4) 目的时钟域检测到sync_req撤销后,清除sync_ack应答;源时钟域将到sync_ack清除后,认为一次同步完成,可以同步下一个脉冲。

代码如下:

module HANDSHAKE_PULSE_SYNC
    (
        src_clk         , //source clock 
        src_rst_n       , //source clock reset (0: reset)
        src_pulse       , //source clock pulse in
        src_sync_fail   , //source clock sync state: 1 clock pulse if sync fail.
        dst_clk         , //destination clock 
        dst_rst_n       , //destination clock reset (0:reset)
        dst_pulse       //destination pulse out
    );
 
//PARA   DECLARATION


//INPUT  DECLARATION
input               src_clk     ; //source clock 
input               src_rst_n   ; //source clock reset (0: reset)
input               src_pulse   ; //source clock pulse in

input               dst_clk     ; //destination clock 
input               dst_rst_n   ; //destination clock reset (0:reset)

//OUTPUT DECLARATION
output              src_sync_fail   ; //source clock sync state: 1 clock pulse if sync fail.
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  ;
reg                 ack_state_dly2  ;
reg                 req_state_dly1  ;
reg                 req_state_dly2  ;
reg                 dst_req_state   ;
reg                 dst_sync_ack    ;

//--========================MODULE SOURCE CODE==========================--


//--=========================================--
// DST Clock :
// 1. generate src_sync_fail; 
// 2. generate sync req 
// 3. sync 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

//--=========================================--
// DST Clock :
// 1. sync src sync req 
// 2. generate dst pulse
// 3. generate sync ack
//--=========================================--
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

参考:https://www.cnblogs.com/digital-wei/p/6014450.html

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SD.ZHAI

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值