学习
实践
活动
专区
工具
TVP
写文章

视频图像采集与接口时序编程设计

各位工程师朋友,同学们大家好!我是本期“来实战”项目《运动目标追踪系统》的执行官。本项目由电路城发起,由ALINX赞助的黑金国产FPGA板卡Logos系列PGL22G学习板实现。

我是一个热爱技术的在校学生。希望可以通过本次的项目来帮助更多的同学,给予一个机会来了解什么是真正的实战项目,也让之前没有竞赛经验的朋友了解一下,竞赛对于我们学生来说并没有那么远。帮助更多的电子专业的同学找到学习的方向,更顺利的进入这个行业,为电子行业做出一份自己的贡献。许多同学在学校期间不去做项目的原因并不是不愿意去做,而是没有方向。其实大项目就可以通过竞赛来获得,竞赛中的一些命题项目可以给予你很多灵感,有了方向之后,即使是个大项目,他也是由一个一个小部分组成的,一步一步完成一个个小项目,自己的大工程不久也就成功了。项目本身的意义可能是在做保护区的摄像头,捕捉动态视频;也可以在监控中做一些应用。更重要的意义就是给广大同学们一个学习视频处理的机会,让想学而不知道怎么去学的同学一个模板。

很多在最初接触FPGA的同学都有这个问题,甚至以为FPGA和单片机一样下板子烧代码。其实不是这样的,FPGA不是单片机,首先FPGA和单片机的区别,本质上是软件和硬件的区别,FPGA更偏向于硬件电路,而单片机更偏于软件。单片机是一种微处理器,类似于电脑CPU的,它一般采用的是哈佛总线结构,或者冯诺依曼结构,对单片机的编程很大程度上要考虑到它的结构和各个寄存器的作用,而FPGA 它的结构是查找表结构,其程序不用去太考虑芯片的结构,要注意的是时序上问题,它的结构比较复杂,功能也很强大,一般应用在通信领域等比较高端的场合,单片机是一个微控制器,通过加载模块软件来实现某种功能,是成型的芯片;FPGA是用来设计芯片的芯片。FPGA由于是硬件电路,运行速度直接取决于晶振速度,系统稳定,特别适合高速接口电路。单片机由于是单线程,哪怕是常用的M3系列流水线也是单线程执行,程序语句需要等待单片机周期才能执行。单片机设计属软件范畴;它的硬件(单片机芯片)是固定的,通过软件编程语言描述软件指令在硬件芯片上的执行;

FPGA开发的语言是Verilog HDL。HDL代表的就是硬件描述语言,描述就代表他并不是一个开发性的语言。相比C语言开发,Verilog更像是你先设计好电路,再用Verilog描述出来你的设计。而对于一个完整的FPGA工程应包含以下几个步骤:算法实现,模块化,模块的硬件电路设计,硬件描述语言书写,小模块进行仿真,总模块的连接,总体工程的仿真,板级验证。下面我们就进入正题......

视频内容截图:

项目设计

01

FPGA硬件资源与算法设计 

1.FPGA硬件资源介绍

首先感谢黑金ALINX提供的开发板对本项目的大力支持,期望以后能有更多的机会合作。对于黑金国产FPGA板卡Logos系列PGL22G学习板,它配备了以下资源:

系统逻辑部分由ov5640驱动模块、RGB转Ycbcr模块、存储控制模块、HDMI驱动模块、图像处理模块、追踪控制模块、sim900a驱动模块共同组成。由OV5640摄像头采集图像,经过RGB转YCbCr模块完成颜色空间转换,为了配合帧差法的数据,将数据进行掩码然后经由DDR3控制器模块控制存入DDR3中,通过HDMI时序从DDR3中取出数据,此时取出的每个16bit数据同时包含了相邻两幅图像的灰度信息,高8位为第n帧图像的某个像素点灰度值,低8位为第n+1帧图像对应像素点的灰度值。图像处理模块将取出的数据进行预处理和帧差法计算得到运动目标的位置信息,追踪控制模块根据运动目标的位置相对于图像中心的偏移通过控制舵机转动来调整OV5640摄像头的方向完成追踪。摄像头使用黑金ALINX视频套餐中的OV5640摄像头;同套餐的还赠送一个屏幕,也非常适合学习视频处理的工程。舵机模块是使用的SC90,来完成摄像头的转动的,该模块看上去很简单,但是他和摄像头一起组合使用就非常炫酷!

2.算法设计

(一)项目简介与项目难点

(二)整体流程

(三)算法基础

均值滤波与中值滤波

Sobel边缘检测

RGB转YCbCr

……

02

视频图像采集与输出模块的接口时序设计 

