第七章 实战项目提升,完善简历
19.OV7725摄像头实时采集送HDMI显示(三)
在详细介绍过OV7725 CMOS Sensor的相关背景知识和如何初始化其内部寄存器达到输出预期视频流的目的后,就到了该例程的核心内容即把OV7725输出的视频流预先缓存到外部DDR3颗粒,接着按照HDMI的视频格式把DDR3颗粒内存储的一帧一帧图像数据送显到屏幕上显示,如图1所示是OV7725摄像头实时采集送HDMI显示整体设计示意图,在这里大家不妨先去停下来去思考下应该怎么设计这些模块,然后这些模块之间如何进行数据交互和缓存。
图1 OV7725摄像头实时采集送HDMI显示整体设计示意图
如图2所示是OV7725摄像头实时采集送HDMI显示功能框图,大家可以根据这个框图通过自顶向下的思路来进行具体模块划分,最后再去层层分层逐一实现每个模块的具体功能。
图2 OV7725摄像头实时采集送HDMI显示功能框图
在这里我们可以理一理整个项目功能工程的编码思路,按照数据来源、数据流向、数据缓存、数据处理来思考。
首先OV7725实时采集的视频流是该项目中数据来源,但对于这么大批量的跨时钟域数据如果再用XC7A35T的片内BRAM资源去缓存是远远不够用的,所以必须借助片外的DDR3内存颗粒去缓存640像素*480像素的图像视频数据;其次需要按照VGA的行场时序逻辑把DDR3中存储的每帧图像数据送显到屏幕上;再次如果这里我们同时去读写同一个地址段的DDR3内存则必然会出现帧交错的情况,这个现象完全可以从“SD卡存放图片VGA送显屏幕”例程中观察到,因为OV7725采集视频流数据写入DDR3和HDMI读取DDR3数据送显屏幕两者是相互独立的事件,所以在程序设计中需要引入乒乓操作规避,当然具体细节会在后面详细介绍;最后还要回归OmniVision的官方手册搞清楚OV7725工作在640像素*480像素RG565模式下以怎么样的形式去输出视频流,以及怎么才能把图像数据按照帧的格式完整存储到DDR3上。
图3 OV7725 CMOS Sensor在VGA帧模式下的输出时序图
如图3所示是OV7725 CMOS Sensor在VGA帧模式下的输出时序图,在详细介绍OV7725视频采集cmos_capture模块的时序设计前还是先来了解一些基本的概念:
VSYNC:场同步信号,该信号由OV7725 CMOS Sensor摄像头端输出,用来标志着一帧数据的开始或者结束,如上图7-39所示VSYNC高电平作为一帧的同步信号,并在低电平时输出的数据有效,但是场同步信号可以通过物理地址为0x15的寄存器进行初始化配置的,在这里为了保持和VGA场同步信号一致,故笔者将其配置成高电平同步有效即于图中电平相反;
HREF:行同步信号,该信号由OV7725 CMOS Sensor摄像头端输出,用于标志一行数据的开始或者结束。如上图7-39所示当HREF为高电平时图像输出有效,同样的也可以通过物理地址为0x15的寄存器进行初始化配置的,为了保持和VGA场同步信号一致,默认为高电平有效即和图中电平一致;
D[9:0]:数据信号,该信号由OV7725 CMOS Sensor摄像头端输出,但是在RGB模式下输出中,默认只有高8位即D[9:2]是有效的;
tPCLK:一个像素时钟的周期;
tp:单个数据周期,请注意上图7-39中左下角所示的部分,手册里说明了在RGB模式中,tp代表2个像素时钟tPCLK。以RGB565数据格式为例,RGB565使用了16bit数据来表示一个像素点,又因为OV7725 在一个像素时钟tPCLK里只能传输8bit数据,所以需要两个时钟周期才能传输一个RGB565的像素点数据;
tLine:摄像头输出一行数据的时间,包含了784个 tp,包含640tp个高电平和 144tp 个低电平,其中640tp为有效像素数据输出的时间,同样的以RGB565 数据格式为例,640tp 实际上是640*2=1280个tPCLK;由上图7-39可知VSYNC的上升沿作为一帧的开始,高电平同步脉冲的时间为4*tLine,接着等待18*tLine时间后HREF开始拉高,这时候输出有效数据,HREF由640tp个高电平和144tp个低电平共同构成,输出480行数据后等待8*tLine时间一帧数据传输结束,所以输出一帧图像的时间实际上是tFrame =(4+18+480+8)*tLine = 510tLine。
图4 OV7725 CMOS Sensor在RGB565模式下的时序图
如图4所示是OV7725 CMOS Sensor在RGB565模式下的时序图,其中PCLK是OV7725 输出的像素时钟,HREF是行同步信号,D[9:2]是8位像素数据。虽然OV7725最大可以输出10位数据,但是在RGB565输出模式下只有高8位是有效的。
像素数据在HREF是高电平时有效,第一次输出的数据为RGB565数据的高8位,而第二次输出的数据RGB565数据的低8位,由first byte 和 second byte 组成一个16位RGB565数据。
同时可以从图中看出因为数据是在像素时钟的下降沿发生改变的,为了在数据最稳定的时刻采集图像数据,所以我们可以在像素时钟的上升沿采集数据,从OmniVision的官方手册中提取出核心信息后,下面我们就开始着手实现OV7725视频采集cmos_capture模块的代码设计了。
如图5所示是笔者通过示波器所观察到的OV7725在RGB565模式下的VSYNC和HREF波形图,其中蓝色的是VSYNC场同步信号而黄色的是HREF行同步信号,这也和上图3波形图相对应。
图5 示波器观察到的OV7725 在RGB565模式下的VSYNC和HREF波形图
如表1所示是cmos_capture模块的信号列表,在这个模块中我们主要去实现OV7725 的视频流采集,并把其拼接成128位数据写入FIFO再由FIFO缓存到MIG IP核中,如图6所示是OV7725视频采集模块的代码设计,在这个模块设计中也需要注意2点:
- 手册里指出配置寄存器生效的时间最长是300ms,大概就是摄像头输出10帧图像数据,所以这里用采集VSYNC场同步信号下降沿的方式来统计帧数,计数器计数超过10次后产生数据有效的标志开始采集图像;
- 像素数据在HREF是高电平时有效,第一次输出的数据为RGB565数据的高8位,而第二次输出的数据RGB565数据的低8位,所以需要进行数据拼接;
信号列表 | ||
信号名 | I/O | 位宽 |
cam_pclk | I | 1 |
rst_n | I | 1 |
cam_vsync | I | 1 |
cam_href | I | 1 |
cam_data | I | 8 |
cmos_pixel_dout | O | 128 |
cmos_pixel_dout_vld | O | 1 |
表1 cmos_capture模块信号列表
图6 OV7725视频采集模块的代码设计