#Verilog HDL# 跨时钟域电路设计之单bit信号(2)

前面提到了简单的双电平锁存器,下面是一些单bit同步电路。



一、慢时钟域 -> 快时钟域



边沿检测同步器:将慢时钟域的脉冲搬移并缩小为快时钟域的脉冲。

既可以检测上升沿,也可以检测下降沿。

如上图,慢时钟下一个有效脉冲的最短周期为慢时钟的一个周期,站在快时钟的角度下,这个慢时钟域的信号会在快时钟域下持续很多个周期。实际上,这个脉冲在慢时钟域只发生了一次,所以如果用快时钟去检查有效脉冲的翻转边沿是最准确的。边沿上升与下降也只有一次。

适用条件:data_width>clk_fast+T_hold,最安全的就是两个同步周期长度。这样才能保证慢时钟域的脉冲足够保持到被快时钟的同步器采样到。

其verilog代码如下:


————————————————

 二、快时钟域向慢时钟域

脉冲同步器:从快时钟域的取出一个单时钟宽度脉冲,在慢时钟域建立新的单时钟宽度脉冲

 图中阴影部分为快时钟域下的翻转电路。

由于在慢时钟域下直接采样快时钟域的信号,很大概率会采样失败。因此,我们采用翻转电路对有效脉冲进行标定。

适用条件:输入脉冲间隔>=2*clk_slow。输入脉冲相隔过近,则慢时钟域的新脉冲也紧密相邻,结果是输出脉冲比一个时钟周期宽;如果太近,则无法检测到每一个脉冲。

其verilog代码如下:


————————————————

针对此脉冲同步器出现的问题:源时钟域中的第一个脉冲和第二个脉冲间隔过短,第一个脉冲未完成同步,第二脉冲又将状态清空,导致最终脉冲同步丢失。我们引入握手机制进行解决,思路如下:

(1) 同步请求产生;当同步器处于空闲(即上一次已同步完成)时,源同步脉冲到达时产生同步请求信号sync_req;

(2) 同步请求信号sync_req同步到目的时钟域,目的时钟域产生脉冲信号并将产生应答信号sync_ack;

(3) 同步应答信号sync_ack同步到源时钟域,源时钟域检测到同步应答信号sync_ack后,清除同步请求信号;

(4) 目的时钟域检测到sync_req撤销后,清除sync_ack应答;源时钟域将到sync_ack清除后,认为一次同步完成,可以同步下一个脉冲。

verilog代码如下:

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


————————————————
版权声明:本文为CSDN博主「沧海一升」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_21842097/article/details/105472961

 三、对比

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值