本项目的一大难点,就是这么多模块如何驱动,接口是是用什么协议驱动的。本步骤主要来一点一点的啃各个模块的接口时序与协议参数。

1.摄像头模块的时序与驱动

首先是摄像头采集模块,我们采用 500 万像素的 OV5640 摄像头模组(模块型号:AN5640)为大家显示更高分辨率的视频画面。OV5640 摄像头模组最大支持 QSXGA (2592x1944)的拍照功能,支持 1080P、720P、VGA、QVGA 视频图像输出。

摄像头模块的驱动实际上就是如何配置寄存器和如何按帧按行的读取像素点。摄像头是通过配置各个寄存器中参数,来确定摄像头运行的模式。OV5640 的寄存器配置是通过 FPGA 的 I2C(也称为 SCCB 接口)接口来配置。用户需要配置正确的寄存器值让 OV5640 输出我们需要的图像格式,我们把摄像头输出分辨率和显示设备分辨率配置成一样的, OV5640 的摄像头输出的数据格式在以下的 0x4300 的寄存器里配置,我们将 OV5640 配置成 RGB565 的输出格式。如ALINX给予的官方版文档中书写的:

关于 OV5640 的寄存器还有很多很多,但很多寄存器用户无需去了解,寄存器的配置用户可以按照 OV5640 的应用指南来配置就可以了。如果您想了解更多的寄存器的信息,可以参考OV5640 的 datasheet 中的寄存器说明。在传输这种信息时,我们使用SCCB(IIC)协议来配置摄像头寄存器。

IIC的传输文件如下所示:

对于IIC,很多接触过电子、单片机的同学都一定不陌生。下面截取黑金教程中对IIC(下称为I2C)

I2C 总线通信过程中出现的几种信号状态和时序迚行分析。

总线空闲状态

I2C 总线总线的 SDA 和 SCL 两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

启动信号(Start)

在时钟线 SCL 保持高电平期间,数据线 SDA 上的电平被拉低(即负跳变),定义为 I2C 总线总线的启动信号,它标志着一次数据传输的开始。启动信号是由主控器主动建立的,在建立该信号前 I2C 总线必须处于空闲状态,如下图所示。

停止信号(Stop)

在时钟线 SCL 保持高电平期间,数据线 SDA 被释放,使得 SDA 返回高电平(即正跳变),称为 I2C 总线的停止信号,它标志着一次数据传输的终止。停止信号也是由主控器主动建立的,建立该信号乊后,I2C 总线将返回空闲状态。

数据位传送

在 I2C 总线上传送的每一位数据都有一个时钟脉冲相对应(戒同步控制),即在 SCL 串行时钟的配合下,在 SDA 上逐位地串行传送每一位数据。迚行数据传送时,在 SCL 呈现高电平期间,SDA 上的电平必须保持稳定,低电平为数据 0,高电平为数据 1。只有在 SCL 为低电平期间,才允许 SDA 上的电平改变状态。

应答信号(ACK 和 NACK)

I2C 总线上的所有数据都是以 8 位字节传送的,収送器每収送一个字节,就在时钟脉冲 9 期间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK 简称应答位),表示接收器已经成功地接收了该字节;

应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。对于反馈有效应答位 ACK 的要求是,接收器在第 9 个时钟脉冲乊前的低电平期间将 SDA 线拉低,并确保在该时钟的高电平期间为稳定的低电平。如果接收器是主控器,则在它收到最后一个字节后,収送一个 NACK 信号,以通知被控収送器结束数据収送,并释放 SDA 线,以便主控接收器収送一个停止信号。

2.摄像头模块硬件语言描述

根据我们的时序,可以写Verilog代码了。由于他也并不是一个核心代码,就不再费劲的为大家写了。在开源网站“http://opencores.org/”

上我们可以找到很多非常好的代码,这些代码大部分都提供详细的...

再说回摄像头,除过摄像头寄存器堆,剩下的要点就是像素数据传输。

摄像头的像素点信息是按行发送的,也就说依次发送一行信息,发送信息的使能信号为HREF 信号。HREF 信号为高时输出一行的图像数据,输出数据在 PCLK 的上升沿的时候有效。也就是在HREF为高的时候,每个PCLK的上升沿时候把数据输出出去。因为 RGB565 显示每个像数为 16bit, 但 OV5640 每个 PCLK 输出的是 8bit,所以每个图像的像数分两次输出,第一个 Byte 输出为 R4~R0 和 G5~G3, 第二个 Byte 输出为 G2~G0 和 B4~B0,将前后 2 个字节拼接起来就是 16Bit RGB565 数据。

