嵌入式FIFO核的调用

摘要:
FIFO,即先进先出存储器,是FPGA中使用的具有先进先出特性的存储器,常用作数据缓存或高速异步数据交互。在双时钟FIFO的符号图中,所有与写入有关的信号都位于上部,所有与读取有关的信号均位于中部,异步复位信号位于下部。这两个FIFOs根据其不同用途在不同的地方使用。

 本次设计源码下载地址:http://download.csdn.net/detail/noticeable/9915523

课程目标:学习调用quartus II 软件的FIFO(先进先出)IP核,并通过仿真,了解其时序。

实验现象:通过quartus II 调用FIFO IP核,并进行不同形式的配置,通过仿真验证其接口时序。

知识点:FIFO IP核的使用。

    FIFO是什么?有什么用?

    FIFO 即先进先出存储器,是一个在FPGA中使用到的具有先进先出特性的一个存储器,其常被用来作为数据的缓存或者高速异步数据的交互。

     FIFO可分为两种结构:单时钟FIFO(SCFIFO)和双时钟FIFO(DCFIFO),其中双时钟FIFO 又可分为普通时钟(DCFIFO)和混合宽度时钟FIFO(DCFIFO_MIXED_WIDTHS).。

两种结构的时钟的符号图如下所示:

嵌入式FIFO核的调用第1张嵌入式FIFO核的调用第2张

关于各接口的引脚说明可以在上传到压缩包中查看官方文档,这里不再缀述 。

从结构图可以看出

  单时钟FIFO具有一个独立的时钟端口clock,因此所有输入信号的读取都是在clock的上升沿进行的,所有输出信号的变化也是在clock信号的上升沿的控制下进行的1,即单时钟FIFO的所有输入输出信号都是同步于clock信号的。

  在双时钟FIFO结构中,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写时钟wrclk的,所有与读相关的信号都是同步于读时钟rdclk的。在双时钟FIFO的符号图中,位于上部分的为与写相关的所有信号,位于中间部分的为与读相关的所有信号,位于下部的为异步清零信号。

     其中根据两种FIFO 各种的用处不同,使用的地点也不同。‘

单时钟FIFO:

  单时钟FIFO常用于片内数据交互,例如,在FPGA的控制下从外部传感器读取到的一连串传感器数据,首先被写入FIFO中,然后再以UART串口的数据发送速率将数据依次发送出去。由于传感器的单次读取数据可能很快,但并不是时刻都需要采集数据,例如某传感器使用SPI接口的协议,FPGA2MSPI数据速率从该传感器中读取20个数据,然后以9600的波特率通过串口发送出去。此过程每秒钟执行一次。因为2M的数据速率远高于串口9600的波特率,因此需要将从传感器中采集到的数据首先用FIFO缓存起来,然后再以串口的数据速率缓慢发送出去。这里,由于传感器数据的读取和串口数据的发送都是可以同步于同一个时钟的,因此可以使用单时钟结构的FIFO来实现此功能。

双时钟FIFO:

    双时钟FIFO的一个典型应用就是异步数据的收发。

    所谓异步数据是指数据的发送端和接收端分别同步与不同的时钟域,使用双时钟FIFO的独立的读写时钟结构,能够将不同时钟域中的数据同步到所需的时钟域系统中。例如,在一个高速数据采集系统中,实现将高速ADC采集的数据通过千兆以太网发送到PC机。ADC的采样时钟(CLK1)由外部专用锁相环芯片产生,则高速ADC采样得到的数据就是同步于该时钟信号的,在FPGA内部,如果FPGA工作时钟(CLK2)是由独立的时钟芯片加片上锁相环产生的CLK1CLK2就是两个不同域的时钟,他们的频率和相位没有必然的联系,假如CLK165MCLK2125M,那么就不能使用125M的数据来直接采集65M速率的数据,因为两者数据速率不匹配,在采集过程中会出现包括亚稳态问题在内的一系列问题,所以这里就可以使用一个具备双时钟结构的FIFO来进行异步数据的收发。

下图为使用FIFO进行异步数据收发的简易系统框图:

嵌入式FIFO核的调用第3张

基于千兆以太网传输的高速数据采集(8bit)系统

 

   在此系统中,由于ADC的数据位宽为8位,基于UDP协议的以太网发送模块所需的数据也是8位,因此使用的是非混合宽度的双时钟FIFO结构。假如CLK1的频率为20MADC的数据位宽为16位,则可以使用混合宽度的双时钟FIFO,在实现异步时钟域数据收发的同时,实现数据位宽的转换。通过设置双时钟FIFO的写入位宽为16位,读取位宽为8位,则可以实现将16位的ADC数据转换为以太网支持的8位发送数据,然后通过以太网发送到PC机。

