基于FPGA实现OV5640摄像头的视频图像采集及VGA显示
0. 背景
最近有些空闲时间,就想着去尝试实现视频图像采集及显示系统,因为以前涉及的数据采集传输系统主要是采集一维物理量,如最常见的就是实时采集各种单一维度的传感器信号,如温度,压力,光通量,加速度等。图像信号虽然采用水平像素和垂直像素的二维分量显示,其本质还是一维信号的分时显示构成的。例如,某幅图像大小为1280*720pixel,则每一行是1280个有效像素点,垂直方向上每一列(line)是由某一行构成,总共有720行,单幅图像所有像素点按时间先后依次分时采集,共计1280*720个有效像素点。
1. 器件选型
为了采集视频图像,需要选购摄像头模组,本质也是传感器(image sensor)+ 镜头 + 马达等部件组成,我采用的主控芯片是FPGA,用于驱动摄像头进行视频采集,以及通过VGA接口进行实时显示。选型时主要参考现阶段应用于DIY较多的豪威OV5640摄像头模组,开源资料比较多,便于固件驱动程序的开发。
OV5640该摄像头支持MIPI和DVP共两种接口模式。DVP接口是并行总线,其数据流速率受限于PCLK,PCLK通常不超过96MHz;而MIPI接口是LVDS低压差分接口,只需要要CLKP、CLKN、DATA+/DATA-组成。可知,MIPI接口比DVP的接口信号线少,差分信号线产生的干扰小,故抗干扰能力也强,因此数据流传输速率更高,现阶段智能手机上的摄像头均采用MIPI接口。现拟采用DVP接口来驱动该摄像头模组。
2. 固件驱动开发
上文提到过,OV5640摄像头模组的开源资料丰富,主要参考以下两个资料即可实现对摄像头模组正常功能的驱动。
资料一是豪威内部编写的摄像头驱动应用指南《OV5640_自动对焦照相模组应用指南(DVP_接口)__R2.13C》;
资料二是OV5640图像传感芯片手册《OV5640_datasheet》;
说明:两个资料均可以在网上免费下载获得,非常感谢网友的无私分享!!!
关于该摄像头的各种规格参数参见资料一二,下面主要介绍该模组的固件驱动开发过程。
(1) 摄像头模组上电复位
参见芯片手册可知,该模组对上电时序是由具体要求的,见图1所示。
如果按照这个上电时序要求进行,即可完成上电复位;上述DVDD电源是由外部电路提供,该图像芯片支持DVDD由内部自己产生,则上电时序有细微差别。
(2) 配置寄存器初始化
该摄像头模组的功能比较强大,例如VCM driver,环境光滤波,AEC/AGC,图像采集格式等等,都是通过配置相关寄存器来实现的。对于寄存器的配置由主控芯片FPGA完成,通信接口为SCCB接口,其本质可类比IIC接口,该接口时序见图2所示。
根据实际用法来具体配置各个寄存器相应值,有些寄存器不容易理解可忽略。《OV5640_自动对焦照相模组应用指南(DVP_接口)__R2.13C》附录1中驱动程序示例提供了常用的寄存器配置模板,可以复制和进行对应修改即可完成配置,见图3所示。
(3) 图像实时采集
经过上述两步完成后,可进行图像视频实时采集的具体实现。拟实现的视频采集参数为720P,60fps,图像格式为RGB565,由此可以算出PCLK时钟频率至少为 PCLK = 1280*720*60 = 55MHz,实际中会有一定比例的无效像素点采集,故PCLK实际工作频率大于55MHz的。DVP接口时序见图4所示。
在视频图像数据实时采集到通过vga接口实时显示链路中,如果二者数据流速率存在偏差,故需要中间加上图像数据缓冲单元,从而保证每帧图像完整采集后能完整显示。图像每个像素点为16bit,计算可知,一帧有效图像的数据量大小为1280*720*16 = 15Mbit,一般的片内ram无法满足,硬件采用DDR3芯片来作为缓冲单元,并将DDR3的存储空间分为两个子空间,每个子空间存储一帧数据,实时乒乓操作进行切换。例如,当空间1进行采集的图像数据写入时,同时从空间2中读取上一帧图像数据输出给VGA进行显示,如此可以保证各帧之间切换无切换痕迹出现。故ddr3在配置时,分配P0,P1两个64bit双向端口,来实现二者同时读写操作。
关于VGA接口,video graphic array 视频图形阵列,是一种基于模拟信号显示,由IBM在1987年随PS/2机一起推出的一种视频传输标准,R,G,B管脚电压范围为0.7V Vpp;故VGA接口需要匹配对应的DAC驱动芯片,其功能是将数字信号转化为电压模拟信号,然后进行图像显示。如果为了硬件设计简单化,可以将VGA驱动芯片替换为一组不同电阻网络来实现采样功能,电阻值的大小依次按照2的指数增长。例如数字信号的电源电压为3.3V,而R,G,B管脚电压范围为0 - 0.7V Vpp,VGA接口源端和终端匹配电阻均为75Ω,如图5所示。
由此可知: 3.3V / (Rx + 75) = 0.7V / 75 。 可以算的:Rx 约为500Ω。该方法具体实现可参考博文如下:
参考链接: https://www.cnblogs.com/spartan/archive/2011/08/23/2150660.html
VGA接口协议可以参考手册《VESA Display Monitor Timing Standard ©Copyright 1994-2004 Video Electronics Standards Association Ver 1.0, Rev. 1.0》,该手册里收录了不同图像帧格式下的各种水平和垂直参数值,参见图6所示。
最终,采集到的实时图像截图见图7所示。
3. 总结
经过一周的固件程序编写及调试,终于实现了基于FPGA实现OV5640摄像头的视频图像采集及VGA实时显示这一功能。途中也遇到一些疑问,依次记录见后文。OV5640的功能还是十分强大的,此时我只实现了基本功能。还有一些常用功能有待后续进行开发,例如自动对焦,进入预览模式,如何实现单帧拍照模式等等。
遇到的问题总结:
(1) 寄存器初始化时,感觉初始化成功,但是图像是一片红绿蓝三色点,则表明iic时序存在细节问题;
(2) OV5640进行iic通信时,该芯片slave address从机地址如何确定,默认地址是0x78,看到好多人不知道如何获取该地址, 其实OV5640的芯片手册就已明确设定了,参见图8所示。
(3)DDR3进行乒乓操作时,写入摄像头采集的数据到ddr中,使用的时钟是PCLK; 从DDR中读取单帧图像数据通过VGA接口进行显示,使用的时钟信号是VGA_CLK,二者不是同一个时钟。如果为了简便,均采用同一个片内时钟源,则需要注意两点:
其一是该时钟信号clk_ddr频率必须高于PCLK和VGA_CLK; 其二,由于ddr缓存模块(clk_ddr时钟),图像采集模块(PCLK时钟),VGA显示模块(VGA_CLK时钟)是不同时钟域之间内部使能信号和数据信号的传递,因此需要进行不同时钟域间的信号同步化,即用本模块时钟进行同步化操作。
(4) 视频采集的图像显示时,红色和蓝色正好发生交换。如图6中圆圈标记可知,牛奶盒上的红色区域变为蓝色显示,而对应的蓝色区域变为红色显示,正好出现了这一个好玩的bug。仔细分析程序时,发现OV5640摄像头模组数据流输出格式依次是B,G,R,我在编写程序时,因疏忽默认按照R,G,B依次采集和存储数据,故正好将蓝色和红色像素值交换了,造成图像反色,一个小疏忽,弄出了一个找茬图像,也算是一个小乐趣吧,在工程应用时应当避免这种错误。