大家好,又见面了,我是你们的朋友全栈君。
一、课题功能指标要求
(一)课程目的
• 加深对数字电路时序的理解; • 掌握 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 到 40×30 的各种尺寸 (6) VarioPixel 子采样方式 (7) 自动影响控制功能包括:自动曝光控制、自动增益控制、自动白平衡,自动消除灯 光条纹、自动黑电平校准、图像质量控制 (8) ISP 具有消除噪声和坏点补偿功能 (9) 支持闪光灯:LED 灯和氙灯 (10) 支持图像缩放 (11) 镜头失光补偿 (12)50/60Hz 自动检测 (13) 饱和度自动调节(UV 调整) (14) 边缘增强自动调节 (15) 降噪自动调
3、功能模块
功能模块包括:感光阵列(共有 656×488 个像素,其中在 YUV 的模式中,有效像素为640×480 个) 、模拟信号处理 、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、主要代码摘录
代码语言:javascript复制//配置寄存器地址与数据
//这里配置的是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(340×240)的8位像素点数据经拼接操作,转存到寄存器data2ram中,data2ram将输出拼接后的16位数据到SRAM模块的输入引脚dina。 不同的摄像头的初始化,主要是根据性能参数、工作需要以及手册,初始化不同的寄存器参数。 代码摘录:
代码语言:javascript复制//将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
代码语言:javascript复制//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,深度为340×240=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、主要代码摘录
代码语言:javascript复制//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
代码语言:javascript复制//生成灰度图
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
代码语言:javascript复制//选择输出格式
//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) 给灰度图显示单独分配一个时钟时间有限上述试想未付诸实践。
(二)最终实现效果。
阿汪先生的演示视频.
(三)附录一张失败画面。
//有一张蛮有意思的图片(多层画面重叠、画中画??)没保存下来。。。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。