总而言之:FIFO在系统中是作为缓冲器存在的一种状态,其根据缓冲的需求不同选择不同机构的fifo,从而使两个或多个不同采样率的数据可以进行数据的交互。

FIFO的设计方法:

Altera FPGA中使用FIFO实现用户功能设计主要有三种实现方式,第一种为用户根据需求自己编写FIFO逻辑,当用户对于FIFO的功能有特殊需求时,可以使用此种方式实现,但此种方式要求用户有较高的RTL设计能力。第二种方式为使用第三方提供的开源IP核,此种IP核以源码的形式提供,能够快速的应用到用户系统中,当用户对FIFO功能有特殊需求时,可以在此源码的基础上进行修改,以适应自己的系统需求。第三种方式为使用Quartus II软件提供的免费FIFO IP核,此种方式下,Quartus II软件为用户提供了友好的图形化界面方便用户对FIFO的各种参数和结构进行配置,生成的FIFO IP核针对Altera不同系列的器件,还可以实现结构上的优化。该FIFO IP核也是通过Verilog语言进行描述的,在Quartus II13.0软件中,该IP核源码存放于Quartus II软件安装目录quartusedasim_lib下的altera_mf.v文件中的第48189行(scfifo(dcfifo结构较多,因此代码内容很多,与之相关的代码有几千行,大家可以在文件中搜索dcfifo即可找到)。由于该FIFO IP核已经提供了几乎我们设计所需的所有功能,因此在系统设计中,推荐使用该FIFO IP核进行系统设计。

设计步骤:

新建porject ,打开megawizard plug-in manager,选择FIFO IP核

嵌入式FIFO核的调用第4张嵌入式FIFO核的调用第5张

嵌入式FIFO核的调用第6张嵌入式FIFO核的调用第7张

 嵌入式FIFO核的调用第8张之后直接next到finish即可。

下面对于IP核的时序接口进行仿真验证:

 编写testbench文件

`timescale 1ns/1ps
`define clock_peride 20
module fifo_tb;
                                                reg              clk;//时钟信号接口
                                                reg            [15:0]  data;//输入数据接口
                                                reg              rdreq;//读请求
                                                reg              sclr;//同步清零
                                                reg              wrreq;//写请求
                                                wire      almost_empty;//将空信号
                                                wire      almost_full;//将满信号
                                                wire      empty;//空信号 
                                                wire      full;//满信号
                                                wire    [15:0]  q;//输出接口
                                                wire    [7:0]  usedw;//可用数据
            fifo                     fifo1 (
                                                    .clock(clk),
                                                    .data(data),
                                                    .rdreq(rdreq),
                                                    .sclr(sclr),
                                                    .wrreq(wrreq),
                                                    .almost_empty(almost_empty),
                                                    .almost_full(almost_full),
                                                    .empty(empty),
                                                    .full(full),
                                                    .q(q),
                                                    .usedw(usedw)
                                                    );


                                    initial clk=1;
                                    always#(`clock_peride/2)  clk=~clk;
                                    integer i;
                                    
                                        initial begin 
                                        wrreq=0;
                                        rdreq=0;
                                        data=0;
                                        #(`clock_peride*20+1);
                                            for(i=0;i<=255;i=i+1)            //写操作
                                            begin 
                                            wrreq=1;
                                            data=i;
                                            #(`clock_peride);
                                            end 
                                            wrreq=0;
                                            #(`clock_peride*20);
                                                for(i=0;i<=255;i=i+1)                    //读操作
                                            begin 
                                            rdreq=1;
                                            #(`clock_peride);
                                            end 
                                            $stop;
                                        end
endmodule

设置仿真文件路径,点击仿真进行前仿,仿真结果如下,可以通过仿真了解各接口的作用及FIFO的读写操作。

嵌入式FIFO核的调用第9张

嵌入式FIFO核的调用第10张

 下面继续创建一个双时钟FIFO,并进行仿真

嵌入式FIFO核的调用第11张嵌入式FIFO核的调用第12张

 嵌入式FIFO核的调用第13张

 嵌入式FIFO核的调用第14张

之后next 到finish

编写dc_fifo_tb文件对IP核文件进行仿真

`timescale 1ns/1ps
`define wrclock_peride 20
`define rdclock_peride 10
                            module dc_fifo_tb;
                            reg    [15:0]  data; //输入数据    
                            reg      rdclk;                //读时钟
                            reg      rdreq;            //读请求
                            reg      wrclk;                //写时钟
                            reg      wrreq;            //写请求
                            wire    [7:0]  q;        //输出开口
                            wire      rdempty;        //读空
                            wire      wrfull;                //写满
                            
                                dc_fifo                dc_fifo1 (
                                                                                .data(data),
                                                                                .rdclk(rdclk),
                                                                                .rdreq(rdreq),
                                                                                .wrclk(wrclk),
                                                                                .wrreq(wrreq),
                                                                                .q(q),
                                                                                .rdempty(rdempty),
                                                                                .wrfull(wrfull)
                                                                                    );



                                                                            initial wrclk = 1;
                                    always #(`wrclock_peride/2) wrclk = ~wrclk;
                                    
                                    initial rdclk = 1;
                                    always #(`rdclock_peride/2)  rdclk = ~rdclk;
                                                    integer i;
                                                            
                                                                initial begin 
                                                                data=0;
                                                                rdreq=0;
                                                                wrreq=0;
                                                                #(`wrclock_peride*20+1)
                                                                for (i=0;i <= 255 ;i = i + 1)begin
                                                                    wrreq = 1;
                                                                    data = i + 1024;
                                                                    #`wrclock_peride;
                                                                end
                                                                wrreq = 0;
                                                                #(`rdclock_peride*20);
                                                            for (i=0;i <= 511 ;i = i + 1)begin
                                                                rdreq = 1;
                                                                #(`rdclock_peride);
                                                            end    
                                                            rdreq = 0;
                                                            #(`rdclock_peride*20);
                                                            $stop;        
                                                                
                                                                
                                                                
                                                                end
    endmodule

