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

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

3天内不再提示

如何设计异步时钟之间的接口电路

FPGA之家 来源:fpga之家 作者:fpga之家 2022-11-15 09:29 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一、FIFO简介

FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,它与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。

用途1:

异步FIFO读写分别采用相互异步的不同时钟。在现代集成电路芯片中,随着设计规模的不断扩大,一个系统中往往含有数个时钟,多时钟域带来的一个问题就是,如何设计异步时钟之间的接口电路。异步FIFO是这个问题的一种简便、快捷的解决方案,使用异步FIFO可以在两个不同时钟系统之间快速而方便地传输实时数据。

用途2:

对于不同宽度的数据接口也可以用FIFO,例如单片机位8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。

二、分类

同步FIFO是指读时钟和写时钟为同一个时钟,在时钟沿来临时同时发生读写操作;

异步FIFO是指读写时钟不一致,读写时钟是互相独立的。

三、FIFO的常见参数

FIFO的宽度:即FIFO一次读写操作的数据位;

FIFO的深度:指的是FIFO可以存储多少个N位的数据(如果宽度为N)。

满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。

空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。

读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。

写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。

===============================分 隔 符 ==============================

读写指针的工作原理

读指针:总是指向下一个将要被写入的单元,复位时,指向第1个单元(编号为0)。

写指针:总是指向当前要被读出的数据,复位时,指向第1个单元(编号为0)

FIFO的“空”/“满”检测

FIFO设计的关键:产生可靠的FIFO读写指针和生成FIFO“空”/“满”状态标志。

当读写指针相等时,表明FIFO为空,这种情况发生在复位操作时,或者当读指针读出FIFO中最后一个字后,追赶上了写指针时,如下图所示:

当读写指针再次相等时,表明FIFO为满,这种情况发生在,当写指针转了一圈,折回来(wrapped around)又追上了读指针,如下图:

为了区分到底是满状态还是空状态,可以采用以下方法:

方法1:在指针中添加一个额外的位(extra bit),当写指针增加并越过最后一个FIFO地址时,就将写指针这个未用的MSB加1,其它位回零。对读指针也进行同样的操作。此时,对于深度为2n的FIFO,需要的读/写指针位宽为(n+1)位,如对于深度为8的FIFO,需要采用4bit的计数器,0000~1000、1001~1111,MSB作为折回标志位,而低3位作为地址指针。

如果两个指针的MSB不同,说明写指针比读指针多折回了一次;如r_addr=0000,而w_addr = 1000,为满。

如果两个指针的MSB相同,则说明两个指针折回的次数相等。其余位相等,说明FIFO为空;

3.二进制FIFO指针的考虑

将一个二进制的计数值从一个时钟域同步到另一个时钟域的时候很容易出现问题,因为采用二进制计数器时所有位都可能同时变化,在同一个时钟沿同步多个信号的变化会产生亚稳态问题。而使用格雷码只有一位变化,因此在两个时钟域间同步多个位不会产生问题。所以需要一个二进制到gray码的转换电路,将地址值转换为相应的gray码,然后将该gray码同步到另一个时钟域进行对比,作为空满状态的检测。

4.

使用gray码进行对比,如何判断“空”与“满”

使用gray码解决了一个问题,但同时也带来另一个问题,即在格雷码域如何判断空与满。

对于“空”的判断依然依据二者完全相等(包括MSB);

而对于“满”的判断,如下图,由于gray码除了MSB外,具有镜像对称的特点,当读指针指向7,写指针指向8时,除了MSB,其余位皆相同,不能说它为满。因此不能单纯的只检测最高位了,在gray码上判断为满必须同时满足以下3条:

wptr和同步过来的rptr的MSB不相等,因为wptr必须比rptr多折回一次。

wptr与rptr的次高位不相等,如上图位置7和位置15,转化为二进制对应的是0111和1111,MSB不同说明多折回一次,111相同代表同一位置。

剩下的其余位完全相等。

5.总体实现

系统的总体框图如下:

1)顶层模块

moduleAsyncFIFO

 #(parameter ASIZE = 4,    //地址位宽
   parameter DSIZE = 8)    //数据位宽
 (
    input  [DSIZE-1:0] wdata,
    input              winc, wclk, wrst_n,  //写请求信号,写时钟,写复位
    input              rinc, rclk, rrst_n,  //读请求信号,读时钟,读复位
    output [DSIZE-1:0] rdata,
    output             wfull,
    output             rempty
 );
