超级版主 
   
	- 积分
 - 5083
 
        - 金钱
 - 5083 
 
       - 注册时间
 - 2019-5-8
 
      - 在线时间
 - 1269 小时
 
 
 
 | 
 
 本帖最后由 正点原子运营 于 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实时显示图像  |   
 
 
 
 |