一 **、SDRAM 缓存处理 **
很多摄像头工程都用到了 SDRAM 作为中间缓存,很多人一脸懵逼,我也是思考了好一阵才明白。先假设 OV5640 和 VGA 直接相连,中间不采用任何缓存器件,那会出现什么情况呢?
OV5640 的帧率为 30fps, VGA 的帧率为 60fps,且时钟也完全不一样。假设分辨率是 3x2 = 6,数据为:1,2,3,4,5,6。OV5640 帧率小,生成一个像素的时间假设是 2 秒,而 VGA 帧率大,需要一个像素的时间假设是 1s。在 6s 的时间里,VGA 就请求了一帧数据,可这个时间里 OV5640 只生成了 1,2,3 共三个像素,VGA 那边就出现了空数据的情况。在 12s 的时间里,VGA 请求了两帧数据,可这个时间里 OV5640 只生成了一帧数据,怎么来说都是错的。上述假设是简化了时间点,实际情况是 OV5640 生成像素和 VGA 请求像素的时间不一致,导致 VGA 总是要不到一帧图像正确的数据,也要不全一帧图像正确的数据。因此,OV5640 和 VGA 之间需要加入一个缓存器件,用于缓存一帧的数据,这样 VGA 每次要一帧数据都可以被满足。加入缓存器件的根本原因就是两端时钟不一致,导致读写速率不一致。
采用什么缓存器件呢?FIFO 和 RAM 是最常用的,但是一帧的图像数据往往是 640x480、1280x768、1920x1280,每个像素是 16bit。数据量大,FPGA 的片内资源无法满足。因此需要引入外部缓存器件,如 SDRAM、DDR2、DDR3 等。
二、无乒乓操作
SDRAM 正常使用其实是无乒乓操作,无乒乓操作是考虑不周的,除非一帧图像是瞬间生成,OV5640 帧率 30fps,VGA 帧率 60fps,仿佛刚好可以写一帧读两帧。但是一帧图像实际情况是一行行的生成和读取的,所以会出现 VGA 从 SDRAM 处读的上半帧是新帧,而由于 SDRAM 缓存的下半帧还没有被 OV5640 写完,VGA 从 SDRAM 处读的下半帧还是老帧。示意图如下所示,红线为写,黑线为读。
将上述 5 帧图像生成的时间点编号为 t1、t2、t3、t4、t5。在 t1、t3、t5 时刻图像都是残缺帧(新老帧参半),在 t2、t4 时刻图像才是完整的一帧,而 VGA 那边可不管,每个时间点都会要一帧图像,这就是错帧现象。而解决错帧现象的方法则是乒乓操作。
三、乒乓操作
1、乒乓操作原理
乒乓操作,使用两个缓存区,写缓存区 1 时读缓存区 2,写缓存区 2 时读缓存区 1,读写交替。示意图如下,红线为写,黑线为读。
由示意图可以看出,乒乓操作中,每次读的(黑线)都是完整的帧,每一帧读 2 次,这样便没有出现读残缺帧的现象,解决了错帧问题。
2、乒乓操作设计
在上述设计中,由于写读速率为 1:2,所以写一帧读两帧即可,但是很多时候写读速率的比例是其他数值,那怎么办呢?
(1)写端在缓存区 1 写完一帧数据就切换到缓存区 2 写下一帧,写完后又切换回缓存区 1 写再下一帧,如此反复。
(2)读端在缓存区 2 读完一帧:
①如果写端仍然在缓存区 1,则读端不切换缓存区,而是继续在缓存区 2 重读一帧。
②如果写端离开了缓存区 1,即切换到缓存区 2 了,说明写端已经在缓存区 1 写完了,则读端可以切换到缓存区 1。这样就能保证读端每次读的都是完整的帧,就算有一小段时间是读写端都在同一个缓存区,但是由于写慢读快,写是不会追上读的,读还是能读完旧帧,之后旧帧才被新帧覆盖。
写慢读快这样设计就行,那如果写快读慢呢?其实也是一样的思想,反过来即可。无论谁快谁慢,都是快端照顾慢端,即慢端一帧结束就离开自身缓存区到另一缓存区。快端则一帧结束后,先检测慢端是否离开自身缓存区,是则切换过去,否则不切换过去,而是重新在自身缓存区再工作一帧。示意图如下所示:
3、SDRAM 乒乓操作
用两片 SDRAM 来进行乒乓操作有些太浪费了,可以直接利用 SDRAM 里面的 bank 进行乒乓操作即可。虽然读写只有一根总线,但是 SDRAM 时钟高,读写足够快,可以满足乒乓操作的需求。具体实现可以看这篇博客《DDR2(5):DDR2 自动读写控制器》,虽然是 DDR2,但道理是一样的。
参考资料:
[1]正点原子 FPGA 教程
[2]小梅哥《OV5640 图像采集从原理到应用》
[3]开源骚客《SDRAM 那些事儿》
[4]韩彬, 于潇宇, 张雷鸣. FPGA 设计技巧与案例开发详解[M]. 电子工业出版社, 2014.
https://www.cnblogs.com/xianyufpga/p/12283590.html