设置仿真路径,并进行仿真,仿真结果如下图

嵌入式FIFO核的调用第15张

还可以自己观察仿真波形中的接口的变化规律,这里就不再缀述了。

免责声明:文章转载自《嵌入式FIFO核的调用》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇基于STM32之UART串口通信协议(一)详解C# Web Service简单使用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

STM32(13)——SPI

简介:   SPI,Serial Peripheral interface串行外围设备接口。   接口应用在:EEPROM, FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。   特点:高速的、全双工、同步的通信总线、占用4根线;可以同时发生和接收串行数据;可以当做主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护...

基于MCP2515的Linux CAN总线驱动程序设计(二)

基于MCP2515的Linux CAN总线驱动程序设计(二) 作者:李老师,华清远见嵌入式学院讲师。 1.前言 CAN(Controller Area Network)总线,即控制器局域网总线,是一种有效支持分布式控制或实时控制的串行通信网络。由于其高性能、高可靠性、及独特的设计和适宜的价格而广泛应用于工业现场控制、智能楼宇、医疗器械、交通工具以及传感器等...

netcat的使用

1,端口扫描 端口扫描经常被系统管理员和黑客用来发现在一些机器上开放的端口,帮助他们识别系统中的漏洞。 $nc -z -v -n 172.31.100.7 21-25 可以运行在TCP或者UDP模式,默认是TCP,-u参数调整为udp. z 参数告诉netcat使用0 IO,连接成功后立即关闭连接, 不进行数据交换(谢谢@jxing 指点) v 参数指使用...

嵌入式Linux学习笔记(五) 通讯协议制定和下位机代码实现

目录 (1).参考资料 (2).协议制定 (3).数据的处理 (4).下位机串口通讯实现 (5).代码     通讯协议可以理解为约束多设备通讯的一套规则,像Modbus,TCP/IP, BLE都是在生产生活常用的协议。不过协议落实到实际应用后,就可以理解为对数据的结构化处理,我之前写的串口点亮LED的实现就涉及了简单的协议制定,对于嵌入式Linux来说,...

【转】说说Timing这回事

【转】说说Timing这回事 Intro 问:一个FPGA设计项目需要用哪些评判标准来检验? 功能正确; 时序收敛; 资源消耗少。 时序收敛,即Timing Closure,意思是使设计的各项时序指标能满足设计前所制定要求。因此,整个过程分为两部分: 制定时序要求 满足时序要求 Timing Constraints Classes 制定时...

FIFO IP核仿真

FIFO IP核仿真 1.FIFO IP核配置 2.FIFO测试逻辑代码 首先往FIFO里面写入512个数据(FIFO深度的一半),然后再开始同时往FIFO里面写入,读出数据。FIFO读和写的时钟域不同,对于不同时钟域的信号应该进行区分,状态机也应该分开来写。 `timescale 1ns /1ps //////////////////////////...