基于FPGA的OV7670驱动--第1部分
基于FPGA的OV7670驱动--第1部分
ov7670图像传感器介绍
ov7670简介
图 3 ov7670实物图
ov7670,CMOS图像传感器,体积小,工作电压低,提供单片VGA摄像头和影像处理器的所有功能。通过SCCB总线控制,可以输入整帧、子采样、取窗口等方式的各种分辨率8位影像数据。该产品VGA图像最高达到30帧/秒。用户可以完全控制图像质量、数据格式和传输方式。所有图像处理功能过程包括伽玛曲线、白平衡、饱和度、色度等都可以通过SCCB接口编程。OmmiVision图像传感器应用独有的传感器技术,通过减少或消除光学或电子缺陷如固定图案噪声、托尼、浮散等,提高图像质量,得到清晰的稳定的彩色图像。
ov7670引脚定义
图 4 ov7670引脚分配图
表 1列出了ov7670主要的引脚说明,在实际的应用中,FPGA主要控制这些引脚进行ov7670驱动以及数据采集。
编号 | 引脚名称 | 输入/输出 | 描述 |
1 | XCLK | 输入 | 系统时钟输入 |
2 | SIO_C(SCL) | 输入 | SCCB时钟口 |
3 | SIO_D(SDA) | 输入 | SCCB数据口 |
4 | PCLK | 输出 | 像素时钟 |
5 | VSYNC | 输出 | 帧同步 |
6 | HREF | 输出 | 行同步 |
7 | D7 | 输出 | 数据位7 |
8 | D6 | 输出 | 数据位6 |
9 | D5 | 输出 | 数据位5 |
10 | D4 | 输出 | 数据位4 |
11 | D3 | 输出 | 数据位3 |
12 | D2 | 输出 | 数据位2 |
13 | D1 | 输出 | 数据位1 |
14 | D0 | 输出 | 数据位0 |
表 1 ov7670主要引脚说明
ov7670视频口有八根数据线, D[7:0],它支持的数据格式有8位 RGB raw 输出, 8位
YcbCr 输出, 8位 RGB 565/555/444 输出。
行同步信号 Href 和 Hsyn 是用同一引脚(Href pin)输出,通过写SCCB寄存器,可
选择这个引脚作为 Href 或hsyn信号。
SCCB总线 SIO_C 和SIO_D应外加上拉电阻,典型值是4.7K。
RESET#低有效,可由GPIO控制,若不使用时可连到DOVDD。如果RESET#连到DOVDD,必须通过写SCCB寄存器来进行软件复位。
ov7670注意事项
- PWDN不用时,应接地, RESET不用时,应拉高。
- SENSOR模拟电压(AVDD)是2.7V。
- SENSOR核心电压(DVDD)是1.8V。
- SENSOR输入输出数字电压(DOVDD)是1.7V到3.0V。
- SENSOR的AGND和DGND在模组内部应分开,在模组PCB外面才可连到一起
(模组内部不可连在一起)。.
- C1应靠近SENSOR的VREF1和AGND。
- C2应靠近SENSOR的AVDD和AGND。
- C3应靠近SENSOR的VREF2和AGND。
- C4应靠近SENSOR的DVDD和DGND。
- C5应靠近SENSOR的DOVDD和DGND。.
- D7-D0是模组YUV和RGB 8-bit输出格式时,八位数据线。
- SIO_C(SCL)和SIO_D(SDA)需外加上拉电阻,ov7670硬件并没有附加,所以在开
发板接口上必须外加4.7K的电阻。
- 一般摄像头出现问题,无法正常工作,有很大的可能是因为VSYNC和HREF出
现问题。
时序特性
图 5 ov7670输出数据时序图
计算PCLK的参数,如下所示:
VSYNC:510*Line = 3*tLine + 17*tLine + 480*tLine
HERF: 784*tP = 640*tP + 144*tP
HSYNC: 784*tP = 80*tP +45*tP +640*tP +19*tP
VGA RGB565、YUV422 30fps:
PCLK = 784 * 510 * 30 * 2(byte) =23990400 =24MHz
因此手册才推荐24MHz的XCLK输入。
注:30fps代表一秒30帧数据,即30张相片。
ov7670的分辨率为640*480,即一张有效的图片上有640*480个像素,每个像素都是2个字节的数据(16位)。但实际上是有784*510个像素,那些没有使用到的像素为无效像素,不过输出这些数据也是需要时间的。FPGA是根据VSYNC和HREF来提取有效的数据(VSYNC低电平和HREF高电平下)。
ov7670的工作频率最小值为10MHz到48MHz,其中典型值为24MHz。在我们实际使用中,使用的频率为25MHz,原因是我们需要通过VGA把图像显示到显示器上,由于显示器的显示频率为25MHz,所以选用25MHz。大概31fps。
下面是实际驱动中使用SignalTap II进行测试的实际波形图,如图 6。
图 6 SignalTap II测试图
通过实际测试,总结了ov7670的时序特点:在25MHz的系统时钟下,每两个时钟为一个像素点数据,例如图 6中A4h和F4h为一行里第一个像素点数据(两个字节),由此实现数据的高速采集。时序和数据有以下特点:当数据有效时,coms_herf信号线应为高电平,coms_vsync信号线应为低电平;时钟coms_pclk(coms_xclk)的上升沿都对应着数据的稳定期,此时可用来做数据采集;数据无效时,coms_data的数据应为0;由于SCCB用于初始化,配置时间很快,所以sccb_sclk和sccb_sdata无法观察到,但最终状态sccb_sclk应为高电平,sccb_sdata应为低电平。
通过对ov7670寄存器进行配置,可以任意选择摄像头输出的数据格式,如RGB565或YUV422。如何配置寄存器在后面SCCB初始化中有讲述。图 7为RGB565的数据输出时序,注意PCLK的上升沿对应着数据的稳定期,可以做数据提取。
图 7 RGB565的输出时序
数据格式说明
RGB565
RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。RGB图像只使用三种颜色,就可以使它们按照不同的比例混合,在屏幕上重现多种颜色。
RGB是从颜色发光的原理来设计定的,通俗点说它的颜色混合方式就好像有红、绿、蓝三盏灯,当它们的光相互叠合的时候,色彩相混,而亮度却等于两者亮度之总和,越混合亮度越高,即加法混合。有色光可被无色光冲淡并变亮。如蓝色光与白光相遇,结果是产生更加明亮的浅蓝色光。红、绿、蓝三盏灯的叠加情况,中心三色最亮的叠加区为白色,加法混合的特点:越叠加越明亮。
RGB565即图像使用RGB色彩模式,有R(red),G(green),B(blue)三种颜色元素,使用16位表示一个像素。这16位中的5位用于R,6位用于G,5位用于B,用两个字节(一个字)表示一个像素。RGR565可以最多显示出65536种颜色(2^16 = 65536)。当读出一个像素后,这个字如图 8所示。在ov7670中,可以通过寄存器配置,把ov7670输出的图像数据格式设置为RGB565,配置过程在后面教程会有所提及。
图 8 RGR565格式数据流
YUV422
YUV模式是被欧洲电视系统所采用的一种颜色编码方法(属于PAL),是PAL和SECAM模拟彩色电视制式采用的颜色空间。在现代彩色电视系统中,通常采用三管彩色摄影机或彩色CCD摄影机进行取像,然后把取得的彩色图像信号经分色、分别放大校正后得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号U、V,最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这种色彩的表示方法就是所谓的YUV色彩空间表示。采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。另外,还有YCbCr模式,YCbCr模式来源于YUV模式,两者接近,在不严格区分下,可以认为相同。
在我们实际应用中,提取的是其中的视频数据。这段数据就相当RGB565的数据一样。一个Y元素代表一个像素,Y代表亮度,UV代表色差。Y,U,V都是8为数据。图 9中的视频数据有720个Y元素,在ov7670中应该只有640个有效Y元素。
YUV信号有很多种,一般YUV420和YUV422用的比较多,YUV422格式,又分为很多小类,按照U、V的排列可以有YUYV,YVYU,UYVY,VYUY四种,这四种格式在ov7670中同样可以通过寄存器进行配置,在后面教程有所提及。
假如有一幅640×480的图片,用YUV422来表示,那么,采样方式就是每个像素采样Y信号,U,V信号隔一个采样,这样算下来,就有640×480个Y,640×240个U,640×240个V,一幅640×480大小的YUV图片占的总字节数为640×480×2个字节,每像素2个字节,也就是16位。
在内存种这样排列:Y0U0Y1V0 Y2U1Y3V1...
第一个像素的YUV值为: Y0 U0 V0
第二个像素的YUV值为: Y1 U0 V0
第三个像素的YUV值为: Y2 U1 V1
.....
其他以此推类,也就是说每两个像素是共用了UV的;在一行上来看,每个像素的YUV值中Y值被采样,UV值采样第一个像素后,跳到第三个像素,然后第五个像素,所以每行上Y有640个,U,V各320个。
图 9 YUV422格式数据流
SCCB初始化
ov7670初始化需要对内部的寄存器进行配置,配置的方式是通过FPGA对ov7670进行数据读写,其中涉及到的协议为SCCB。其实,SCCB与I2C很接近,写入的时序一样,读取有一点差别。先写入设备地址,然后寄存器地址,最后是寄存器的值。ID_Address + SUB_Address +W_Data(ov7670的设备地址为0x42,最后一位用来读写,读则为0x43)。对ov7670的初始化,也是FPGA驱动ov7670的关键。FPGA对ov7670的驱动设计框图如图 10,主要分为三大模块:1.主控器、2.ov7670寄存器配置库、3.SCCB接口。
图 10 FPGA驱动ov7670设计框图
先再次简述下I2C协议:在I2C总线传输过程中,将两种特定的情况定义为开始和停止条件(见下图):当SCL保持"高"时,SDA由"高"变为"低"为开始条件;当SCL保持"高"且SDA由"低"变为"高"时为停止条件。开始和停止条件均由主控制器产生,如图 11所示。使用硬件接口可以很容易地检测到开始和停止条件,没有这种接口的微机必须以每时钟周期至少两次对SDA取样,以检测这种变化。
图 11 I2C开始与结束状态的定义
SDA线上的数据在时钟"高"期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的"高"或"低"状态才可以改变。输出到SDA线上的每个字节必须是8位,每次传输的字节不受限制,但每个字节必须要有一个应答ACK。如果一接收器件在完成其他功能(如一内部中断)前不能接收另一数据的完整字节时,它可以保持时钟线SCL为低,以促使发送器进入等待状态;当接收器准备好接受数据的其它字节并释放时钟SCL后,数据传输继续进行。
数据传送具有应答是必须的。与应答对应的时钟脉冲由主控制器产生,发送器在应答期间必须下拉SDA线。当寻址的被控器件不能应答时,数据保持为高并使主控器产生停止条件而终止传输。在传输的过程中,在用到主控接收器的情况下,主控接收器必须发出一数据结束信号给被控发送器,从而使被控发送器释放数据线,以允许主控器产生停止条件。
I2C总线在开始条件后的首字节决定哪个被控器将被主控器选择,例外的是"通用访问"地址,它可以在所有期间寻址。当主控器输出一地址时,系统中的每一器件都将开始条件后的前7位地址和自己的地址进行比较。如果相同,该器件即认为自己被主控器寻址,而作为被控接收器或被控发送器则取决于R/W位。
图 12与图 13分别为I2C写入与读出的时序图。
图 12 I2C写入时序
图 13 I2C读出时序
ov7670的初始化是FPGA驱动ov7670的关键,ov7670初始化需要对内部的寄存器进行配置,配置的方式是通过FPGA对ov7670进行数据读写,其中涉及到的协议为SCCB。SCCB与I2C相比,写入的时序一样,但读取有点差别。先写入设备地址,然后寄存器地址,最后是寄存器的值。如图 14,ID_Address + SUB_Address +W_Data(ov7670的设备地址为0x42,最后一位用来读写,读则为0x43)。
图 14 SCCB写入时序图
读取设计与写入设计有些类似。在读取中,在发送设备地址、指定寄存器地址之后,还需要发次发送设备地址,才能读取指定寄存器的数据。在Verilog设计中,主要分成第一次指定寄存器,第二次读取寄存器数据两个步骤,如图 16。其实,读取设计在本系统中作用不大,仅仅用于读取COMS图像传感器的厂商识别或者产片标志。
图 16 SCCB读取时序图
寄存器配置
对ov7670的初始化,其实就是通过SCCB对ov7670进行寄存器的配置。这些寄存器的大概有100多个,都对应着相应的功能。但其实一般情况下,实际用到的可能就是十几二十个,其他用默认值,具体可以看datasheet。在之前的FPGA驱动ov7670框图中,主控制器调用寄存器配置库,然后把数据送到SCCB上。在寄存器配置库这部分上,实际是采用了一个查找表设计,先把对应好的寄存器编号和寄存器需要配置好的值合并好(16位数据),然后跟着顺序一个一个的读取。图 18列出了主要需要配置的寄存器。
具体每一个寄存器对应的配置内容可以查看官方的datasheet,接下来列出几个比较重点的寄存器。之前所说的如何设置RGB565和YUV422格式就是修改以下对应的寄存器的值实现的。
- 复位,选择图像输出的模式,如YUV422 或者 RGB565。如表 2所示。
表 2 12号寄存器配置内容
- 时钟输入设置。例程中ov7670使用的是FPGA输出的25MHz,为外部时钟。如表 3 所示。
表 3 11号寄存器配置内容
- PLL寄存器配置。这里可以使用PLL对外部时钟进行倍频。如表 4所示。
表 4 6B号寄存器配置内容
- PCLK像素时钟设置。通过这个寄存器的配置,可以改变采样时钟,同时改变输出图像的大小。这个寄存器的配置,还和73号寄存器有关。如表 5和表 6所示。
表 5 3E号寄存器配置内容
表 6 73号寄存器配置内容
- 设置YUV格式。这里需要3A号寄存器和3D寄存器配合,才能输出固定的序列。如表 7和表 8所示。
表 7 3A号寄存器配置内容
表 8 3D号寄存器配置内容
- 设置数据位RGB565为00-FF,YUV必须为01-FE或者更小。如表 9所示。
表 9 40号寄存器配置内容
例程解析
摄像头接口原理图
在配套的ov7670驱动例程中,共有6个verilog文件,如图 19所示。这6个文件组成了整个ov7670的驱动模块,
其中可以分为两部分,一部分是时钟PLL模块(ov7670_pll),另一部分是纯驱动模块(ov7670_drive_top),如图 20所示。图 21则为纯驱动模块内部的模块组成(ov7670_sccb_contronler模块,ov7670_sccb模块,ov7670_register_config模块,ov7670_pretreatment模块),前三个模块正是对应之前教程SCCB初始化的ov7670的驱动设计三大模块。
图 20 ov7670驱动顶层模块
图 21 ov7670纯驱动模块
接下来,我们对每个模块做解释说明,如表 10所示。
序号
模块名
功能描述
1
ov7670_pll
本模块主要把外部时钟(50MHz)经PLL分配得到25MHz的ov7670驱动时钟drive_sys_clk。
2
ov7670_drive_top
本模块是整个ov7670驱动及数据预处理的顶层模块。
3
ov7670_sccb_controler
本模块是ov7670驱动sccb协议的主控部分(主控+寄存器配置+sccb协议),主要实现的功能是对寄存器模块的调用以及对sccb协议模块的反馈信号进行相应操作。
4
ov7670_register_config
本模块是ov7670驱动sccb协议的寄存器配置部分(主控+寄存器+sccb协议),主要实现的功能是根据主控模块进行操作,对ov7670内部寄存器进行配置,并将配置完的数据发送给sccb协议模块处理并最终输出给ov7670。
5
ov7670_sccb
本模块是ov7670驱动sccb协议的sccb协议驱动的部分(主控+寄存器+sccb协议),主要实现的功能是完成sccb协议的模拟,把寄存器配置部分的数据即SDATA写入ov7670.另外也可以完成对ov7670的数据读取。最终完成对ov7670初始化。
6
ov7670_pretreatment
本模块完成的功能主要是对ov7670采集后数据进行预处理,因为ov7670一开始出来的10帧数据可能不稳定,所以把前10帧数据除去再接收,同时把8位数据合成为16位。这部分涉及到ov7670时钟信号和数据信号一些时序的问题。
表 10 例程各模块说明
在例程中,我们还使用了SignalTapII 来观察FPGA开发板对ov7670的驱动情况。
嵌入式逻辑分析仪测试结果如下
https://item.taobao.com/item.htm?spm=a1z10.1-c.w4004-24211932856.7.489d7241aCjspB&id=35795666317