CrazyBingo

【连载6.2.1.4】CMOS摄像头视频图像采集接口设计

0
阅读(1774)

前面我们已经的完成了OV7725的初始化,如果硬件/通信正常的话,OV7725已经按照我们预期进行工作。关于CMOS摄像头视频时序,我们主要关心的主要有以下几个信号:

4.jpg

Altera Quartus II提供了强大的Signal Tap II在线逻辑分析仪,通过JTAG即可方便的捕获硬件的时序信号,因此Bingo这里将简单的采用SignalTap II进行CMOS视频时序的介绍,详细的给出了以下几个方面的采集分析:

(1)VSYNC = L Valid时视频流数据

在OV7725默认状态,即未经过初始化时,输出的VSYNC信号为低电平有效。或者在I2C_OV7725_RGB565_Config中设置0x15寄存器的值为默认值0x00,得到如下波形:

4.jpg

这个波形是OV7725输出的默认电平下的视频信号时序。从波形中可知,在数据无效时OV7725输出0;而在数据有效时,HREF与DATA同时有效,此时场信号VSYNC默认为低电平有效。

(2)VSYNC = H Valid时视频流数据

由于Micron、VGA等都在VSYNC为高电平时数据有效,并且这也更符合逻辑,同时可以和VGA时序匹配,因此在I2C_OV7725_RGB565_Config中设置0x15寄存器的值为默认值0x02,即翻转VSYNC,得到如下波形:

4.jpg

可见在场有效信号VSYNC由低电平变成了高电平,其他信号保持不变。在Bingo后续的设计中,都将设置OV7725 VSYNC为高电平有效,低电平场同步模式。

(3)视频信号深度分析

放大② 中的波形,在行有效信号HREF起始时,Data同步从低电平开始输出,在行有效信号HREF结束时,Data同步从输出变成低电平,如下图所示:

4.jpg

从图中分析,在当前行有效信号输出时,HREF从采样点3199开始,到5759结束。由于输入数据为24MHz,而采样时钟为48MHz(SignalTap II采样时钟),因此一个数据被采样了2次,这样每行输出的数据计算如下:

 4.jpg

再次结合OV7725的数据手册,翻看OV7725的时序图,如下所示:

5.jpg

注意,Bingo在OV7725初始化的时候,设置了VSYNC为低电平同步,即VSYNC与上图相反!此时时序与VGA扫描时序,除了时间间隔,其他完全相同。

同时,我们用示波器验证分析按照Bingo的初始化列表初始化后的视频流格式,抓图如下所示:

4.jpg

从图中可见数据在VSYNC高点平有效,在VSYNC低电平同步。同时VSYNC为25FPS(图中不可见),这主要与寄存器的配置有关。在手册中说道CMOS 24MHz像素时钟的时候,帧率为30FPS,那那是相对于国外60Hz交流电而言的。国内交流电为50Hz,为了避免工频闪烁,在设置寄存器0x2B为9e,由于25Hz恰好为50Hz的约束,这样便更容易的实现了自动曝光避免。

此外,前面Bingo选择了RGB565模式的初始化,因此查看OV7725数据手册,可见RGB565模式下输出的图像数据格式为:

4.jpg

RGB565即{R[4:0], G[5:0],B[4:0]},此时已经达到了人眼能够分辨的真彩色。结合视频流像素输出规律,从OV7725输出的RGB565时序图中分析,可见以下几点:

① 在HREF无效时,不输出数据;在HREF有效时,连续输出640*2个的一行数据。

② 数据输出仅D[9:2]有效,D[1:0]忽略(实际上硬件中我们的确只用了高8位)。

③ 从HREF有效开始,先输出RGB565的高8位,即{R[4:0],G[5:3]},再输出RGB565的低8位,即{G[2:0],B[4:0]}。

④ 数据在PCLK低电平是改变,在PCLK高电平时可以有效读取。

因此,将CMOS_PCLK作为主时钟,简单的通过捕获CMOS_VSYNC与CMOS_HREF的信号,就可以直接采集到每行1280(640*2),每场480行的数据。唯一需要处理的是实现前后8Bit RGB565数据的拼接,以至于将输入的24MHz的像素时钟,降低到了12MHz的像素时钟。主要代码及分析如下。

