cdc跨时钟域处理-结绳握手法

参考文档

https://blog.csdn.net/u011412586/article/details/10009761

前言

对于信号需要跨时钟域处理而言,最重要的就是确保数据能稳定的传送到采样时钟域。

普通的cdc处理方法需要关注时钟域速度的异同,即分慢时钟域到快时钟域、快时钟域到慢时钟域、相位关系等问题,会让人瞬间爆炸。

那么,是否有一种相对稳定,又无需关注传送时钟域和接收时钟域两者时钟速度、相位关系的数据传递方式呢?

这里仿真验证握手结绳法,自己想的,不知道跟结绳法是不是一致的。。。。。。

思考方式为:要绝对的保证数据被接收,自然是握手应答机制。

流程

首先考虑亚稳态说明:对于异步信号的采集,不可避免的会有亚稳态,但亚稳态的恢复时间一般为1个时钟或者两个时钟,同样其不会是0、1的中间值,而是一个开发者无法确定的定值,同时你的时钟频率越高,亚稳态发生的概率就越大。

网上感觉都说的不明就里,对于简单的使用多级触发器,然后使用最高的2bit进行边沿检测,目测是不行的。

可以理解为仿真中的x值,但数字电路的本质上是有值的,要么0,要么1。

所以如果是检测一个信号的上升沿,即使采到亚稳态,那就分两种情况:

(1)边沿比较陡峭,时钟只采到1次亚稳态,那么边沿寄存器的值就可能为:00、01。检测到00,下一次就会采到01。如果是检测到01,就是想要的沿。

(2)边沿一点都不陡峭,导致时钟采到两次甚至更多次的亚问题,那这就没得玩了。因为你不知道当前是00\01\10\11,这就可能导致你的后续逻辑完蛋了。

当然这里第二种情况不予考虑,FPGA内部不太可能出现这么糟糕的上升沿,除非你的时钟过快,在时钟沿到来前,亚稳态还没有恢复过来。

极端的处理方式是(本质上是滤波):用更多位的寄存器,比如8bit,当检测到为8‘b0000_1111,那就是上升沿啦,虽然这阔以绝对可靠的检测到边沿,但检测出沿的所用的时间更长,同时需要保证前级信号的高低电平长度,否则就被滤波了。。。。。。

所以,信号的边沿陡峭性是很重要的,专业术语叫做:上升时间、下降时间。

言归正传,那么握手结绳法是咋样的操作呢?

如下图所示:有点复杂

如图所示,则操作流程为:上述方法应该是支持多bit数据跨时钟域的,这里的多bit说的是FPGA内部数据,pulse_clk1表示发送数据使能,clk1检测到使能则拉高pulse_delay_clk1开始结绳。在clk2中,检测到clk1中的结绳信号的上升沿则产生pulse_clk2,clk2检测到pulse_clk2则启动clk2中的结绳pulse_delay_clk2,在clk1中检测到clk2中的结绳信号为高则解掉clk1的结绳。在clk2中检测到clk1的结绳拉低,则解绳clk2中的结绳信号pulse_delay_clk2,完成传输。

待传送数据在clk2的结绳上升沿被采样。

busy信号为clk1中的信号,在clk1的发送数据使能到来则拉高,在pulse_delay_clk2的下降沿则拉低。

可以看到,这种方式只适合少量的慢速的数据传输。

源代码

