超级版主
- 积分
- 4676
- 金钱
- 4676
- 注册时间
- 2019-5-8
- 在线时间
- 1224 小时
|
本帖最后由 正点原子运营 于 2021-10-30 10:19 编辑
1)实验平台:正点原子新起点V2FPGA开发板
2) 章节摘自【正点原子】《新起点之FPGA开发指南 V2.1》
3)购买链接:https://detail.tmall.com/item.htm?id=609758951113
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz_xinqidian(V2).html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子FPGA技术交流QQ群:712557122
第四十二章 OV5640摄像头HDMI显示实验
在OV5640摄像头RGB-LCD显示实验中,成功地在LCD屏上实时显示出了摄像头采集的图像。本章将使用FPGA开发板实现对OV5640的数字图像采集并在HDMI显示器上实时显示。
本章包括以下几个部分:
4141.1简介
41.2实验任务
41.3硬件设计
41.4程序设计
41.5下载验证
42.1简介
在“OV5640摄像头RGB-LCD显示实验”中对OV5640的视频传输时序、SCCB协议以及寄存器的配置信息等内容作了详细的介绍,如果大家对这部分内容不是很熟悉的话,请参考“OV5640摄像头RGB-LCD显示实验”中的OV5640简介部分。
42.2实验任务
本节实验任务是使用新起点开发板及OV5640摄像头实现图像采集,并通过HDMI接口驱动HDMI显示器,并实时显示出图像。
42.3硬件设计
摄像头扩展接口原理图及OV5640模块说明与“OV5640摄像头RGB-LCD显示实验”完全相同,请参考“OV5640摄像头RGB-LCD显示实验”硬件设计部分。HDMI接口部分的硬件设计请参考“HDMI彩条显示实验”中的硬件设计部分。
由于OV5640、HDMI接口和SDRAM引脚数目较多且在前面相应的章节中已经给出它们的管脚列表,这里不再列出管脚分配。
42.4程序设计
根据实验任务,首先我们设计如图 42.4.1所示的系统框图,本章实验的系统框架延续了“OV5640摄像头RGB-LCD显示实验”的整体架构。本次实验包括以下模块:时钟模块、IIC配置模块、IIC驱动模块、SDRAM控制器模块、摄像头图像采集模块和HDMI顶层模块。其中IIC配置模块、IIC驱动模块、摄像头图像采集模块和SDRAM控制器模块我们没有做任何修改,这些模块在“OV5640摄像头RGB-LCD显示实验”中已经说明过,这里不再详述,本次实验将LCD顶层模块替换成了HDMI顶层模块。因为本次实验用的是HDMI显示器来显示,所以需要将LCD顶层模块替换成HDMI顶层模块。本次实验也不需要图像尺寸配置模块,因为本次实验摄像头的分辨率是固定的,其分辨率为1280x800。
OV5640摄像头HDMI显示系统框图如下图所示:
图 42.4.1 顶层系统框图
由上图可知,本节实验有两个锁相环,其中pll_clk锁相环为IIC配置模块和SDRAM模块提供时钟信号,而clk_hdmi锁相环则是专门为HDMI控制模块提供时钟,本节实验采用的是1280*800的分辨率,因此clk_hdmi锁相环提供的像素时钟就是71Mhz(VESA标准)和355Mhz(并行转串行5倍时钟)。其他的模块像SDRAM控制器模块,HDMI控制器模块等等都在前面的实验中做过详细的讲解了,因此本节实验就不再重复讲解了,下面给出本节实验的顶层代码:
- 1 module ov5640_hdmi(
- 2 input sys_clk , //系统时钟
- 3 input sys_rst_n , //系统复位,低电平有效
- 4 //摄像头
- 5 input cam_pclk , //cmos 数据像素时钟
- 6 input cam_vsync , //cmos 场同步信号
- 7 input cam_href , //cmos 行同步信号
- 8 input [7:0] cam_data , //cmos 数据
- 9 output cam_rst_n , //cmos 复位信号,低电平有效
- 10 output cam_pwdn , //cmos 电源休眠模式选择信号
- 11 output cam_scl , //cmos SCCB_SCL线
- 12 inout cam_sda , //cmos SCCB_SDA线
- 13 //SDRAM
- 14 output sdram_clk , //SDRAM 时钟
- 15 output sdram_cke , //SDRAM 时钟有效
- 16 output sdram_cs_n , //SDRAM 片选
- 17 output sdram_ras_n, //SDRAM 行有效
- 18 output sdram_cas_n, //SDRAM 列有效
- 19 output sdram_we_n , //SDRAM 写有效
- 20 output [1:0] sdram_ba , //SDRAM Bank地址
- 21 output [1:0] sdram_dqm , //SDRAM 数据掩码
- 22 output [12:0] sdram_addr , //SDRAM 地址
- 23 inout [15:0] sdram_data , //SDRAM 数据
- 24 //HDMI接口
- 25 output tmds_clk_p, // TMDS 时钟通道
- 26 output tmds_clk_n,
- 27 output [2:0] tmds_data_p, // TMDS 数据通道
- 28 output [2:0] tmds_data_n
- 29 );
- 30
- 31 //parameter define
- 32 parameter SLAVE_ADDR = 7'h3c ; //OV5640的器件地址7'h3c
- 33 parameter BIT_CTRL = 1'b1 ; //OV5640的字节地址为16位 0:8位 1:16位
- 34 parameter CLK_FREQ = 27'd50_000_000 ; //i2c_dri模块的驱动时钟频率
- 35 parameter I2C_FREQ = 18'd250_000 ; //I2C的SCL时钟频率,不超过400KHz
- 36 parameter V_CMOS_DISP = 11'd800 ; //CMOS分辨率--行
- 37 parameter H_CMOS_DISP = 11'd1280 ; //CMOS分辨率--列
- 38 parameter TOTAL_H_PIXEL = 13'd2570 ; //CMOS分辨率--行
- 39 parameter TOTAL_V_PIXEL = 13'd980 ;
- 40
- 41 //wire define
- 42 wire clk_100m ; //100mhz时钟,SDRAM操作时钟
- 43 wire clk_100m_shift ; //100mhz时钟,SDRAM相位偏移时钟
- 44 wire clk_50m ;
- 45 wire hdmi_clk ;
- 46 wire hdmi_clk_5 ;
- 47 wire locked ;
- 48 wire locked_hdmi ;
- 49 wire rst_n ;
- 50 wire sys_init_done ; //系统初始化完成(sdram初始化+摄像头初始化)
- 51
- 52 wire i2c_exec ; //I2C触发执行信号
- 53 wire [23:0] i2c_data ; //I2C要配置的地址与数据(高8位地址,低8位数据)
- 54 wire i2c_done ; //I2C寄存器配置完成信号
- 55 wire i2c_dri_clk ; //I2C操作时钟
- 56 wire [ 7:0] i2c_data_r ; //I2C读出的数据
- 57 wire i2c_rh_wl ; //I2C读写控制信号
- 58 wire cam_init_done ; //摄像头初始化完成
- 59
- 60 wire wr_en ; //sdram_ctrl模块写使能
- 61 wire [15:0] wr_data ; //sdram_ctrl模块写数据
- 62 wire rd_en ; //sdram_ctrl模块读使能
- 63 wire [15:0] rd_data ; //sdram_ctrl模块读数据
- 64 wire sdram_init_done; //SDRAM初始化完成
- 65
- 66 //*****************************************************
- 67 //** main code
- 68 //*****************************************************
- 69
- 70 assign rst_n = sys_rst_n & locked & locked_hdmi;
- 71 //系统初始化完成:SDRAM和摄像头都初始化完成
- 72 //避免了在SDRAM初始化过程中向里面写入数据
- 73 assign sys_init_done = sdram_init_done & cam_init_done;
- 74 //电源休眠模式选择 0:正常模式 1:电源休眠模式
- 75 assign cam_pwdn = 1'b0;
- 76 assign cam_rst_n = 1'b1;
- 77
- 78 //锁相环
- 79 pll u_pll(
- 80 .areset (~sys_rst_n),
- 81 .inclk0 (sys_clk),
- 82 .c0 (clk_100m),
- 83 .c1 (clk_100m_shift),
- 84 .c2 (clk_50m),
- 85 .locked (locked)
- 86 );
- 87
- 88 pll_hdmi pll_hdmi_inst (
- 89 .areset ( ~sys_rst_n ),
- 90 .inclk0 ( sys_clk ),
- 91 .c0 ( hdmi_clk ),//hdmi pixel clock 71Mhz
- 92 .c1 ( hdmi_clk_5 ),//hdmi pixel clock*5 355Mhz
- 93 .locked ( locked_hdmi )
- 94 );
- 95
- 96 //I2C配置模块
- 97 i2c_ov5640_rgb565_cfg u_i2c_cfg(
- 98 .clk (i2c_dri_clk),
- 99 .rst_n (rst_n ),
- 100
- 101 .i2c_exec (i2c_exec ),
- 102 .i2c_data (i2c_data ),
- 103 .i2c_rh_wl (i2c_rh_wl ), //I2C读写控制信号
- 104 .i2c_done (i2c_done ),
- 105 .i2c_data_r (i2c_data_r ),
- 106
- 107 .cmos_h_pixel (H_CMOS_DISP ), //CMOS水平方向像素个数
- 108 .cmos_v_pixel (V_CMOS_DISP ), //CMOS垂直方向像素个数
- 109 .total_h_pixel (TOTAL_H_PIXEL), //水平总像素大小
- 110 .total_v_pixel (TOTAL_V_PIXEL), //垂直总像素大小
- 111
- 112 .init_done (cam_init_done)
- 113 );
- 114
- 115 //I2C驱动模块
- 116 i2c_dri #(
- 117 .SLAVE_ADDR (SLAVE_ADDR ), //参数传递
- 118 .CLK_FREQ (CLK_FREQ ),
- 119 .I2C_FREQ (I2C_FREQ )
- 120 )
- 121 u_i2c_dr(
- 122 .clk (clk_50m ),
- 123 .rst_n (rst_n ),
- 124
- 125 .i2c_exec (i2c_exec ),
- 126 .bit_ctrl (BIT_CTRL ),
- 127 .i2c_rh_wl (i2c_rh_wl ), //固定为0,只用到了IIC驱动的写操作
- 128 .i2c_addr (i2c_data[23:8]),
- 129 .i2c_data_w (i2c_data[7:0] ),
- 130 .i2c_data_r (i2c_data_r ),
- 131 .i2c_done (i2c_done ),
- 132 .scl (cam_scl ),
- 133 .sda (cam_sda ),
- 134 .dri_clk (i2c_dri_clk ) //I2C操作时钟
- 135 );
- 136
- 137 //CMOS图像数据采集模块
- 138 cmos_capture_data u_cmos_capture_data( //系统初始化完成之后再开始采集数据
- 139 .rst_n (rst_n & sys_init_done),
- 140
- 141 .cam_pclk (cam_pclk ),
- 142 .cam_vsync (cam_vsync),
- 143 .cam_href (cam_href ),
- 144 .cam_data (cam_data ),
- 145
- 146 .cmos_frame_vsync (),
- 147 .cmos_frame_href (),
- 148 .cmos_frame_valid (wr_en ), //数据有效使能信号
- 149 .cmos_frame_data (wr_data ) //有效数据
- 150 );
- 151
- 152
- 153 //SDRAM 控制器顶层模块,封装成FIFO接口
- 154 //SDRAM 控制器地址组成: {bank_addr[1:0],row_addr[12:0],col_addr[8:0]}
- 155 sdram_top u_sdram_top(
- 156 .ref_clk (clk_100m), //sdram 控制器参考时钟
- 157 .out_clk (clk_100m_shift), //用于输出的相位偏移时钟
- 158 .rst_n (rst_n), //系统复位
- 159
- 160 //用户写端口
- 161 .wr_clk (cam_pclk), //写端口FIFO: 写时钟
- 162 .wr_en (wr_en), //写端口FIFO: 写使能
- 163 .wr_data (wr_data), //写端口FIFO: 写数据
- 164 .wr_min_addr (24'd0), //写SDRAM的起始地址
- 165 .wr_max_addr (V_CMOS_DISP*H_CMOS_DISP-1), //写SDRAM的结束地址
- 166 .wr_len (10'd512), //写SDRAM时的数据突发长度
- 167 .wr_load (~rst_n), //写端口复位: 复位写地址,清空写FIFO
- 168
- 169 //用户读端口
- 170 .rd_clk (hdmi_clk), //读端口FIFO: 读时钟
- 171 .rd_en (rd_en), //读端口FIFO: 读使能
- 172 .rd_data (rd_data), //读端口FIFO: 读数据
- 173 .rd_min_addr (24'd0), //读SDRAM的起始地址
- 174 .rd_max_addr (V_CMOS_DISP*H_CMOS_DISP-1), //读SDRAM的结束地址
- 175 .rd_len (10'd512), //从SDRAM中读数据时的突发长度
- 176 .rd_load (~rst_n), //读端口复位: 复位读地址,清空读FIFO
- 177
- 178 //用户控制端口
- 179 .sdram_read_valid (1'b1), //SDRAM 读使能
- 180 .sdram_pingpang_en (1'b1), //SDRAM 乒乓操作使能
- 181 .sdram_init_done (sdram_init_done), //SDRAM 初始化完成标志
- 182
- 183 //SDRAM 芯片接口
- 184 .sdram_clk (sdram_clk), //SDRAM 芯片时钟
- 185 .sdram_cke (sdram_cke), //SDRAM 时钟有效
- 186 .sdram_cs_n (sdram_cs_n), //SDRAM 片选
- 187 .sdram_ras_n (sdram_ras_n), //SDRAM 行有效
- 188 .sdram_cas_n (sdram_cas_n), //SDRAM 列有效
- 189 .sdram_we_n (sdram_we_n), //SDRAM 写有效
- 190 .sdram_ba (sdram_ba), //SDRAM Bank地址
- 191 .sdram_addr (sdram_addr), //SDRAM 行/列地址
- 192 .sdram_data (sdram_data), //SDRAM 数据
- 193 .sdram_dqm (sdram_dqm) //SDRAM 数据掩码
- 194 );
- 195
- 196 //例化HDMI顶层模块
- 197 hdmi_top u_hdmi_top(
- 198 .hdmi_clk (hdmi_clk ),
- 199 .hdmi_clk_5 (hdmi_clk_5 ),
- 200 .rst_n (rst_n ),
- 201
- 202 .rd_data (rd_data ),
- 203 .rd_en (rd_en ),
- 204 .h_disp (),
- 205 .v_disp (),
- 206 .pixel_xpos (),
- 207 .pixel_ypos (),
- 208 .video_vs (),
- 209 .tmds_clk_p (tmds_clk_p ),
- 210 .tmds_clk_n (tmds_clk_n ),
- 211 .tmds_data_p (tmds_data_p),
- 212 .tmds_data_n (tmds_data_n)
- 213 );
- 214
- 215 endmodule
复制代码
FPGA顶层模块(ov5640_hdmi)例化了以下六个模块:时钟模块、I2C驱动模块(i2c_dri)、I2C配置模块(i2c_ov5640_rgb565_cfg)、摄像头图像采集模块(cmos_capture_data)、SDRAM读写控制模块(sdram_top)和HDMI顶层模块(hdmi_top)。
时钟模块:时钟模块通过调用PLL IP核实现,共输出5个时钟,频率分别为100M时钟、100M偏移-75度时钟、50M时钟、71Mhz时钟和355M时钟(HDMI像素时钟的5倍频)。其中pll 产生了50M时钟、100M时钟和100M偏移-75度时钟,pll_hdmi 产生了71Mhz时钟和355M时钟,这里之所以用两个锁相环是因为HDMI所用的时钟71Mhz与SDRAM控制模块使用的100M时钟不是整数倍,使用一个锁相环不符合设计要求。100Mhz时钟作为SDRAM控制模块的驱动时钟,100M偏移-75度时钟用来输出给外部SDRAM芯片使用,50Mhz时钟作为I2C驱动模块的驱动时钟,71Mhz时钟和355M时钟(HDMI像素时钟的5倍频)负责驱动HDMI顶层模块。
I2C驱动模块(i2c_dri):I2C驱动模块负责驱动OV5640 SCCB接口总线,用户可根据该模块提供的用户接口对OV5640的寄存器进行配置,该模块和“EEPROM读写实验”章节中用到的I2C驱动模块为同一个模块,有关该模块的详细介绍请大家参考“EEPROM读写实验”章节。
I2C配置模块(i2c_ov5640_rgb565_cfg):I2C配置模块的驱动时钟是由I2C驱动模块输出的时钟提供的,这样方便了I2C驱动模块和I2C配置模块之间的数据交互。该模块寄存需要配置的寄存器地址、数据以及控制初始化的开始与结束,同时该模块输出OV5640的寄存器地址和数据以及控制I2C驱动模块开始执行的控制信号,直接连接到I2C驱动模块的用户接口,从而完成对OV5640传感器的初始化。OV7725和OV5640寄存器配置时序非常相似,有关该模块的详细介绍请大家参考“OV7725摄像头RGB-LCD显示实验”章节。
摄像头图像采集模块(cmos_capture_data):摄像头采集模块在像素时钟的驱动下将传感器输出的场同步信号、行同步信号以及8位数据转换成SDRAM读写控制模块的写使能信号和16位写数据信号,完成对OV5640传感器图像的采集。OV7725和OV5640图像输出时序非常相似,有关该模块的详细介绍请大家参考“OV7725摄像头RGB-LCD显示实验”章节。
SDRAM读写控制模块(sdram_top):SDRAM读写控制器模块负责驱动SDRAM片外存储器,缓存图像传感器输出的图像数据。该模块将SDRAM复杂的读写操作封装成类似FIFO的用户接口,非常方便用户的使用。有关该模块的详细介绍请大家参考“SDRAM读写测试实验”章节,修改部分请大家参考“OV7725摄像头RGB-LCD显示实验”章节。
HDMI顶层模块(hdmi_top):HDMI顶层模块负责驱动HDMI显示器的驱动信号的输出,同时为其他模块提供显示器参数、场同步信号和数据请求信号。关HDMI顶层模块的详细介绍请大家参考“OV5640摄像头HDMI显示实验”章节。
42.5下载验证
编译完工程之后我们就可以开始下载程序。将OV5640摄像头模块插在新起点开发板“OLED/CAMERA”插座上,并将HDMI电缆一端连接到开发板上的HDMI插座、另一端连接到显示器。将下载器一端连电脑,另一端与开发板上的JTAG端口连接,连接电源线并打开电源开关。接下来我们下载程序,验证OV5640 HDMI实时显示功能。下载完成后观察HDMI显示器显示的图案如下图所示,说明OV5640 HDMI实时显示程序下载验证成功。
图 42.5.1 HDMI实时显示图像 |
|