wire [ASIZE-1:0] waddr, raddr;
wire [ASIZE:0]   wptr, rptr, wq2_rptr, rq2_wptr;        /************************************************************
* In order to perform FIFO full and FIFO empty tests using 
* this FIFO style, the read and write pointers must be
* passed to the opposite clock domain for pointer comparison
*************************************************************/
/*在检测“满”或“空”状态之前,需要将指针同步到其它时钟域时,使用格雷码,可以降低同步过程中亚稳态出现的概率*/
sync_r2w I1_sync_r2w(
    .wq2_rptr(wq2_rptr), 
    .rptr(rptr),
    .wclk(wclk), 
    .wrst_n(wrst_n));
sync_w2r I2_sync_w2r (
    .rq2_wptr(rq2_wptr), 
    .wptr(wptr),
    .rclk(rclk), 
    .rrst_n(rrst_n));
/*
*  DualRAM 
*/
DualRAM #(DSIZE, ASIZE) I3_DualRAM(
    .rdata(rdata), 
    .wdata(wdata),
    .waddr(waddr), 
    .raddr(raddr),
    .wclken(winc), 
    .wclk(wclk));
    
/*
*  空、满比较逻辑
*/
rptr_empty #(ASIZE) I4_rptr_empty(
    .rempty(rempty),
    .raddr(raddr),
    .rptr(rptr), 
    .rq2_wptr(rq2_wptr),
    .rinc(rinc), 
    .rclk(rclk),
    .rrst_n(rrst_n));
wptr_full #(ASIZE) I5_wptr_full(
    .wfull(wfull), 
    .waddr(waddr),
    .wptr(wptr), 
    .wq2_rptr(wq2_rptr),
    .winc(winc), 
    .wclk(wclk),
    .wrst_n(wrst_n));
endmodule

2)DualRAM模块

module DualRAM
#(
    parameter DATA_SIZE = 8,   // 数据位宽
    parameter ADDR_SIZE = 4   // 地址位宽
)
(
    input                       wclken,wclk,
    input      [ADDR_SIZE-1:0]  raddr,     //RAM read address
    input      [ADDR_SIZE-1:0]  waddr,     //RAM write address
    input      [DATA_SIZE-1:0]  wdata,    //data input
    output     [DATA_SIZE-1:0]  rdata      //data output
);    
localparam RAM_DEPTH = 1 << ADDR_SIZE;   //RAM深度 = 2^ADDR_WIDTH
        reg [DATA_SIZE-1:0] Mem[RAM_DEPTH-1:0];
        always@(posedge wclk)
begin
     if(wclken)
         Mem[waddr] <= wdata;
end
assign rdata =  Mem[raddr];
endmodule

3)同步模块

module sync_r2w 
#(parameter ADDRSIZE = 4)
(
    output reg [ADDRSIZE:0] wq2_rptr,
    input      [ADDRSIZE:0] rptr,
    input                       wclk, wrst_n
);
reg [ADDRSIZE:0] wq1_rptr;
always @(posedge wclk or negedge wrst_n)
    if (!wrst_n) 
        {wq2_rptr,wq1_rptr} <= 0;
    else 
        {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr};
endmodule

4)同步模块2

module sync_w2r 
#(parameter ADDRSIZE = 4)
(
    output reg  [ADDRSIZE:0] rq2_wptr,
    input         [ADDRSIZE:0] wptr,
    input         rclk, rrst_n
);        reg [ADDRSIZE:0] rq1_wptr;
always @(posedge rclk or negedge rrst_n)
    if (!rrst_n)
        {rq2_wptr,rq1_wptr} <= 0;
    else 
        {rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr};
endmodule

5)空判断逻辑

module rptr_empty 
#(parameter ADDRSIZE = 4)
(
    output reg rempty,
    output     [ADDRSIZE-1:0] raddr,
    output reg [ADDRSIZE :0]  rptr,
    input       [ADDRSIZE :0] rq2_wptr,
    input       rinc, rclk, rrst_n);


reg  [ADDRSIZE:0] rbin;
wire [ADDRSIZE:0] rgraynext, rbinnext;
wire  rempty_val;
//-------------------
// GRAYSTYLE2 pointer: gray码读地址指针
//-------------------
always @(posedge rclk or negedge rrst_n)
    if (!rrst_n) 
        begin 
            rbin <= 0;
            rptr <= 0;
        end
    else
        begin
            rbin <= rbinnext ; 
            rptr <= rgraynext;
        end