`timescale 1ns/1ps
module cdc_test (
    input               i_clk1               ,
    input               i_clk2               ,
    // input               i_rst_n              ,
    input               i_en_clk1            ,
    input     [15:0]    i_data_clk1          ,
    output              o_busy_clk1          ,
    output              o_valid_clk2         ,
    output    [15:0]    o_data_clk2
);
////clk1
////clk1的发送使能边沿检测
reg [1:0] r_en_clk1_edge = 2‘b00;
always @(posedge i_clk1)
begin
    r_en_clk1_edge <= {r_en_clk1_edge[0],i_en_clk1};
end
reg r_en_clk2 = 1‘b0;////clk2的使能边沿检测
reg [1:0] r_en_clk2_edge = 2‘b00;
always @(posedge i_clk1)
begin
    r_en_clk2_edge <= {r_en_clk2_edge[0],r_en_clk2};
end
reg r_en_expand = 1‘b0; ////clk1的使能延长
always @(posedge i_clk1)
begin
    if (r_en_clk1_edge == 2‘b01)
        r_en_expand <= 1‘b1;
    else if (r_en_clk2_edge == 2‘b01)
        r_en_expand <= 1‘b0;
end
reg r_busy_clk1 = 1‘b0; ////传输忙碌指示,忙碌的时候clk1的数据不可发生改变
always @(posedge i_clk1)
begin
    if (r_en_clk1_edge == 2‘b01)
        r_busy_clk1 <= 1‘b1;
    else if (r_en_clk2_edge == 2‘b10)
        r_busy_clk1 <= 1‘b0;
end

////clk2
reg [1:0] r_en_expand_edge = 2‘b00; ////clk1的扩展后的使能边沿检测
always @(posedge i_clk2)
begin
    r_en_expand_edge <= {r_en_expand_edge[0],r_en_expand};
end

always @(posedge i_clk2) ////clk2中的使能
begin
    if (r_en_expand_edge == 2‘b01)
        r_en_clk2 <= 1‘b1;
    else if (r_en_expand_edge == 2‘b10)
        r_en_clk2 <= 1‘b0;
end

reg r_valid_clk2 = 1‘b0;
always @(posedge i_clk2)
begin
    if (r_en_expand_edge == 2‘b01) ////上升沿表示数据有效
        r_valid_clk2 <= 1‘b1;
    else
        r_valid_clk2 <= 1‘b0;
end
reg [15:0] r_data_clk2 = 16‘d0;
always @(posedge i_clk2)
begin
    if (r_en_expand_edge == 2‘b01) ////上升沿刷新数据
        r_data_clk2 <= i_data_clk1;
end

////信号输出

assign o_busy_clk1  = r_busy_clk1;
assign o_valid_clk2 = r_valid_clk2;
assign o_data_clk2  = r_data_clk2;

endmodule // end the cdc_test model

仿真看看。

可以看到数据正确传输,不管是快到慢还是慢到快。

以后再板级测试啦。

以上。

原文地址:https://www.cnblogs.com/kingstacker/p/11348025.html

时间: 2024-08-29 01:07:45

cdc跨时钟域处理-结绳握手法的相关文章

基于FPGA的跨时钟域信号处理——亚稳态(V3-FPGA学院)

(V3-FPGA学院教你学习FPGA) 基于FPGA的跨时钟域信号处理--亚稳态 基于FPGA的跨时钟域信号处理--亚稳态 什么是亚稳态? 所有数字器件(例如FPGA)的信号传输都会有一定的时序要求,从而保证每 个寄存器将捕获的输入信号正确输出.为了确保可靠的操作,输入寄存器的信号必须在时钟沿的某段时间(寄存器的建立时间Tsu)之前保持稳定,并且持续到时钟沿之后的某段时间(寄存器的保持时间Th)之后才能改变.而该寄存器的输入反映到输出则需要经过一定的延时(时钟到输出的时间Tco).如果数据信号的

跨时钟域的寄存器访问

在verilog中,如果对于一个寄存器可能同时有两个时钟clk对其进行操作,为了防止读写冲突,需要做如下简单处理 clk_f( fast时钟)和clk_s(slow时钟) clk_s对寄存器time_cnt进行写操作, clk_f对寄存器time_cnt进行读操作, 所以当clk_f边沿读取time_cnt的值得时候,time_cnt可能正是clk_s对寄存器写的时候,从而造成clk_f读错误 如下处理 reg time_cnt1,time_cnt2; always @(posedge clk_

跨时钟域信号处理

1.什么是跨时钟域? 如图所示: 缺点:数据传输不可靠 2.如何实现信号传输稳定? 设计最基本的思想就是同步. 看两篇文章:<(多图) 跨越鸿沟:同步世界中的异步信号>.<cpu与fpga跨时钟域数据交换的实现问题>

FPGA中亚稳态相关问题及跨时钟域处理

前言 触发器输入端口的数据在时间窗口内发生变化,会导致时序违例.触发器的输出在一段时间内徘徊在一个中间电平,既不是0也不是1.这段时间称为决断时间(resolution time).经过resolution time之后Q端将稳定到0或1上,但是稳定到0或者1,是随机的,与输入没有必然的关系. 触发器由于物理工艺原因,数据并不是理想化的只要触发沿时刻不变即可.触发器有固定的建立时间,保持时间. 建立时间:在时钟有效沿到来前数据需要稳定的时间. 保持时间:在时钟有效沿之后数据还需要保持不变的时间.

跨时钟域设计【二】——Fast to slow clock domain

跨时钟域设计中,对快时钟域的Trigger信号同步到慢时钟域,可以采用上面的电路实现,Verilog HDL设计如下:   // Trigger signal sync, Fast clock domain to slow domainmodule Trig_CrossDomain_F2S ( input clkB, input rst_n, input TrigIn_clkA,  output  reg TrigOut_clkB );  reg Q1,Q2,nQ2;  always @(pos

跨时钟域设计【一】——Slow to fast clock domain

跨时钟域设计是FPGA设计中经常遇到的问题,特别是对Trigger信号进行同步设计,往往需要把慢时钟域的Trigger信号同步到快时钟域下,下面是我工作中用到的慢时钟域到快时钟域的Verilog HDL设计.     // Trigger Cross Domain Design, Slow to fast clock domain  module Trig_ CrossDomain _S2F (      input clkB,      input rst_n,      input Trig

跨时钟域信号处理——专用握手信号

在逻辑设计领域,只涉及单个时钟域的设计并不多.尤其对于一些复杂的应用,FPGA往往需要和多个时钟域的信号进行通信.异步时钟域所涉及的两个时钟之间可能存在相位差,也可能没有任何频率关系,即通常所说的不同频不同相. 图1是一个跨时钟域的异步通信实例,发送域和接收域的时钟分别是clk_a和clk_b.这两个时钟频率不同,并且存在一定的相位差.对于接收时钟域而言,来自发送时钟域的信号data_a2b有可能在任何时刻变化. 图1 跨时钟域通信 对于上述的异步时钟域通信,设计者需要做特殊的处理以确保数据可靠

数字IC学习之五(综合、SVA以及跨时钟域设计)

我们来说说综合,通常意义上的综合指的是,将RTL风格的描述转化为逻辑网标,通俗点说,就是把你的代码转化成真实的电路,我们以EDA工具Design Compiler为例来说说如何进行综合,对于综合我推荐的资料为<Design Compiler User Guide>(synopsys)(书1),<Optimization Reference Manual>(synopsys)(书2),<高级ASIC芯片综合>(书3),<专用集成电路设计实用教程>(虞)(书4)

FPGA中信号的跨时钟域处理模板(一)

在做项目的时,我们经常会使用到多个时钟.每一个时钟在FPGA内部都会形成一个时钟域,如果一个时钟域中要用到另外一个时钟域的信号,也就形成了跨时钟域的操作,这时候要格外小心. 一.实际使用背景       假设在项目中需要在clk_b时钟域中用到用到来自clk_a中的信号.那么此信号就需要从clk_a时钟域跨越到clk_b中因此我们要建立一个同步计数器,该设计器从clk_a 中获取信号,然后再clk_b中创建一个新的信号.并从作为输出.模型如下: 在此设计中.我们假设输入的信号与clk_a和clk