一视频处理FPGA驱动OV7725摄像头模块
Posted @晓凡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一视频处理FPGA驱动OV7725摄像头模块相关的知识,希望对你有一定的参考价值。
使用的模块是正点原子的ov7725不带fifo的摄像头,开发板是正点原子的开拓者。
一、SCCB协议与IIC协议的不同
摄像头采用的是SCCB协议,这个协议与I2C协议很像,但是有细微的区别。差别在于
- SCCB传输协议中,第9位为不必关心位,而IIC写传输协议位答应位
- SCCB每次传输过程不超过3个阶段,即不能连续读写
- SCCB读传输协议中没有重复开始的概念,在写完寄存器地址后,发起停止信号
OV7725支持不同分辨率图像的输出,包括VGA(640480)、QCVGA(320240)等。OV7725支持多种不同的数据像素格式,包括YUV(亮度参量和色度参量分开表示的像素格式)、RGB(其中RGB格式包含RGB565、RGB555)以及8位的RAW(原始图像数据)和10位的RAW。
二、OV7725图像输出时序
三、硬件接口和系统框图
四、i2c_ov7725_rgb565_cfg代码
这个模块需要跟i2c_dri模块搭配一起使用,i2c_ov7725_rgb565_cfg模块复制将参数传送给i2c_dri模块,然后由i2c_dri模块完成摄像头的配置
module i2c_ov7725_rgb565_cfg(
input clk , //时钟信号
input rst_n , //复位信号,低电平有效
input i2c_done , //I2C寄存器配置完成信号
output reg i2c_exec , //I2C触发执行信号
output reg [15:0] i2c_data , //I2C要配置的地址与数据(高8位地址,低8位数据)
output reg init_done //初始化完成信号
);
//parameter define
parameter REG_NUM = 7'd70 ; //总共需要配置的寄存器个数
//reg define
reg [9:0] start_init_cnt; //等待延时计数器
reg [6:0] init_reg_cnt ; //寄存器配置个数计数器
//*****************************************************
//** main code
//*****************************************************
//cam_scl配置成250khz,输入的clk为1Mhz,周期为1us,1023*1us = 1.023ms
//寄存器延时配置
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
start_init_cnt <= 10'b0;
else if((init_reg_cnt == 7'd1) && i2c_done)
start_init_cnt <= 10'b0;
else if(start_init_cnt < 10'd1023) begin
start_init_cnt <= start_init_cnt + 1'b1;
end
end
//寄存器配置个数计数
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
init_reg_cnt <= 7'd0;
else if(i2c_exec)
init_reg_cnt <= init_reg_cnt + 7'b1;
end
//i2c触发执行信号
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
i2c_exec <= 1'b0;
else if(start_init_cnt == 10'd1022)
i2c_exec <= 1'b1;
//只有刚上电和配置第一个寄存器增加延时
else if(i2c_done && (init_reg_cnt != 7'd1) && (init_reg_cnt < REG_NUM))
i2c_exec <= 1'b1;
else
i2c_exec <= 1'b0;
end
//初始化完成信号
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
init_done <= 1'b0;
else if((init_reg_cnt == REG_NUM) && i2c_done)
init_done <= 1'b1;
end
//配置寄存器地址与数据
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
i2c_data <= 16'b0;
else begin
case(init_reg_cnt)
//先对寄存器进行软件复位,使寄存器恢复初始值
//寄存器软件复位后,需要延时1ms才能配置其它寄存器
//i2c_data 高8位地址,低8位为数据
7'd0 : i2c_data <= 8'h12, 8'h80; //COM7 BIT[7]:复位所有的寄存器
7'd1 : i2c_data <= 8'h3d, 8'h03; //COM12 模拟过程直流补偿
7'd2 : i2c_data <= 8'h15, 8'h00; //COM10 href/vsync/pclk/data信号控制
7'd3 : i2c_data <= 8'h17, 8'h26; //HSTART 水平起始位置
7'd4 : i2c_data <= 8'h18, 8'ha0; //HSIZE 水平尺寸
7'd5 : i2c_data <= 8'h19, 8'h07; //VSTRT 垂直起始位置
7'd6 : i2c_data <= 8'h1a, 8'hf0; //VSIZE 垂直尺寸
7'd7 : i2c_data <= 8'h32, 8'h00; //HREF 图像开始和尺寸控制,控制低位
7'd8 : i2c_data <= 8'h29, 8'ha0; //HOutSize 水平输出尺寸
7'd9 : i2c_data <= 8'h2a, 8'h00; //EXHCH 虚拟像素MSB
7'd10 : i2c_data <= 8'h2b, 8'h00; //EXHCL 虚拟像素LSB
7'd11 : i2c_data <= 8'h2c, 8'hf0; //VOutSize 垂直输出尺寸
7'd12 : i2c_data <= 8'h0d, 8'h41; //COM4 PLL倍频设置(multiplier)
//Bit[7:6]: 0:1x 1:4x 2:6x 3:8x
7'd13 : i2c_data <= 8'h11, 8'h00; //CLKRC 内部时钟配置
//Freq=multiplier/[(CLKRC[5:0]+1)*2]
7'd14 : i2c_data <= 8'h12, 8'h06; //COM7 输出VGA RGB565格式
7'd15 : i2c_data <= 8'h0c, 8'h10; //COM3 Bit[0]: 0:图像数据 1:彩条测试
//DSP 控制
7'd16 : i2c_data <= 8'h42, 8'h7f; //TGT_B 黑电平校准蓝色通道目标值
7'd17 : i2c_data <= 8'h4d, 8'h09; //FixGain 模拟增益放大器
7'd18 : i2c_data <= 8'h63, 8'hf0; //AWB_Ctrl0 自动白平衡控制字节0
7'd19 : i2c_data <= 8'h64, 8'hff; //DSP_Ctrl1 DSP控制字节1
7'd20 : i2c_data <= 8'h65, 8'h00; //DSP_Ctrl2 DSP控制字节2
7'd21 : i2c_data <= 8'h66, 8'h00; //DSP_Ctrl3 DSP控制字节3
7'd22 : i2c_data <= 8'h67, 8'h00; //DSP_Ctrl4 DSP控制字节4
//AGC AEC AWB
//COM8 Bit[2]:自动增益使能 Bit[1]:自动白平衡使能 Bit[0]:自动曝光功能
7'd23 : i2c_data <= 8'h13, 8'hff; //COM8
7'd24 : i2c_data <= 8'h0f, 8'hc5; //COM6
7'd25 : i2c_data <= 8'h14, 8'h11;
7'd26 : i2c_data <= 8'h22, 8'h98;
7'd27 : i2c_data <= 8'h23, 8'h03;
7'd28 : i2c_data <= 8'h24, 8'h40;
7'd29 : i2c_data <= 8'h25, 8'h30;
7'd30: i2c_data <= 8'h26, 8'ha1;
7'd31: i2c_data <= 8'h6b, 8'haa;
7'd32: i2c_data <= 8'h13, 8'hff;
//matrix sharpness brightness contrast UV
7'd33 : i2c_data <= 8'h90, 8'h0a; //EDGE1 边缘增强控制1
//DNSOff 降噪阈值下限,仅在自动模式下有效
7'd34 : i2c_data <= 8'h91, 8'h01; //DNSOff
7'd35 : i2c_data <= 8'h92, 8'h01; //EDGE2 锐度(边缘增强)强度上限
7'd36 : i2c_data <= 8'h93, 8'h01; //EDGE3 锐度(边缘增强)强度下限
7'd37 : i2c_data <= 8'h94, 8'h5f; //MTX1 矩阵系数1
7'd38 : i2c_data <= 8'h95, 8'h53; //MTX1 矩阵系数2
7'd39 : i2c_data <= 8'h96, 8'h11; //MTX1 矩阵系数3
7'd40 : i2c_data <= 8'h97, 8'h1a; //MTX1 矩阵系数4
7'd41 : i2c_data <= 8'h98, 8'h3d; //MTX1 矩阵系数5
7'd42 : i2c_data <= 8'h99, 8'h5a; //MTX1 矩阵系数6
7'd43 : i2c_data <= 8'h9a, 8'h1e; //MTX_Ctrl 矩阵控制
7'd44 : i2c_data <= 8'h9b, 8'h3f; //BRIGHT 亮度
7'd45 : i2c_data <= 8'h9c, 8'h25; //CNST 对比度
7'd46 : i2c_data <= 8'h9e, 8'h81;
7'd47 : i2c_data <= 8'ha6, 8'h06; //SDE 特殊数字效果控制
7'd48 : i2c_data <= 8'ha7, 8'h65; //USAT "U"饱和增益
7'd49 : i2c_data <= 8'ha8, 8'h65; //VSAT "V"饱和增益
7'd50 : i2c_data <= 8'ha9, 8'h80; //VSAT "V"饱和增益
7'd51 : i2c_data <= 8'haa, 8'h80; //VSAT "V"饱和增益
//伽马控制
7'd52 : i2c_data <= 8'h7e, 8'h0c;
7'd53 : i2c_data <= 8'h7f, 8'h16;
7'd54 : i2c_data <= 8'h80, 8'h2a;
7'd55 : i2c_data <= 8'h81, 8'h4e;
7'd56 : i2c_data <= 8'h82, 8'h61;
7'd57 : i2c_data <= 8'h83, 8'h6f;
7'd58 : i2c_data <= 8'h84, 8'h7b;
7'd59 : i2c_data <= 8'h85, 8'h86;
7'd60 : i2c_data <= 8'h86, 8'h8e;
7'd61 : i2c_data <= 8'h87, 8'h97;
7'd62 : i2c_data <= 8'h88, 8'ha4;
7'd63 : i2c_data <= 8'h89, 8'haf;
7'd64 : i2c_data <= 8'h8a, 8'hc5;
7'd65 : i2c_data <= 8'h8b, 8'hd7;
7'd66 : i2c_data <= 8'h8c, 8'he8;
7'd67 : i2c_data <= 8'h8d, 8'h20;
7'd68 : i2c_data <= 8'h0e, 8'h65; //COM5
7'd69 : i2c_data <= 8'h09, 8'h00; //COM2 Bit[1:0] 输出电流驱动能力
//只读存储器,防止在case中没有列举的情况,之前的寄存器被重复改写
default:i2c_data <= 8'h1C, 8'h7F; //MIDH 制造商ID 高8位
endcase
end
end
endmodule
---晓凡 2022年7月于桂林书
VerilogFPGA驱动Ov7670/Ov7725搭建视频通路(RGB565灰度图)
一、课题功能指标要求
(一)课程目的
• 加深对数字电路时序的理解;
• 掌握 OV 系列摄像头输出时序;
• 掌握 I2C 总线时序,以及使用 verilog 驱动三态门的方法;
• 掌握数字系统设计的方法;
(二)设计任务
o 设计并利用 FPGA 实现 OV7670(Ov7725)~VGA(320*240)显示器的视频通路;
o (基本要求)设计 I2C 总线接口以及控制器,实现对摄像头的配置;
o (基本要求)设计 OV7670(Ov7725) 输出转简单格式模块;
o (基本要求)利用 BRAM 搭建图像帧缓冲空间;
o (基本要求)设计 VGA 显示模块,显示摄像头输入的图像;
o (提高要求)使用双缓冲机制搭建视频通路;
o (提高要求)设计 RGB565 转灰度图模块,可利用拨码开关选择显示彩图或是灰度图;
(三)验收功能指标
1、输入时序的仿真波形;
2、图像在输入情况良好的情况下不撕裂,无歪斜或平移;
3、所有电路均采用同步电路的设计方法,除输入模块以外均采用同一个时钟驱动。
二、系统硬件描述
(一)系统硬件框图
其中,OV76760和显示屏为单独外设,FPGA主控模块和SRAM模块均为EGO1FPGA板板载资源。
(二)OV7670概述
- 阿汪先生的相关笔记:CMOS图像传感器-OV7670.
1、功能描述
OV7670/OV7171_CAMERACHIPTM 图像传感器,体积小、工作电压低,提供单片 VGA 摄像头和影像处理器的所有功能。通过 SCCB 总线控制,可以输出整帧、子采样、取窗口等方式的各种分辨率 8 位影响数据。该产品 VGA 图像最高达到 30 帧/秒。
用户可以完全控制图像质量、数据格式和传输方式。所有图像处理功能过程包括伽玛曲线、白平衡、饱和度、色度等都可以通过 SCCB 接口编程。OmmiVision 图像传感器应用独有的传感器技术,通过减少或消除光学或电子缺陷如固定图案噪声、托尾、浮散等,提高图像质量,得到清晰的稳定的彩色图像。
2、性能参数
(1) 高灵敏度适合低照度应用
(2) 低电压适合嵌入式应用
(3) 标准的 SCCB 接口,兼容 I2C 接口
(4)RawRGB,RGB(GRB4:2:2,RGB565/555/444),YUV (4:2:2)和 YCbCr(4:2:2)输出格式
(5) 支持 VGA,CIF,和从 CIF 到 40x30 的各种尺寸
(6) VarioPixel 子采样方式
(7) 自动影响控制功能包括:自动曝光控制、自动增益控制、自动白平衡,自动消除灯 光条纹、自动黑电平校准、图像质量控制
(8) ISP 具有消除噪声和坏点补偿功能
(9) 支持闪光灯:LED 灯和氙灯
(10) 支持图像缩放
(11) 镜头失光补偿
(12)50/60Hz 自动检测
(13) 饱和度自动调节(UV 调整)
(14) 边缘增强自动调节
(15) 降噪自动调
3、功能模块
功能模块包括:感光阵列(共有 656x488 个像素,其中在 YUV 的模式中,有效像素为640x480 个) 、模拟信号处理 、A/D 转换 、测试图案发生器 、数字信号处理器 、图像缩放 、时序发生器 、数字视频端口、SCCB 接口 、LED 和闪光灯输出控。
4、功能框
OV7670内部功能框图:
5、时序框图
OV7670摄像头的接口为SCCB接口,其时序图如下。
一行图像数据获取时序图如下:
一帧图像数据获取时序图如下:
(1) SCCB简介
SCCB协议有两线也有三线,两线为SIO_C与SIO_D,三线为SIO_E、SIO_C 与SIO_D。2线的SCCB总线只能是一个主器件对一个从器件控制,但3线SCCB接口可以对多个从器件控制,因此当只有一个从机(slave device)时用两线,有多个从机时用三线。其中SIO_C只能由主机配置(FPGA),SIO_D是一个三态门, 双向数据线,既可以由主机控制,也可以由从机控制。
(2) 数据传输
当写数据到从机被定义为写传输(write transmission),当从机中读数据被定义为读传输 (read transmission),每一个传输都要有开始和结束来释放总线(start + sotp)
完整的数据传输包括两个或三个阶段,每一个阶段包含9位数据,其中高8位为所要传输 的数据,最低位根据器件所处情况有不同的取值。
规律如下:
-
每一个阶段组成:8位数据+don’t care/NA
如果是主机发送数据,即进行写操作,第九位就为don’t care 如果是从机发送数据,即为读操作,第九位就为NA。 -
在进行主器件写操作时,全部阶段的最低位均是Don’t care bit 写操作:三个阶段构成传输的写,每个阶段都为9位
ID地址(7位ID地址+1位读写控制+don’t care) + 要写的寄存器地址(8位寄存器地址+don’t care) +要写入的数据(8位数据+don’t care)
ID地址组成:
- 写操作有: start + ID地址(地址位42)+ 寄存器地址 + 数据 + stop
- 读操作:根据SCCB接口的读操作时序有两个阶段传输组成。2个阶段写传输 + 2个阶段读传输,每一相都是9位,具体如下:
- ID地址(8位ID地址+1位读写控制+don’t care)+ FPGA要向从机写入即将要读的寄存器地址(8位寄存器地址+don’t care)
- ID地址(8位ID地址+1位读写控制+don’t care) +从机向FPGA发送被指定寄存器里面的数据的数据(8位数据+NA)
- 读操作为:
- start1+ ID地址(42)+ 寄存器地址 +stop1+start 2 +ID地址(43)+ 数据 + stop2
总结如下:
每一个阶段组成:8位数据+don’t care/NA
如果是主机发送数据,即进行写操作,第九位就为don’t care 如果是从机发送数据,即为读操作,第九位就为NA.
在进行主器件写操作时,全部阶段的最低位均是Don’t care bit
(三)VGA显示模块
VGA接口是一种D型接口,上面共有15针孔,分成三排,每排五个,其中比较重要的是 3根RGB彩色分量信号和2根扫描同步信号HSYNC和VSYNC针,其引脚编号图如下所示:
VGA 显示器扫描方式从屏幕左上角一点开始,从左向右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,CRT 对电子束进行消隐,每行结束时, 用行同步信号进行同步;
当扫描完所有的行,形成一帧,用场同步信号进行场同步,并使扫描回到屏幕左上方,同时进行场消隐,开始下一帧。
完成一行扫描的时间称为水平扫描时间,其倒数称为行频率;完成一帧(整屏)扫描的 时间称为垂直扫描时间,其倒数称为场频率,即屏幕的刷新频率。
行扫描:Hor Sync 、Hor Back Porch 、Hor Active Video和Hor Front Porch
Hor Scan Time是一个扫描周期,它会先扫描到Hor Sync、再扫描Hor Back Porch,然后才进入有效显示区Hor Active Video,最后是一段Hor Front Porch;
可以看出来,四段区间只有Hor Active Video这一段是能够正常显示图像信息的,也就是屏幕上显示的那一块区间。
列扫描:Ver Sync 、Ver Back Porch 、Ver Active Video和Ver Front Porch
Ver Scan Time是一个扫描周期,它会先扫描到Ver Sync、再扫描Ver Back Porch,然后才进入有效显示区Ver Active Video,最后是一段Ver Front Porch;可以看出来,四段区间只有Ver Active Video这一段是能够正常显示图像信息的,也就是屏幕上显示的那一块区间。
VGA常用的分辨率时序参数如下图所示:
VGA在显示屏上的显示范围如下图所示:
三、软件设计描述
(一)软件设计框图
(二)I2C驱动模块
- 阿汪先生的相关笔记:I2C协议.
1、 SCCB 接口
OV7670 摄像头接口为 SCCB 接口。SCCB 接口是特殊的 I2C 协议,SCCB 与 I2C 的具体差异如下:
(1) SCCB传输协议中,第9位为不必关心位,而IIC写传输协议为应答位。
(2) SCCB每次传输过程不超过3个阶段,即不能连续读写。
(3) SCCB读传输协议中没有重复开始的概念,在写完寄存器地址后,发起停止信号。
2、I2C协议概述
(1) 总线空闲状态:SDA为高电平,SCL为高电平
I2C协议起始位:SCL为高电平时,SDA出现下降沿,产生一个起始位 I2C协议结束位:SCL为高电平时,SDA出现上升沿,产生一个结束位SCL低电平时,SDA线上的数据变化(SCL:100k~400k,最大可达3.4M) SCL高电平时,SDA线上的数据被读取
(2) 应答位
每当数据接收方正确接收一个字节的指令或数据,都会产生一个应答位(ACK) 每当数据发送方发送完一个字节的数据或指令后,应该将SDA信号设置为三态输入 。
由于总线上拉电阻的存在,此时SDA信号线为高电平。数据接收方控制SDA信号线,如果正确接收数据,则将SDA信号线拉为低电平。
3、I2C器件地址
每一个I2C器件都有一个器件地址。
有的器件地址出厂即设置好了。有的设置好了几位(如常见的I2C接口的EEPROM存储器,留有3个控制地址的引脚,由用户自己在硬件设计时确定)。
主机向总线发送地址,所有从机接收并与自己地址识别,如果地址匹配,该从机想总线 发送响应信号,主机收到响应信号,开始向总线发送数据。若主机没有收到响应信号,则表 示寻址失败。
摄像头OV7670,其器件地址固定为0x42。
4、工作状态
在本次项目设计中,我们只需要用I2C协议对摄像头OV7670进行写操作,初始化
OV7670的寄存器参数以控制其输出格式。
(1) 写时序概述
(单个)写时序:主机---->发生控制字节—>从机应答---->主机传存储器地址---->传数据。
(单个)写时序:起始位—>控制字节(最低位为0)—>应答位—>一个字节的存储器地址—>应答位—一个字节的存储器地址(可选)—应答位(可选)—写入一个字节的数据应答位……停止位
(2) 写时序具体过程:
● 主机设置SDA为输出
● 主机产生起始信号
● 主机传输器件地址字节,其中最低位位0,表明为写操作
● 主机设置SDA为三态门输入,读取从机应答信号
● 读取应答信号成功,主机设置SDA为输出,传输1字节地址数据
● 主机设置SDA为三态门输入,读取从机应答信号
● 读取应答信号成功,对于2字节地址段器件,传输地址数据低字节;对于1字节地 址段器件,主机设置SDA为输出,传输待写入的数据。
● 设置SDA为三态门输入,读取从机应答信号,对于2字节地址段器件,执行下一步 骤;对于1字节地址段器件,直接跳转到最后一步。
● 读取应答信号成功,主机设置SDA为输出,传输待写入的数据
● 设置SDA为三态门输入,读取从机应答信号
● 读取应答信号成功,主机产生STOP位,终止传输。
5、vivado中的电路原理图
(三)I2C配置模块
1、模块概述
在系统开始工作之前,I2C驱动模块必须向摄像头OV7670发送初始化信号,对摄像头的 工作方式(寄存器)进行初始化。
本模块主要是在I2C驱动模块发送0V7670器件地址0x42后,将SDA信号线设置为三态输 入,因为的存在,此时SDA为高电平,摄像头响应地址后会将SDA信号线拉为低电平。
每一个支持I2C协议的器件,内部总会有一些可供读/写的寄存器。
OV7670的CMOS摄像头: 内部是一系列编址的可供读/写的寄存器。通过对这些寄存器写入数据来初始化摄像头的功能和工作方式。
2、主要代码摘录
//配置寄存器地址与数据
//这里配置的是Ov7725的寄存器,其它摄像头的配置根据相关数据手册即可
always @(posedge clk or negedge rst_n) begin if(!rst_n)
i2c_data <= 16'b0; else begin
case(init_reg_cnt)
//先对寄存器进行软件复位,使寄存器恢复初始值
//寄存器软件复位后,需要延时1ms才能配置其它寄存器
7'd0 : i2c_data <= 8'h12, 8'h80; //COM7 BIT[7]:复位所有的寄存器
7'd1 : i2c_data <= 8'h3d, 8'h03; //COM12 模拟过程直流补偿
7'd2 : i2c_data <= 8'h15, 8'h00; //COM10 href/vsync/pclk/data信号控制7'd3 : i2c_data <= 8'h17, 8'h3f;//8'h17, 8'h26; //HSTART 水平起始位置
7'd4 : i2c_data <= 8'h18, 8'h50;//8'h18, 8'ha0; //HSIZE 水平尺寸
7'd5 : i2c_data <= 8'h19, 8'h03;//8'h19, 8'h07; //VSTRT 垂直起始位置
7'd6 : i2c_data <= 8'h1a, 8'h78;//8'h1a, 8'hf0; //VSIZE 垂直尺寸
7'd7 : i2c_data <= 8'h32, 8'h00; //HREF 图像开始和尺寸控制,控制低位
7'd8 : i2c_data <= 8'h29, 8'h50;//8'h29, 8'ha0; //HOutSize 水平输出尺寸
7'd9 : i2c_data <= 8'h2a, 8'h00; //EXHCH 虚拟像素MSB
7'd10 : i2c_data <= 8'h2b, 8'h9e;//8'h2b, 8'h00; //EXHCL 虚 拟 像 素 LSB 7'd11 : i2c_data <= 8'h2c, 8'h78;//8'h2c, 8'hf0; //VOutSize 垂直输出尺寸7'd12 : i2c_data <= 8'h0d, 8'h41; //COM4 PLL倍频设置(multiplier)
7'd13 : i2c_data <= 8'h11, 8'h00; //CLKRC 内部时钟配置
//Freq=multiplier/[(CLKRC[5:0]+1)*2]
7'd14 : i2c_data <= 8'h12, 8'h46;//8'h12, 8'h06; //COM7 输出QVGA(320*240)
7'd15 : i2c_data <= 8'h0c, 8'h90;//8'h0c, 8'h10; //COM3 Bit[0]: 0:图像数据 1:
这里列举出一部分初始化寄存器的代码,OV7670的内部寄存器总共有201个,实际使用过程中,我们可以根据需要对相关寄存器进行初始化。
3、 vivado中的电路原理图
4、程序流程图
(四)CMOS图像数据采集模块
CMOS图像数据采集模块,需等待I2C协议对摄像头内部寄存器进行初始化。寄存器全部配置完成后,还需等待10帧数据,此等待10帧数据的目的是等待摄像头工作状态稳定。
待寄存器配置生效、摄像头工作状态稳定后再开始采集图像。
具体地,待等待帧数等于10时,会使能标志信号frame_val_flag,使得OV77670开始对采集的图像数据中相应范围0~76800(340x240)的8位像素点数据经拼接操作,转存到寄存器data2ram中,data2ram将输出拼接后的16位数据到SRAM模块的输入引脚dina。
不同的摄像头的初始化,主要是根据性能参数、工作需要以及手册,初始化不同的寄存器参数。
代码摘录:
//将cmos_frame_valid转为ram地址
always @(posedge cam_pclk or negedge rst_n) begin if (!rst_n) begin //复位
addr<=0; data2ram<=0;
end
else if (addr>=76800) begin //320*240=76800 addr<=0; //像素地址回到初始位置
end
else if (cmos_frame_valid) begin addr<=addr+1;
data2ram<=cmos_frame_data;//使其和使能一样延迟一个时钟
end
end
//8位数据转16位RGB565数据
always @(posedge cam_pclk or negedge rst_n) begin
if(!rst_n) begin //复位
cmos_data_t <= 16'd0; cam_data_d0 <= 8'd0; byte_flag <= 1'b0;
end
else if(cam_href) begin
byte_flag <= ~byte_flag; //翻转标志位cam_data_d0 <= cam_data;
end
if(byte_flag)
cmos_data_t <= cam_data_d0,cam_data; //8位拼接16位
else begin
byte_flag <= 1'b0; cam_data_d0 <= 8'b0;
end
end
摄像头像素点数据输出:
2、Vivado中的电路原理图
(五)SRAM存储模块
1、概述
这部分模块主要通过调用ROM IP Core实现。点击IP Catalog,在搜索框中搜索block。选择Single Port ROM,图片位宽为16bit,深度为340x240=76800,表示有76800个16bit的RGB565像素。
图3.5.1. 调用配置IP核
RAM.ROM读取有延时,要在扫描第一个点的前两个时钟周期读取RAM/ROM,我在这里用的 是双口RAM,在Vivado这里显示的是有两个时钟的周期的延时,也就是当你给读命令时,RAM会把读出来的数据缓存两级才会输出给你想给数据的地方。
2、模块单独仿真时的时序图如下。
图3.5.2. SRAM传输数据时序图
3、Vivado中的电路原理图
(六)VGA驱动模块
VGA扫描显示其实就是两条线,一个行扫描,一个场扫描,在行有效和场有效的时候把 数据发送给VGA显示。
显示屏扫描方式分为逐行扫描和隔行扫描:逐行扫描是扫描从屏幕左上角一点开始,从左像右逐点扫描,每扫描完一行,电子书回到屏幕的左边下一行的起始位置,在这器件,CRT 对电子束进行消隐,每行结束时,用场同步信号进行场同步,并使扫描回到屏幕左上方,同 时进行场消隐,开始下一帧。VGA时序过程前面已有介绍,隔行扫描方式在此也不赘述了。
1、主要代码摘录
//RGB565数据输出
assign vga_rgb = vga_en ? pixel_data : 16'd0;
assign vga_gray = vga_en ? Y : 16'd0;
//扩展8位
always @(posedge vga_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
r1<=0; g1<=0; b1<=0;
end
else begin
r1<=pixel_data[15:11],pixel_data[15:13];
g1<=pixel_data[10:5],pixel_data[10:9];
b1<=pixel_data[4:0],pixel_data[4:2];
end
end
//生成灰度图
always @(posedge vga_clk or negedge sys_rst_n)begin
if (!sys_rst_n) begin
R_mult<=0; G_mult<=0; B_mult<=0;
end
else begin
R_mult <= r1 * 76;
G_mult <= g1 * 150;
B_mult <= b1 * 30;
end
end
always @(posedge vga_clk or negedge sys_rst_n) begin if (!sys_rst_n)
begin
Y<=0;
end
else begin
Y<=(R_mult+G_mult+B_mult)>>8;
end
end
//选择输出格式
//vga_en为像素有效标志
//switch为拨码开关,选择RGB/灰度图显示
assign vga_rgb0=(vga_en==1)?vga_rgb[15:12],vga_rgb[10:7],vga_rgb[4:1]:12'hfff;
assign vga_rgb1=(vga_en==1)?vga_gray[7:4],vga_gray[7:4],vga_gray[7:4]:12'hfff;
assign vga_rgb_444 = vga_en0 ? (swtich ? vga_rgb0:vga_rgb1 ) :12'h000;
2、Vivado中的电路原理图
四、测试与总结
(一)测试结果分析
灰度图显示:
彩色图显示:
1、基本完成所有的设计要求:
(1) 设计I2C总线接口以及控制器,实现对摄像头的配置;
(2) 设计OV7670输出转简单格式模块;
(3) 利用BRAM搭建图像帧缓冲空间;
(4) 设计VGA显示模块,显示摄像头输入的图像;
(5) 使用双缓冲机制搭建视频通路;
(6) 设计RGB565转灰度图模块,可利用拨码开关选择显示彩图或是灰度图;
2、还存在的问题
在RGB彩色输出切换至灰度图输出时,由于有2个像素时钟的延时,在VGA显示屏上显示的灰度图区域会较彩色图向右平移2个像素点。
这是由于灰度图转换成彩色图需要经过2个像素时钟的计算过程,这2个像素时钟的延时 导致了显示区域的右移。
3、解决方案试想
(1) 彩色图显示的时钟也延时2个像素延时
(2) 给灰度图显示单独分配一个时钟时间有限上述试想未付诸实践。
(二)最终实现效果。
阿汪先生的演示视频.
(三)附录一张失败画面。
//有一张蛮有意思的图片(多层画面重叠、画中画??)没保存下来。。。
以上是关于一视频处理FPGA驱动OV7725摄像头模块的主要内容,如果未能解决你的问题,请参考以下文章
VerilogFPGA驱动Ov7670/Ov7725搭建视频通路(RGB565灰度图)