// gray码计数逻辑
assign rbinnext = !rempty ? (rbin + rinc) : rbin;
assign rgraynext = (rbinnext>>1) ^ rbinnext;      //二进制到gray码的转换
        assign raddr = rbin[ADDRSIZE-1:0];
//---------------------------------------------------------------
// FIFO empty when the next rptr == synchronized wptr or on reset
//---------------------------------------------------------------
/*
*   读指针是一个n位的gray码计数器,比FIFO寻址所需的位宽大一位
*   当读指针和同步过来的写指针完全相等时(包括MSB),说明二者折回次数一致,FIFO为空
*     
*/
assign rempty_val = (rgraynext == rq2_wptr);
        always @(posedge rclk or negedge rrst_n)
if (!rrst_n) 
    rempty <= 1'b1;
else 
    rempty <= rempty_val;
endmodule

6)满判断逻辑

module wptr_full 
#(
    parameter ADDRSIZE = 4
)
(
    output reg                wfull,
    output     [ADDRSIZE-1:0] waddr,
    output reg [ADDRSIZE :0]  wptr,
    input      [ADDRSIZE :0]  wq2_rptr,
    input                     winc, wclk, wrst_n);        

reg  [ADDRSIZE:0] wbin;
wire [ADDRSIZE:0] wgraynext, wbinnext;
wire wfull_val;
// GRAYSTYLE2 pointer
always @(posedge wclk or negedge wrst_n)
    if (!wrst_n) 
    begin
        wbin <= 0;
        wptr <= 0;
    end
    else 
    begin
        wbin <= wbinnext;
         wptr <= wgraynext;
    end
//gray 码计数逻辑    
assign wbinnext  = !wfull ? wbin + winc : wbin;
assign wgraynext = (wbinnext>>1) ^ wbinnext;
        assign waddr = wbin[ADDRSIZE-1:0];
        /*由于满标志在写时钟域产生,因此比较安全的做法是将读指针同步到写时钟域*/
/**/
//------------------------------------------------------------------
// Simplified version of the three necessary full-tests:
// assign wfull_val=((wgnext[ADDRSIZE] !=wq2_rptr[ADDRSIZE] ) &&
// (wgnext[ADDRSIZE-1] !=wq2_rptr[ADDRSIZE-1]) &&
// (wgnext[ADDRSIZE-2:0]==wq2_rptr[ADDRSIZE-2:0]));
//------------------------------------------------------------------
assign wfull_val = (wgraynext=={~wq2_rptr[ADDRSIZE:ADDRSIZE-1],
                    wq2_rptr[ADDRSIZE-2:0]});
always @(posedge wclk or negedge wrst_n)
if (!wrst_n) 
    wfull <= 1'b0;
else 
    wfull <= wfull_val;
endmodule

P.S : 在quartus中有异步FIFO IP核,为安全起见推荐使用IP核定制FIFO,本文的目的只是作为思路参考。

审核编辑:郭婷

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

    关注

    462

    文章

    53530

    浏览量

    458837
  • 存储器
    +关注

    关注

    39

    文章

    7714

    浏览量

    170797
  • fifo
    +关注

    关注

    3

    文章

    406

    浏览量

    45480

原文标题:异步FIFO的FPGA实现

