OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3711|回复: 0

[ALTERA] 《新起点之FPGA开发指南 V2.1》第四十二章 OV5640摄像头HDMI显示实验

[复制链接]

1119

主题

1130

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4676
金钱
4676
注册时间
2019-5-8
在线时间
1224 小时
发表于 2021-10-27 10:40:50 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 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 QQ群.png

原子哥.jpg

微信公众号.png





第四十二章 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显示系统框图如下图所示:
第四十二章 OV5640摄像头HDMI显示实验937.png
图 42.4.1 顶层系统框图
由上图可知,本节实验有两个锁相环,其中pll_clk锁相环为IIC配置模块和SDRAM模块提供时钟信号,而clk_hdmi锁相环则是专门为HDMI控制模块提供时钟,本节实验采用的是1280*800的分辨率,因此clk_hdmi锁相环提供的像素时钟就是71Mhz(VESA标准)和355Mhz(并行转串行5倍时钟)。其他的模块像SDRAM控制器模块,HDMI控制器模块等等都在前面的实验中做过详细的讲解了,因此本节实验就不再重复讲解了,下面给出本节实验的顶层代码:
  1. 1   module ov5640_hdmi(   
  2. 2       input         sys_clk    ,  //系统时钟
  3. 3       input         sys_rst_n  ,  //系统复位,低电平有效
  4. 4       //摄像头
  5. 5       input         cam_pclk   ,  //cmos 数据像素时钟
  6. 6       input         cam_vsync  ,  //cmos 场同步信号
  7. 7       input         cam_href   ,  //cmos 行同步信号
  8. 8       input  [7:0]  cam_data   ,  //cmos 数据  
  9. 9       output        cam_rst_n  ,  //cmos 复位信号,低电平有效
  10. 10      output        cam_pwdn   ,  //cmos 电源休眠模式选择信号
  11. 11      output        cam_scl    ,  //cmos SCCB_SCL线
  12. 12      inout         cam_sda    ,  //cmos SCCB_SDA线
  13. 13      //SDRAM
  14. 14      output        sdram_clk  ,  //SDRAM 时钟
  15. 15      output        sdram_cke  ,  //SDRAM 时钟有效
  16. 16      output        sdram_cs_n ,  //SDRAM 片选
  17. 17      output        sdram_ras_n,  //SDRAM 行有效
  18. 18      output        sdram_cas_n,  //SDRAM 列有效
  19. 19      output        sdram_we_n ,  //SDRAM 写有效
  20. 20      output [1:0]  sdram_ba   ,  //SDRAM Bank地址
  21. 21      output [1:0]  sdram_dqm  ,  //SDRAM 数据掩码
  22. 22      output [12:0] sdram_addr ,  //SDRAM 地址
  23. 23      inout  [15:0] sdram_data ,  //SDRAM 数据   
  24. 24      //HDMI接口
  25. 25      output       tmds_clk_p,    // TMDS 时钟通道
  26. 26      output       tmds_clk_n,
  27. 27      output [2:0] tmds_data_p,   // TMDS 数据通道
  28. 28      output [2:0] tmds_data_n
  29. 29      );
  30. 30  
  31. 31  //parameter define
  32. 32  parameter SLAVE_ADDR    = 7'h3c          ; //OV5640的器件地址7'h3c
  33. 33  parameter BIT_CTRL      = 1'b1           ; //OV5640的字节地址为16位  0:8位 1:16位
  34. 34  parameter CLK_FREQ      = 27'd50_000_000 ; //i2c_dri模块的驱动时钟频率
  35. 35  parameter I2C_FREQ      = 18'd250_000    ; //I2C的SCL时钟频率,不超过400KHz
  36. 36  parameter V_CMOS_DISP   = 11'd800        ; //CMOS分辨率--行
  37. 37  parameter H_CMOS_DISP   = 11'd1280       ; //CMOS分辨率--列
  38. 38  parameter TOTAL_H_PIXEL = 13'd2570       ; //CMOS分辨率--行
  39. 39  parameter TOTAL_V_PIXEL = 13'd980        ;
  40. 40  
  41. 41  //wire define
  42. 42  wire        clk_100m       ;  //100mhz时钟,SDRAM操作时钟
  43. 43  wire        clk_100m_shift ;  //100mhz时钟,SDRAM相位偏移时钟
  44. 44  wire        clk_50m        ;
  45. 45  wire        hdmi_clk       ;  
  46. 46  wire        hdmi_clk_5     ;  
  47. 47  wire        locked         ;
  48. 48  wire        locked_hdmi    ;
  49. 49  wire        rst_n          ;
  50. 50  wire        sys_init_done  ;  //系统初始化完成(sdram初始化+摄像头初始化)
  51. 51  
  52. 52  wire        i2c_exec       ;  //I2C触发执行信号
  53. 53  wire [23:0] i2c_data       ;  //I2C要配置的地址与数据(高8位地址,低8位数据)         
  54. 54  wire        i2c_done       ;  //I2C寄存器配置完成信号
  55. 55  wire        i2c_dri_clk    ;  //I2C操作时钟
  56. 56  wire [ 7:0] i2c_data_r     ;  //I2C读出的数据
  57. 57  wire        i2c_rh_wl      ;  //I2C读写控制信号
  58. 58  wire        cam_init_done  ;  //摄像头初始化完成
  59. 59                          
  60. 60  wire        wr_en          ;  //sdram_ctrl模块写使能
  61. 61  wire [15:0] wr_data        ;  //sdram_ctrl模块写数据
  62. 62  wire        rd_en          ;  //sdram_ctrl模块读使能
  63. 63  wire [15:0] rd_data        ;  //sdram_ctrl模块读数据
  64. 64  wire        sdram_init_done;  //SDRAM初始化完成
  65. 65  
  66. 66  //*****************************************************
  67. 67  //**                    main code
  68. 68  //*****************************************************
  69. 69  
  70. 70  assign  rst_n = sys_rst_n & locked & locked_hdmi;
  71. 71  //系统初始化完成:SDRAM和摄像头都初始化完成
  72. 72  //避免了在SDRAM初始化过程中向里面写入数据
  73. 73  assign  sys_init_done = sdram_init_done & cam_init_done;
  74. 74  //电源休眠模式选择 0:正常模式 1:电源休眠模式
  75. 75  assign  cam_pwdn  = 1'b0;
  76. 76  assign  cam_rst_n = 1'b1;
  77. 77  
  78. 78  //锁相环
  79. 79  pll u_pll(
  80. 80      .areset             (~sys_rst_n),
  81. 81      .inclk0             (sys_clk),            
  82. 82      .c0                 (clk_100m),
  83. 83      .c1                 (clk_100m_shift),
  84. 84      .c2                 (clk_50m),
  85. 85      .locked             (locked)
  86. 86      );
  87. 87  
  88. 88  pll_hdmi    pll_hdmi_inst (
  89. 89      .areset             ( ~sys_rst_n  ),
  90. 90      .inclk0             ( sys_clk     ),
  91. 91      .c0                 ( hdmi_clk    ),//hdmi pixel clock 71Mhz
  92. 92      .c1                 ( hdmi_clk_5  ),//hdmi pixel clock*5 355Mhz
  93. 93      .locked             ( locked_hdmi )
  94. 94      );
  95. 95      
  96. 96  //I2C配置模块
  97. 97  i2c_ov5640_rgb565_cfg u_i2c_cfg(
  98. 98      .clk                (i2c_dri_clk),
  99. 99      .rst_n              (rst_n      ),
  100. 100            
  101. 101     .i2c_exec           (i2c_exec   ),
  102. 102     .i2c_data           (i2c_data   ),
  103. 103     .i2c_rh_wl          (i2c_rh_wl  ),      //I2C读写控制信号
  104. 104     .i2c_done           (i2c_done   ),
  105. 105     .i2c_data_r         (i2c_data_r ),   
  106. 106                 
  107. 107     .cmos_h_pixel       (H_CMOS_DISP  ),    //CMOS水平方向像素个数
  108. 108     .cmos_v_pixel       (V_CMOS_DISP  ),    //CMOS垂直方向像素个数
  109. 109     .total_h_pixel      (TOTAL_H_PIXEL),    //水平总像素大小
  110. 110     .total_v_pixel      (TOTAL_V_PIXEL),    //垂直总像素大小
  111. 111         
  112. 112     .init_done          (cam_init_done)
  113. 113     );   
  114. 114
  115. 115 //I2C驱动模块
  116. 116 i2c_dri #(
  117. 117     .SLAVE_ADDR         (SLAVE_ADDR    ),    //参数传递
  118. 118     .CLK_FREQ           (CLK_FREQ      ),              
  119. 119     .I2C_FREQ           (I2C_FREQ      )
  120. 120     )
  121. 121 u_i2c_dr(
  122. 122     .clk                (clk_50m       ),
  123. 123     .rst_n              (rst_n         ),
  124. 124
  125. 125     .i2c_exec           (i2c_exec      ),   
  126. 126     .bit_ctrl           (BIT_CTRL      ),   
  127. 127     .i2c_rh_wl          (i2c_rh_wl     ),     //固定为0,只用到了IIC驱动的写操作   
  128. 128     .i2c_addr           (i2c_data[23:8]),   
  129. 129     .i2c_data_w         (i2c_data[7:0] ),   
  130. 130     .i2c_data_r         (i2c_data_r    ),   
  131. 131     .i2c_done           (i2c_done      ),   
  132. 132     .scl                (cam_scl       ),   
  133. 133     .sda                (cam_sda       ),
  134. 134     .dri_clk            (i2c_dri_clk   )       //I2C操作时钟
  135. 135     );
  136. 136
  137. 137 //CMOS图像数据采集模块
  138. 138 cmos_capture_data u_cmos_capture_data(         //系统初始化完成之后再开始采集数据
  139. 139     .rst_n              (rst_n & sys_init_done),
  140. 140     
  141. 141     .cam_pclk           (cam_pclk ),
  142. 142     .cam_vsync          (cam_vsync),
  143. 143     .cam_href           (cam_href ),
  144. 144     .cam_data           (cam_data ),         
  145. 145     
  146. 146     .cmos_frame_vsync   (),
  147. 147     .cmos_frame_href    (),
  148. 148     .cmos_frame_valid   (wr_en    ),      //数据有效使能信号
  149. 149     .cmos_frame_data    (wr_data  )       //有效数据
  150. 150     );
  151. 151
  152. 152
  153. 153 //SDRAM 控制器顶层模块,封装成FIFO接口
  154. 154 //SDRAM 控制器地址组成: {bank_addr[1:0],row_addr[12:0],col_addr[8:0]}
  155. 155 sdram_top u_sdram_top(
  156. 156     .ref_clk            (clk_100m),         //sdram 控制器参考时钟
  157. 157     .out_clk            (clk_100m_shift),   //用于输出的相位偏移时钟
  158. 158     .rst_n              (rst_n),            //系统复位
  159. 159                                             
  160. 160     //用户写端口                              
  161. 161     .wr_clk             (cam_pclk),         //写端口FIFO: 写时钟
  162. 162     .wr_en              (wr_en),            //写端口FIFO: 写使能
  163. 163     .wr_data            (wr_data),          //写端口FIFO: 写数据
  164. 164     .wr_min_addr        (24'd0),            //写SDRAM的起始地址
  165. 165     .wr_max_addr        (V_CMOS_DISP*H_CMOS_DISP-1),   //写SDRAM的结束地址
  166. 166     .wr_len             (10'd512),          //写SDRAM时的数据突发长度
  167. 167     .wr_load            (~rst_n),           //写端口复位: 复位写地址,清空写FIFO
  168. 168                                             
  169. 169     //用户读端口                              
  170. 170     .rd_clk             (hdmi_clk),          //读端口FIFO: 读时钟
  171. 171     .rd_en              (rd_en),            //读端口FIFO: 读使能
  172. 172     .rd_data            (rd_data),          //读端口FIFO: 读数据
  173. 173     .rd_min_addr        (24'd0),            //读SDRAM的起始地址
  174. 174     .rd_max_addr        (V_CMOS_DISP*H_CMOS_DISP-1),   //读SDRAM的结束地址
  175. 175     .rd_len             (10'd512),          //从SDRAM中读数据时的突发长度
  176. 176     .rd_load            (~rst_n),           //读端口复位: 复位读地址,清空读FIFO
  177. 177                                                
  178. 178     //用户控制端口                                
  179. 179     .sdram_read_valid   (1'b1),             //SDRAM 读使能
  180. 180     .sdram_pingpang_en  (1'b1),             //SDRAM 乒乓操作使能
  181. 181     .sdram_init_done    (sdram_init_done),  //SDRAM 初始化完成标志
  182. 182                                             
  183. 183     //SDRAM 芯片接口                                
  184. 184     .sdram_clk          (sdram_clk),        //SDRAM 芯片时钟
  185. 185     .sdram_cke          (sdram_cke),        //SDRAM 时钟有效
  186. 186     .sdram_cs_n         (sdram_cs_n),       //SDRAM 片选
  187. 187     .sdram_ras_n        (sdram_ras_n),      //SDRAM 行有效
  188. 188     .sdram_cas_n        (sdram_cas_n),      //SDRAM 列有效
  189. 189     .sdram_we_n         (sdram_we_n),       //SDRAM 写有效
  190. 190     .sdram_ba           (sdram_ba),         //SDRAM Bank地址
  191. 191     .sdram_addr         (sdram_addr),       //SDRAM 行/列地址
  192. 192     .sdram_data         (sdram_data),       //SDRAM 数据
  193. 193     .sdram_dqm          (sdram_dqm)         //SDRAM 数据掩码
  194. 194     );
  195. 195
  196. 196 //例化HDMI顶层模块
  197. 197 hdmi_top u_hdmi_top(
  198. 198     .hdmi_clk       (hdmi_clk   ),
  199. 199     .hdmi_clk_5     (hdmi_clk_5 ),
  200. 200     .rst_n          (rst_n      ),
  201. 201                 
  202. 202     .rd_data        (rd_data    ),
  203. 203     .rd_en          (rd_en      ),
  204. 204     .h_disp         (),  
  205. 205     .v_disp         (),
  206. 206     .pixel_xpos     (),
  207. 207     .pixel_ypos     (),
  208. 208     .video_vs       (),  
  209. 209     .tmds_clk_p     (tmds_clk_p ),
  210. 210     .tmds_clk_n     (tmds_clk_n ),
  211. 211     .tmds_data_p    (tmds_data_p),
  212. 212     .tmds_data_n    (tmds_data_n)
  213. 213     );   
  214. 214
  215. 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实时显示程序下载验证成功。

第四十二章 OV5640摄像头HDMI显示实验11835.png
图 42.5.1 HDMI实时显示图像
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-27 11:26

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表