【CDC跨时钟域信号处理】快时钟域到慢时钟域-单bit
创始人
2024-03-23 11:19:36
0

快时钟域到慢时钟域分两种情况:
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)beginif(!rst_n)data_in_fast<= 0;elsedata_in_fast<= data_in ? (~data_in_fast) : data_in_fast;end//将展宽的脉冲信号在慢时钟域打两拍,并检测边沿。always@(posedge clk_slow or negedge rst_n)beginif(!rst)data_slow <= 3'b0;elsedata_slow <= {data_slow[1:0],data_in_reg};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)beginif(!rst_n)fast_ack <= 3'd0;elsefast_ack <= {fast_ack[1:0],slow_ack};end//生成请求信号fast_reqalways@(posedge clk_fast or negedge rst_n)beginif(!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)beginif(!rst_n)slow_req <= 0;elseslow_req <= {slow_req[1:0],fast_req};end//生成应答信号slow_ackalways@(posedge clk_slow or negedge rst_n)beginif(!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) beginif (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;endalways @ (posedge dst_clk or negedge rst_n) beginif (rst_n == 1'b0)beginreq_state_dly1 <= 1'b0;req_state_dly2 <= 1'b0;dst_req_state <= 1'b0;end else beginreq_state_dly1 <= src_sync_req;req_state_dly2 <= req_state_dly1;        dst_req_state <= req_state_dly2;endendassign dst_sync_ack = req_state_dly2;always @ (posedge src_clk or negedge rst_n) beginif (rst_n == 1'b0) beginack_state_dly1 <= 1'b0;src_sync_ack <= 1'b0;endelse beginack_state_dly1 <= dst_sync_ack;src_sync_ack <= ack_state_dly1;endendassign  dst_pulse =   dst_req_state & (~req_state_dly2);endmodule

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

module handshake_pulse_sync
(input src_clk , //source clockinput src_rst_n, //source clock reset (0: reset)input src_pulse , //source clock pulse inoutput src_sync_fail , //source clock sync state: 1 clock pulse if sync fail.input dst_clk , //destination clockinput 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) beginif(src_rst_n == 1'b0)src_sync_fail <= 1'b0 ;else if (src_pulse & (~src_sync_idle))src_sync_fail <= 1'b1 ;elsesrc_sync_fail <= 1'b0 ;end//set sync req if src_pulse when sync idle ;always @(posedge src_clk or negedge src_rst_n) beginif(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 ;endalways @(posedge src_clk or negedge src_rst_n) beginif(src_rst_n == 1'b0) beginack_state_dly1 <= 1'b0 ;ack_state_dly2 <= 1'b0 ;src_sync_ack <= 1'b0 ;endelse beginack_state_dly1 <= dst_sync_ack ;ack_state_dly2 <= ack_state_dly1 ;src_sync_ack <= ack_state_dly2 ;endendalways @(posedge dst_clk or negedge dst_rst_n) beginif(dst_rst_n == 1'b0) beginreq_state_dly1 <= 1'b0 ;req_state_dly2 <= 1'b0 ;dst_req_state <= 1'b0 ;endelse beginreq_state_dly1 <= src_sync_req ;req_state_dly2 <= req_state_dly1 ;dst_req_state <= req_state_dly2 ;endend//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) beginif(dst_rst_n == 1'b0)dst_sync_ack <= 1'b0;else if (req_state_dly2)dst_sync_ack <= 1'b1;elsedst_sync_ack <= 1'b0;end
endmodule

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

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

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

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

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...