摄像头的FIFO配置使用
一、FIFO的基本工作原理讲解
FIFO( First Input First Output),简单说就是指“先进先出”。为了适应数据处理的高速缓存活临时缓存的需求,今天的FPGA中内嵌了丰富的存储单元,这些存储单元可以灵活的配置为RAM、双口RAM、ROM和FIFO。
在FPGA设计中,为了增加数据传输率、处理大量数据流、匹配不同的传输速率,常常需要用到FIFO存储器,以提高系统性能。FIFO存储器是一个先入先出的双口缓冲器,即第一个进入其内的数据第一个被移出,其中一端是存储器的输入,另一端是存储器的输出。FIFO可分为同步FIFO和异步FIFO,这个同步和异步,主要是针对输入和输出两端的时钟是否相同而已的。输入输出同时钟源,称为同步FIFO;输入输出时钟不同,称为异步FIFO。
1、FIFO和RAM的区别:FIFO和RAM都会在FPGA内部开辟存储空间。对于RAM来说,写入存储空间的数据,即使被读出了,它也还会存在储存空间。直到写入新数据,原来的数据才会消失。而FIFO不一样,写入的数据一旦被读出,则不会再存在,会消失。
2、FIFO的使能信号决定着数据是否有效。
3、Flag 是标志FIFO空还是满状态的信号。
4、prog-flag 是标志FIFO可编程的信号。
5、common clock 是指FIFO的写时钟和读时钟一样
6、independent clock 是指FIFO的写时钟和读时钟不一样
二、Vivado中FIFO IP的添加和基本配置
1、想用FIFO用在ARM的话,可以选择AXI总线。native是基础总线。
“实现”方式可以选择。其中“common clock”和“independent clock”指的是写时钟和读时钟是否一样。这里选择最后一个,“写时钟和读时钟不一致的内建FIFO”
2、standard FIFO 指标准FIFO,读使能来了之后,要一定时间,第一个要读出的数据才会出现在数据总线,这个时间就是 read latency,单位是时钟周期。如果选择 first word fall through,则读使能还没到时,第一个要读出的数据就已经出现在数据总线了。
3、write width 是数据位宽,选择8。而write depth 指的是深度,即FPGA的FIFO使用多少个位宽为8的寄存器。由于分辨率是 640×480 ,也就是水平方向需要640个寄存器,所以需要至少640深度,但是可以留多点余量,比如1024,以防不够。
4、rd_en 信号拉高后,则表示数据dout有效,standard FIFO会经过一个时钟延迟 read latency,这个数据才会出现在数据总线。而vaild是一个数据输出有效的信号标志,这个信号和dout信号完全同步。single programmable full threshold constant 表示单个可编程全阈值常数,也就是FIFO写满后,一起输出。这里设置为640,指的是一行的640个寄存器全写满后,再一起输出。
5、最后再看看总结,OK
三、IP文档资料的获取方法
怎么系统学习Xilinx的官方文档?如果安装了相关软件,则可以点开查看product guide 查看,如果没有下载,则可以去网站查看。
四、编写测试脚本
1、复制 FIFO 的例化模板。
2、新建存放FIFO仿真文件的文件夹
2、在 testbench 文件夹下面新建一个 tb_fifo_img 文件夹,这个文件夹专门存放仿真 fifo 相关的文件。可以把之前的仿真自动化模板文件复制到 tb_fifo_img
3、全部的仿真代码
这是完整的测试代码
4、仿真代码解释
①、图像传感器端工作时钟是25M时钟,所以FIFO输入端是25M时钟。FIFO内部的图像采集模块时钟是50M时钟,所以FIFO输出端是50M时钟。
信号都有:
时钟,复位,写使能,写数据,读使能,读数据,
输出有效信号(即 fifo_dout_vld 拉高后,表示输出的数据才有效),满信号,空信号,写满640个寄存器后的标志信号。
写满 640个reg后,fifo_prog_full 拉高,然后一起读出。
②、例化的FIFO模块的复位端口(rst)是高电平有效,而外面的复位信号(rst_n)是低电平有效,所以取反。
③、时钟和复位信号的产生
④、
标出的地方,“1”是第一个上升沿,“2”是以末尾上升沿为一个repeat,“3“是在第640个repeat的末尾上升沿处,fifo_wren拉高,然后延迟1000个时间单位。
”4“是先拉高读使能,直到时钟上升沿到,才读数据,而数据是以头部上升沿为一个repeat的,读使能信号比读数据维持了稍微多一点的时间,就是第一个repeat的上升沿处。之后的代码也一样。。。。。
5、在 tb_fifo_img 文件夹下创建一个 output_file 文件,用来保存写入和读出的数据,这样便可以做对比。
再创建一个 fifo_wr_data.txt 文件,文件属性是读,”w“。
wfile = $fopen(“./output_file/fifo_wr_data.txt”,“w”);
fifo_wren拉高后,则把写入FIFO的数据,写入文件 fifo_wr_data.txt 中,
fifo_dout_vld拉高后,则把FIFO读出的数据,写入文件 fifo_wr_data.txt 中。
则测试文件完成!
5、为什么测试代码要加 #1000;这些延时?
5、由于复位信号,FIFO的状态信号,它们的切换过程是需要时间的,不是立刻切换后,就能达到稳定信号的,所以在每次切换时,最好给一定的时间。这样信号真实一些。
两次测试之间可以间隔长一些,方便观察,比如5000
五、修改自动化文件
1、compile.do文件
只修改一处:网表文件的路径
”1“是复制下来的路径,"2"是上一个文件残留下来的路径。
修改后
2、run_simulation文件
添加了这些内容,目的是可以在批处理窗口输入不同的数字,单独执行不同的仿真文件。实现了对单独模块的仿真。
在批处理窗口输入”2“,回车,自动执行仿真。
六、小意外
结果在这里有个问题,没有找到文件。。。。
一检查,发现是 compile.do 文件的路径写错了。少了个 img 。加上去后再重新仿真就没有问题了。
七、分析波形
1、初值维持时间
”1“指的是 在第1000ns处拉高复位信号
”2“指的是 复位信号(第1000ns处)后,再等待1000ns,所以是2000ns
"3"由于@(posedge clk_25m);即 25m的时钟上升沿触发后,才有信号,而第2000ns处没有上升沿,要再等待20ns才出现25m时钟的上升沿,所以综上所述,在第2020ns之前,输入的信号都处于初值。
2、fifo_wren使能,数据信号 fifo_din 有数据输入时(2020ns处),fifo_empty信号不会马上拉低,而是在2110ns处才被拉低。这个延迟相当于”反应时间“。第一个写入的数据是十六进制的数24(十进制是36)
可以看到,写使能和写入的数据是完全同步的。
3、读出使能和读出数据(浅色箭头标出的位置是十六进制的24)
读使能信号和读出的数据并不完全同步,它们之间有时间差,
与读出的数据完全同步的信号是fifo_dout_vld,
4、在27580ns处,最后一个数据才刚开始写入,但是写入是需要时间的,所以留给了一些时间。之后 fifo_prog_full 信号拉高,标志着 640 个数据都已经稳定地写入了 FIFO
八、分析文件
下载compare插件后再比较,发现全是绿色,说明全部一样。