0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

跨异步时钟域处理方法大全

FPGA设计论坛 ? 来源:FPGA设计论坛 ? 2025-05-14 15:33 ? 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

方法1 双触发器(打2拍)

该方法只用于慢到快时钟域的1bit信号传递。在Xilinx器件中,可以使用(* ASYNC_REG = "TRUE" *)标记,将两个寄存器尽量靠近综合,降低 亚稳态因导线延迟太大而传播到第二个寄存器的可能性。

moduleff2(  input clk0,//10Minput din,  input clk1,//100Moutputdout );  regdin_r=1'd0;   (* ASYNC_REG ="TRUE"*)  regr0=1'd0;   (* ASYNC_REG ="TRUE"*)  regr1=1'd0;  assigndout = r1;  always@(posedgeclk0)     din_r <= din;//由于不确定前级是否有触发器,这里默认加一级寄存,防止出现毛刺always@(posedge?clk1)begin? ? ?r0 ? ?<= din_r; ? ? ? ? r1 ? ?<= r0; ? ?endendmodule

方法2 双向握手 传递信号

双向握手方法使用了5个触发器,右边3个与方法1一致。左边两个用于将确认信号同步到写时钟域。用户必须将信号保持到确认信号置高。
该方法适用于慢到快快到慢1bit信号传递,一般而言,信号有效值为高电平。

c44907a8-2c8d-11f0-9310-92fbcf53809c.png
可以用一个非门、一个异或门、一个与门,和一个触发器(下图中的reg-2)实现信号保持,输入低速单脉冲,但是不保证输出单脉冲,可以在输出端加一个寄存器,用于上升沿判断.
c45bc8b6-2c8d-11f0-9310-92fbcf53809c.png
verilog可以用一些简单的判断来保持信号。下面是一个单向信号异步桥,支持单脉冲输入,单脉冲输出,时钟速率无限制
使用时,确保在active置低时,将s_vld给异步桥。

/* *  Name : 单向信号异步桥 *  Origin: 230406 *  EE  : hel */modulesignalbridge_async(  inputwire        s_clk  ,  inputwire        s_rstn ,  inputwire        s_vld  ,// pulse inputinputwire        d_clk  ,  inputwire        d_rstn ,  outputreg        d_vld  ,// pulse outputoutputwire        active  );reg[1 :0] s_syncer ;reg[1 :0] d_syncer ;wire    ack_d2 = s_syncer[1];wire    req_d2 = d_syncer[1];  reg     req_d3;reg     async_req;wire    async_ack = req_d2;assign   active = async_req | ack_d2 ;// Source clock domainalways@(posedges_clkornegedges_rstn)beginif(!s_rstn)begin    s_syncer  <=?2'd0; ? ?endelsebegin? ? ? ? ?s_syncer ? <= ?{s_syncer[0],async_ack}; ? ?endendalways?@(posedge?s_clk?ornegedge?s_rstn)?beginif?(!s_rstn)?begin? ? ? ? ?async_req ? <=?1'd0; ? ?endelseif(ack_d2)begin? ? ? ? ?async_req ? <=?1'd0; ? ?endelseif(s_vld)begin? ? ? ? ?async_req ? <=?1'd1; ? ?endend// Destination clock domainalways?@(posedge?d_clk?ornegedge?d_rstn)?beginif?(!d_rstn)?begin? ? ? ? ?d_syncer ? <=?2'd0; ? ?endelsebegin? ? ? ? ?d_syncer ? <= ?{d_syncer[0],async_req}; ? ?endendalways?@(posedge?d_clk?ornegedge?d_rstn)?beginif?(!d_rstn)?begin? ? ? ? ?req_d3 ? ? ?<=?1'd0; ? ? ? ? d_vld ? ? ? <=?1'd0; ? ?endelsebegin? ? ? ? ?req_d3 ? ? ?<= req_d2; ? ? ? ? d_vld ? ? ? <= req_d2 & (~req_d3); ? ?endendendmodule

方法3 双向握手 传递数据

可以使用请求信号采样跨时钟域过来的多比特数据,就可以做到数据的跨时钟域了(数据跨时钟域,频率低到高,高到低)如下图:

c46cca8a-2c8d-11f0-9310-92fbcf53809c.png
图里没有画反馈信号,数据需要在目的时钟采样时保持稳定。这种单个数据跨时钟域传输的编写流程如下:

原时钟域置高req,置好data

目的时钟域将req打两拍变成req_d2

目的时钟域检测到req_d2置高,将data打到寄存器内,并将ack置高

原时钟域检测到ack_d2被置高,拉低req

目的时钟域检测到req_d2被拉低,将ack拉低

通过上述流程编写的数据异步桥如下:
支持单个数据输入输出,时钟速率无限制。使用时,确保在active置低时,将s_din和s_vld给异步桥,s_vld必须为单脉冲。

/* *  Name : 单向数据异步桥 *  Origin: 230404 *  EE  : hel */moduledatabridge_async #(  parameterDW =8)(  inputwire        s_clk  ,  inputwire        s_rstn ,  inputwire  [DW-1:0]  s_din  ,  inputwire        s_vld  ,// pulse inputinputwire        d_clk  ,  inputwire        d_rstn ,  outputreg  [DW-1:0]  d_dout ,  outputreg        d_vld  ,// pulse outputoutputwire        active  );reg[1 :0] s_syncer ;reg[1 :0] d_syncer ;wire    ack_d2 = s_syncer[1];wire    req_d2 = d_syncer[1];  reg     req_d3;reg[DW-1:0] async_dat;reg     async_req;wire    async_ack = req_d2;assign   active = async_req | ack_d2 ;// Source clock domainalways@(posedges_clkornegedges_rstn)beginif(!s_rstn)begin    s_syncer  <=?2'd0; ? ?endelsebegin? ? ? ? ?s_syncer ? <= ?{s_syncer[0],async_ack}; ? ?endendalways?@(posedge?s_clk?ornegedge?s_rstn)?beginif?(!s_rstn)?begin? ? ? ? ?async_dat ? <= {DW{1'd0}}; ? ?endelseif(s_vld && (!active))begin? ? ? ? ?async_dat ? <= ?s_din; ? ?endendalways?@(posedge?s_clk?ornegedge?s_rstn)?beginif?(!s_rstn)?begin? ? ? ? ?async_req ? <=?1'd0; ? ?endelseif(ack_d2)begin? ? ? ? ?async_req ? <=?1'd0; ? ?endelseif(s_vld)begin? ? ? ? ?async_req ? <=?1'd1; ? ?endend// Destination clock domainalways?@(posedge?d_clk?ornegedge?d_rstn)?beginif?(!d_rstn)?begin? ? ? ? ?d_syncer ? <=?2'd0; ? ?endelsebegin? ? ? ? ?d_syncer ? <= ?{d_syncer[0],async_req}; ? ?endendalways?@(posedge?d_clk?ornegedge?d_rstn)?beginif?(!d_rstn)?begin? ? ? ? ?d_dout ? ? ?<= {DW{1'd0}}; ? ?endelseif(req_d2)begin? ? ? ? ?d_dout ? ? ?<= async_dat; ? ?endendalways?@(posedge?d_clk?ornegedge?d_rstn)?beginif?(!d_rstn)?begin? ? ? ? ?req_d3 ? ? ?<=?1'd0; ? ? ? ? d_vld ? ? ? <=?1'd0; ? ?endelsebegin? ? ? ? ?req_d3 ? ? ?<= req_d2; ? ? ? ? d_vld ? ? ? <= req_d2 & (~req_d3); ? ?endendendmodule

testbench:

`timescale1ns/1psmoduledatabridge_async_tb ();parameterDW =8;regs_clk =0;regs_rstn =0;reg[DW-1:0] s_din =0;regs_vld =0;regd_clk =0;regd_rstn =0;wire[DW-1:0] d_dout;wired_vld;wireactive;reg[DW-1:0]buffer ;realts;realtd;reala;realb;realclkstp;always#(ts) s_clk <= ~s_clk;always#(td)? d_clk <= ~d_clk; databridge_async?#(DW)?databridge_async ( ? ?.s_clk? ?( s_clk ?), ? ?.s_rstn? ( s_rstn ), ? ?.s_din? ?( s_din ?), ? ?.s_vld? ?( s_vld ?), ? ?.d_clk? ?( d_clk ?), ? ?.d_rstn? ( d_rstn ), ? ?.d_dout? ( d_dout ), ? ?.d_vld? ?( d_vld ?), ? ?.active? ( active ) );taskautomatic?gen_trans;input?[DW-1:0]data;begin? ? ?#0? ? ?s_vld ?= ?1; ? ? s_din ?= data; ? ? @(posedge?s_clk); ? ? #0? ? ?s_vld ?= ?0; ? ? s_din ?= ?0;endendtask//automatictaskautomatic?wait_busy;begin? ? ?@(posedge?s_clk);#0; ? ?while?(active)?begin? ? ? ? ?@(posedge?s_clk);#0; ? ?endendendtask//automatictaskautomatic?loop_test;inputinteger?n;integer?i;reg?[63:0]random_dat;beginfor?(i =?0;i

方法4 转为独热码或格雷码

如果多bit信号是简单连续变化(连续加一或减一),可以将其转为格雷码,再打2拍到目标时钟域,最终再解码为二进制编码。

如果多bit信号没有变化规律,可以将其转为独热码,再打2拍到目标时钟域,最终再解码为二进制编码。该方法适用于慢到快多bit信号传递。

为什么data不能直接通过同步器过域:
c478739e-2c8d-11f0-9310-92fbcf53809c.jpg
多比特数据由于存在传输路径延迟,到达同步器有先后顺序,导致同步器采样到不同电平,输出错误数据。
根本原因是源端数据有多个bit发生跳变。如果每次只有一个bit跳变(连续变化格雷码、独热码),就一定能采样到正确的数据。
假如目的时钟非常慢,比原时钟慢很多,在慢时钟上升沿时还是能采到正确数据,可能采到跳变之前的也可能是之后的,但总之都是source的数据。如果采到跳变之前的数据,就会产生异步FIFO的虚空虚满。从这个角度看,异步FIFO是绝对安全的(忽略同步器失效),异步FIFO两边的时钟频率没有任何要求。

方法5 深度为2的ASYNC-FIFO

在传输信号,不需要较高带宽时,可以将普通格雷码异步FIFO特化为2-deep ASYNC-FIFO,该方法适用于慢到快快到慢多bit信号传递。一般很少使用2deep-FIFO,而是使用双向握手来传递单个多比特数据。
c4822e0c-2c8d-11f0-9310-92fbcf53809c.png

方法6 ASYNC-FIFO

该方法适用于慢到快快到慢多bit数据传递。

moduleasync_fifo//(First_Word_Fall_Through FIFO,数据提前输出,可能不利于时序收敛)#(  parameterintegerDATA_WIDTH =16,  parameterintegerADDR_WIDTH =8//深度只能是2**ADDR_WIDTH) (  inputwire        wr_rst ,    inputwire        wr_clk ,    inputwire        wr_ena ,    inputwire[DATA_WIDTH-1:0] wr_dat ,   outputwire        wr_full ,  inputwire        rd_rst ,   inputwire        rd_clk ,    inputwire        rd_ena ,    outputwire[DATA_WIDTH-1:0] rd_dat ,   outputwire        rd_empty );reg [DATA_WIDTH-1:0]mem[0:2**ADDR_WIDTH-1];reg [ADDR_WIDTH :0]wrptr;reg [ADDR_WIDTH :0]rdptr;wire[ADDR_WIDTH-1:0]wraddr = wrptr[ADDR_WIDTH-1:0];wire[ADDR_WIDTH-1:0]rdaddr = rdptr[ADDR_WIDTH-1:0];wire[ADDR_WIDTH :0]wrptr_gray = (wrptr>>1)^wrptr;wire[ADDR_WIDTH :0]rdptr_gray = (rdptr>>1)^rdptr;reg [ADDR_WIDTH :0]wrptr_gray_r0;reg [ADDR_WIDTH :0]wrptr_gray_r1;reg [ADDR_WIDTH :0]rdptr_gray_r0;reg [ADDR_WIDTH :0]rdptr_gray_r1;assignwr_full = (wrptr_gray == {~rdptr_gray_r1[ADDR_WIDTH:ADDR_WIDTH-1],rdptr_gray_r1[ADDR_WIDTH-2:0]});assignrd_empty = (rdptr_gray == wrptr_gray_r1);//在有些设计中,full和empty提早一个时钟出现,并加了一级寄存,这有助于收敛always@(posedgewr_clkorposedgewr_rst)beginif(wr_rst)begin    rdptr_gray_r0 <=?'d0; ? ? ? ? rdptr_gray_r1 <=?'d0; ? ?endelsebegin? ? ? ? ?rdptr_gray_r0 <= rdptr_gray; ? ? ? ? rdptr_gray_r1 <= rdptr_gray_r0; ? ?endendalways?@(posedge?rd_clk?orposedge?rd_rst)?beginif?(rd_rst)?begin? ? ? ? ?wrptr_gray_r0 <=?'d0; ? ? ? ? wrptr_gray_r1 <=?'d0; ? ?endelsebegin? ? ? ? ?wrptr_gray_r0 <= wrptr_gray; ? ? ? ? wrptr_gray_r1 <= wrptr_gray_r0; ? ?endendalways?@(posedge?wr_clk?orposedge?wr_rst)?beginif?(wr_rst)?begin? ? ? ? ?mem[0] ? ? ?<=?'d0; ? ? ? ? wrptr ? ? ? <=?'d0; ? ?endelseif?(wr_ena&&(!wr_full))?begin? ? ? ? ?mem[wraddr] <= wr_dat; ? ? ? ? wrptr ? ? ? <= wrptr +?1'd1; ? ?endelsebegin? ? ? ? ?mem[wraddr] <= mem[wraddr]; ? ? ? ? wrptr ? ? ? <= wrptr; ? ?endendalways?@(posedge?rd_clk?orposedge?rd_rst)?beginif?(rd_rst)?begin? ? ? ? ?rdptr ? ? ? <=?'d0; ? ?endelseif?(rd_ena&&(!rd_empty))?begin? ? ? ? ?rdptr ? ? ? <= rdptr +?1'd1; ? ?endelsebegin? ? ? ? ?rdptr ? ? ? <= rdptr; ? ?endendassign?rd_dat = mem[rdaddr];endmodule

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    31

    文章

    5440

    浏览量

    124964
  • Xilinx
    +关注

    关注

    73

    文章

    2185

    浏览量

    125728
  • 触发器
    +关注

    关注

    14

    文章

    2041

    浏览量

    62235
  • 时钟域
    +关注

    关注

    0

    文章

    53

    浏览量

    9809

原文标题:跨异步时钟域的6种方法

文章出处:【微信号:gh_9d70b445f494,微信公众号:FPGA设计论坛】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    关于时钟信号的处理方法

    我在知乎看到了多bit信号时钟的问题,于是整理了一下自己对于时钟信号的处理
    的头像 发表于 10-09 10:44 ?7226次阅读

    如何处理好FPGA设计中时钟问题?

    以手到擒来。这里介绍的三种方法时钟处理方法如下:打两拍;
    发表于 09-22 10:24

    探寻FPGA中三种时钟处理方法

    以手到擒来。这里介绍的三种方法时钟处理方法如下:打两拍;
    发表于 10-20 09:27

    三种时钟处理方法

    的三种方法时钟处理方法如下:  1. 打两拍;  2.
    发表于 01-08 16:55

    三种FPGA界最常用的时钟处理法式

    时钟处理方法如下:打两拍;异步双口RAM;格雷码转换。01方法一:打两拍大家很清楚,
    发表于 02-21 07:00

    FPGA初学者的必修课:FPGA时钟处理3大方法

    时钟处理方法如下:打两拍;异步双口RAM;格雷码转换。01方法一:打两拍大家很清楚,
    发表于 03-04 09:22

    如何处理好FPGA设计中时钟间的数据

    介绍3种时钟处理方法,这3种方法可以说是FPGA界最常用也最实用的
    发表于 07-29 06:19

    FPGA界最常用也最实用的3种时钟处理方法

    介绍3种时钟处理方法,这3种方法可以说是FPGA界最常用也最实用的
    发表于 11-15 20:08 ?1.4w次阅读

    cdc路径方案帮您解决时钟难题

    这一章介绍一下CDC也就是时钟可能存在的一些问题以及基本的时钟
    的头像 发表于 11-30 06:29 ?7653次阅读
    cdc路径方案帮您解决<b class='flag-5'>跨</b><b class='flag-5'>时钟</b><b class='flag-5'>域</b>难题

    如何解决异步FIFO时钟亚稳态问题?

    时钟的问题:前一篇已经提到要通过比较读写指针来判断产生读空和写满信号,但是读指针是属于读时钟的,写指针是属于写
    的头像 发表于 09-05 14:29 ?6385次阅读

    揭秘FPGA时钟处理的三大方法

    时钟处理方法,这三种方法可以说是 FPGA 界最常用也最实用的
    的头像 发表于 12-05 16:41 ?2010次阅读

    介绍3种方法时钟处理方法

    介绍3种时钟处理方法,这3种方法可以说是FPGA界最常用也最实用的
    的头像 发表于 09-18 11:33 ?2.3w次阅读
    介绍3种<b class='flag-5'>方法</b><b class='flag-5'>跨</b><b class='flag-5'>时钟</b><b class='flag-5'>域</b><b class='flag-5'>处理</b><b class='flag-5'>方法</b>

    三种时钟处理方法

    时钟处理是FPGA设计中经常遇到的问题,而如何处理
    的头像 发表于 10-18 09:12 ?9187次阅读

    时钟电路设计总结

    时钟操作包括同步时钟操作和异步
    的头像 发表于 05-18 09:18 ?1056次阅读
    <b class='flag-5'>跨</b><b class='flag-5'>时钟</b><b class='flag-5'>域</b>电路设计总结

    FPGA时钟处理方法(二)

    上一篇文章已经讲过了单bit时钟处理方法,这次解说一下多bit的
    的头像 发表于 05-25 15:07 ?1350次阅读
    FPGA<b class='flag-5'>跨</b><b class='flag-5'>时钟</b><b class='flag-5'>域</b><b class='flag-5'>处理</b><b class='flag-5'>方法</b>(二)