文章出处:【微信号:zhuyandz,微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。

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

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    瑞萨RA系列FSP库开发实战指南(29)CGC(时钟生成电路时钟控制

      第13章 CGC——时钟控制   CGC CGC(Clock Generation Circuit):时钟生成电路 13.1 CGC模块简介 #CGC 全称是Clock Generation
    的头像 发表于 08-05 14:02 3095次阅读
    瑞萨RA系列FSP库开发实战指南(29)CGC(<b class='flag-5'>时钟</b>生成<b class='flag-5'>电路</b>)<b class='flag-5'>时钟</b>控制

    ADC和FPGA之间LVDS接口设计需要考虑的因素

    本文描述了ADC和FPGA之间LVDS接口设计需要考虑的因素,包括LVDS数据标准、LVDS接口数据时序违例解决方法以及硬件设计要点。
    的头像 发表于 07-29 10:01 5011次阅读
    ADC和FPGA<b class='flag-5'>之间</b>LVDS<b class='flag-5'>接口</b>设计需要考虑的因素

    AMD FPGA异步模式与同步模式的对比

    本文讲述了AMD UltraScale /UltraScale+ FPGA 原生模式下,异步模式与同步模式的对比及其对时钟设置的影响。
    的头像 发表于 07-07 13:47 1420次阅读

    USB串口芯片GP232RL替代FT232RL/uart 接口

    GP232r 是一个 usb 到串行 uart 接口,带有可选的时钟发生器输出,以及新的 ftdichip-idTM 安全加密器特性。此外,还提供了异步和同步位崩接口模式。 通过将外部
    发表于 06-23 10:12

    电容在时钟电路中的应用有哪些

    时钟电路精密的运行体系中,电容器扮演着不可或缺的角色。从净化信号到稳定传输,从调节频率到优化电源,电容以其独特的电气特性,在不同环节发挥关键作用。本文将深入解析电容在时钟电路中的用途
    的头像 发表于 05-05 15:55 866次阅读

    时钟电路的组成与设计要点介绍

    在数字电子系统的运行中,时钟电路掌控着各部件协同工作的节奏。它通常由时钟发生器、时钟分频器、时钟缓冲器等核心部分构成,这些组件各司其职,共同
    的头像 发表于 05-05 15:40 1262次阅读

    时钟电路与晶振电路两者的区别有哪些

    在数字电子系统设计中,时钟电路与晶振电路是两个高频出现的概念。虽然二者紧密相关且常被协同讨论,但从功能定位、电路构成到应用场景都存在本质差异。本文将从技术原理出发,系统解析两者的区别。
    的头像 发表于 05-05 15:19 1686次阅读

    中国集成电路大全 接口集成电路

    章内容,系统地介绍了接口集成电路及其七大类别,详细说明了每一类别所包括品种的特性、电路原理、参数测试和应用方法。因为接口集成电路的类别多,而
    发表于 04-21 16:33

    AD9576双通道PLL、异步时钟发生器技术手册

    AD9576具有多路输出时钟发生器功能,内置两个具有灵活频率转换功能的专用锁相环(PLL)内核,经过优化可用作整个系统的稳定异步时钟源,通过监控冗余晶体(XTAL)输入并实现这些输入之间
    的头像 发表于 04-09 18:14 920次阅读
    AD9576双通道PLL、<b class='flag-5'>异步</b><b class='flag-5'>时钟</b>发生器技术手册

    接口电路防护设计要点解析

    一、接口电路电路中与用户或者外界媒介进行交互的部分,是内部核心敏感电路和外部设备进行信息交互的桥梁。接口
    的头像 发表于 03-31 19:32 1785次阅读
    <b class='flag-5'>接口</b><b class='flag-5'>电路</b>防护设计要点解析

    SDRAM控制器的设计——Sdram_Control.v代码解析(异步FIFO读写模块、读写SDRAM过程)

    前言 SDRAM控制器里面包含5个主要的模块,分别是PLL模块,异步FIFO 写模块,异步FIFO读模块,SDRAM接口控制模块,SDRAM指令执行模块。 其中异步FIFO模块解读
    的头像 发表于 03-04 10:49 2173次阅读
    SDRAM控制器的设计——Sdram_Control.v代码解析(<b class='flag-5'>异步</b>FIFO读写模块、读写SDRAM过程)

    异步串行接口有哪些,异步串行接口为何需要波特率

    在现代电子通信领域,异步串行接口作为数据交换的一种基本方式,广泛应用于各种嵌入式系统、计算机设备以及远程通信网络中。本文将深入探讨异步串行接口的主要类型,并解析为何波特率在
    的头像 发表于 01-29 14:47 1568次阅读

    EE-209:ADSP-21161N SHARC处理器上的异步主机接口

    电子发烧友网站提供《EE-209:ADSP-21161N SHARC处理器上的异步主机接口.pdf》资料免费下载
    发表于 01-06 15:30 0次下载
    EE-209:ADSP-21161N SHARC处理器上的<b class='flag-5'>异步</b>主机<b class='flag-5'>接口</b>

    EE-213:Blackfin处理器通过异步存储器接口进行主机通信

    电子发烧友网站提供《EE-213:Blackfin处理器通过异步存储器接口进行主机通信.pdf》资料免费下载
    发表于 01-05 10:09 0次下载
    EE-213:Blackfin处理器通过<b class='flag-5'>异步</b>存储器<b class='flag-5'>接口</b>进行主机通信

    总线接口的类型与选择指南

    ) 类型:异步、全双工串口总线。 特性:有两根线,一根TXD用于发送,一根RXD用于接收。不需要时钟信号来同步传输,而是依赖于发送设备和接收设备之间预定义的配置。 I2C总线 类型:同步、半双工双向的两线式串口总线。 特性:由串
    的头像 发表于 12-31 10:06 2223次阅读