根据时序图,我们来书写读取摄像头数据的文件。调试摄像头的第一个问题在于视频同时读写,如何做到读写不冲突?为了不出现显示的问题,在设计帧读写模块时,所有帧基地址选择(最大 4 帧选择),每次读视频帧地址和正在写的帧地址是不同的,而是上次写入一帧数据的地址,这样就可以避免读写冲突,避免视频画面裂开错位。但是注意采用了上述拆分数据之后,要写一个模块模块完成摄像头输入的 2 个 8bit 数据转换到一个 16bit 数据(一个像素),数据位宽变成 2 倍,时钟频率不变,所以 16bit 数据是隔一个时钟周期有效,并不是每个时钟一直有效。要检测的是行场信号,首先要检测HREF信号的上升沿,每个上升沿到来的时候就是新的一行数据到来。之后每隔时钟上升沿检测HREF信号是否为高,如果HREF信号为高,则接收这个数据。完成这个操作的代码如下:

摄像头读写模块通过判断摄像头的列同步信号 cmos_vsync 的上升沿,生成 ov5640数据写入的请求信号,表示一帧图像开始写入请求。另外生成 write_addr_index 写地址选择和read_addr_index 读地址选择,这里 read_addr_index 的值会比 write_addr_index 的值延迟一帧,使得读和写的地址不冲突

3.HDMI接口时序与驱动

配置好摄像头,我们来配置HDMI接口。

HDMI 显示器扫描方式和我们更加熟悉的VGA相似,从屏幕左上角一点开始,从左向右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,CRT 对电子束进行消隐,(每行开头和结束有几个数据是不显示的)每行结束时,用行同步信号进行同步;当扫描完所有的行,形成一帧,用场同步信号进行场同步,并使扫描回到屏幕左上方,同时进行场消隐,开始下一帧。完成一行扫描的时间称为水平扫描时间,其倒数称为行频率;完成一帧(整屏)扫描的时间称为垂直扫描时间,其倒数称为场频率,即刷新一屏的频率,常见的有 60Hz,75Hz 等等。标准的显示的场频 60Hz。时钟频率:以1024x768@59.94Hz(60Hz)为例,每场对应 806 个行周期,其中 768 为显示行。每显示行包括 1344 点时钟,其中 1024 点为有效显示区。由此可知:需要点时钟频率:806*1344*60约 65MHz。

上图看上去是一个二维的,实际上横向的一个信号与纵向的一个信号,横向的信号就是行信号,和摄像头一样,每当行信号HSync的一个脉冲,即新的一行开始了。但是也不是脉冲一结束就是数据像素点,而是一串没有意义的数据。讲起来很绕,其实就是人眼睛会有留影,为了消除这些影子,每行开头和每帧开头设置一串供消影的数据。帧信号VSync也是每个脉冲到来,也是新的一帧到来了。根据这个信号我们来区别上一张图像和这一张图像的边界。

所以我们在编写Verilog 时要注意这些参数,只有确定好这些参数才能在HDMI屏幕上显示出图像。

我们使用的600*800像素的上述参数如下:

dvi_encoder 模块中包含两个模块 encode 和 serdes_4b_10to1 模块,实现 RGB 格式的图像转化成 TMDS 差分输出,来驱动 HDMI 显示。

1). encode:红,绿,蓝的 8 位视频数据及时钟编码成 10 位的 TMDS 视频数据。关于编码的原因和方法我们已经在前面介绍过,具体如何实现,可以参考下图

TMDS视频数据编码(TMDS Video Data Coding)是将像素的8位数据转化成10个位的字符,但他不是主流的8b/10b编码方式。其编码需两道过程:首先将8位转换到9位,将位的转换最小化。转换最小化可以降低铜连接线环境的电磁干扰(Electromagnetic Interference)。其次,产生10位来造成直流平衡化理想的字符。

TMDS视频数据编码算法过程如下(摘自DVI规范):

2). serdes_4b_10to1:方法是通过两个 OSERDESE2 的串联把 10 比特的并行数据转换成串行发送出去。

4. HDMI模块硬件语言描述

根据时序图,和上述的模块图结合在一起,就可以书写模块了。模块的书写和摄像头相类似,时序单元基本相同。具体完成的就如同上述时序,对行场信号生成,也就是写计数器,技术标准就是前图的参数。

再设置寄存器,将我们要显示的数据输出(摄像头采集到的数据)。这部分按顺序一位一位的发送即可。

03

存储模块与图像处理模块的设计与实现 

04

系统整体设计的实现与优化 

……

(步骤三、步骤四待更新。。。)

05

附件下载

往期《来实战》栏目回顾

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200906A02R4S00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

关注

腾讯云开发者公众号
10元无门槛代金券
洞察腾讯核心技术
剖析业界实践案例
腾讯云开发者公众号二维码

扫码关注腾讯云开发者

领取腾讯云代金券