一视频处理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
		---晓凡 20227月于桂林书

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概述

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驱动模块

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灰度图)

VerilogFPGA驱动Ov7670/Ov7725搭建视频通路(RGB565灰度图)

摄像头图像采集基础知识总结

STM32 OV7725 传感器

FPGA驱动OV5640用VGA显示画面上有很多彩色条纹

OV7725初始化配置