首先,在正式开始采集数据之前,我们得稳定初始化后的CMOS Sensor。手册要求必须给足300ms,或者说延时10FPS,如下所示。因此我们要通过VSYNC的下降沿的计数,来实现10FPS的延时。

4.jpg

这里用到了“边沿检测技术”,通过判断CMOS VSYNC下降沿(前面寄存器设置低电平同步)作为使能信号。这里通过cmos_vsync的寄存,来获得2个时刻的值,相关代码如下(cmos_href_r的寄存后续模块有用):

4.jpg

此时,采用cmos_vsync_end作为计数使能信号,计数到10后,停止,相关代码如下:

4.jpg

这里CMOS_FRAME_WAITCNT作为外部输入的帧延时宏定义变量,例化时定义10,即为10 FPS的延时。由于某些相机不需要10FPS的延时,或者其他的一些原因,在上一步骤之后,为了实现帧同步,我们需要等待下一次帧结束信号。即让完成了10 FPS的延时(如有CMOS有要求的话),在等待下一个帧完成信号,打开帧同步信号frame_sync_flag,相关代码如下所示:

4.jpg

这里的frame_sync_flag对于整个CMOS视频采集模块而言,非常的重要。唯有frame_sync_flag,有效,采集的信号才能正常输出,这将是采集模块成功的一个标志。

接下来,我们正式开始RGB565数据的采集。从前文中我们已经了解到RGB565即{R[4:0], G[5:0],B[4:0]},在VSYNC及HREF有效时,每个CMOS_PCLK先发送RGB565的高8位,即{R[4:0],G[5:3]},然后发送RGB565的后8位,即{G[2:0],B[4:0]},因此,从HREF有效开始,我们必须拼接每相邻的2个Data,实现完整的RGB565的读取。相关代码如下所示:

4.jpg

这里的byte_flag作为高低8Bit的标志,即0的时候为高8Bit,1的时候为低8Bit。每次在byte_flag == 0的时候寄存像素数据,在byte_flag == 1的时候拼接{寄存像素数据,当前像素数据},得到RGB565。拼接后的数据为cmos_frame_data_r。

当然,这里涉及到frame_sync_flag同步信号,最后实现一下数据流的使能控制,如下所示,cmos_frame_data为最终延时、同步、拼接输出的16Bit RGB565数据:

4.jpg

此外,既然RGB565发两次数据最为一个完整的像素数据,因此我们有必要认为生成一个数据读取使能时钟,作为后续数据读取的标致信号。我们每次在byte_flag == 1的时候通过拼接输出数据,因此应该在byte_flag == 0的时候输出使能信号。但由于第一次byte_flag == 0的时候还没有数据,同时最后一个数据拼接后不再有byte_flag == 0,因此这里将byte_flag延时一个时钟,同时用byte_flag == 1(为什么是1自己想清楚)作为RGB565数据输出的使能信号,相关代码如下所示(同时结合帧同步信号):

4.jpg

此外,相对于数据流的输入而言,我们用2个时钟输出了拼接后的数据,因此VSYNC与HREF均应该滞后2个时钟,结合帧同步信号,帧同步信号cmos_frame_vsync与行同步信号cmos_frame_href的输出如下所示:

4.jpg

这一部分代码,Bingo在当前工程目录给出了完整的Modelsim仿真测试文件。这里得到了测试波形如下所示,详情请自行分析CMOS_Capture_RGB565_TB:

4.jpg

所谓完美是没有极限的,Verilog HDL是万能的。这里Bingo教大家如何用RTL实时计算帧率。首先我们通过像素时钟24MHz得到2S的周期,代码如下所示:

4.jpg

在这2S内,我们需要做的就是累积这段时间内的帧数。每次2S计数到时,通过累积的帧数/2,便得到了实时的帧率。2S更新一次是一个相对的值,您可以额10S,更新一次,但提高了准确性的同时,却降低了实时更新的速度。这里更新的相关代码如下:

4.jpg

输出的cmos_fps_rate便是得到的2S更新一次的帧率值。

废话一大片,我们终于完成了CMOS视频流数据的采集,这里给出例化代码,如下:

4.jpg

从复位的例化中可见,每次模块在CMOS Sensor与SDRAM均初始化完毕后,才开始打开CMOS视频流采集电路,这样保证了数据的捕获与写入是有效的,避免由于不稳定性导致的数据缺失。