|
本帖最后由 正点原子 于 2023-2-27 15:26 编辑
1)实验平台:正点原子紫光PGL22G开发板
2)购买链接:https://item.taobao.com/item.htm?&id=692368045899
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-340253-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子FPGA交流群:435699340
第四十二章 OV5640摄像头HDMI显示实验
在OV5640摄像头RGB-LCD显示实验中,成功的在LCD屏上实时显示出了摄像头采集的图像。本章将使用FPGA开发板实现对OV5640的数字图像采集并在HDMI显示器上实时显示。
本章包括以下几个部分:
42.1简介
42.2实验任务
42.3硬件设计
42.4程序设计
42.5下载验证
42.1简介
在“OV5640摄像头RGB-LCD显示实验”中对OV5640的视频传输时序、SCCB协议以及寄存器的配置信息等内容作了详细的介绍,如果大家对这部分内容不是很熟悉的话,请参考“OV5640摄像头RGB-LCD显示实验”中的简介部分。
42.2实验任务
本节实验任务是使用ATK-DFPGL22G开发板及OV5640摄像头实现图像采集,并通过HDMI接口驱动HDMI显示器,并实时显示出图像。
42.3硬件设计
摄像头扩展接口原理图及OV5640模块说明与“OV5640摄像头RGB-LCD显示实验”完全相同,请参考“OV5640摄像头RGB-LCD显示实验”硬件设计部分。HDMI接口部分的硬件设计请参考“HDMI彩条显示实验”中的硬件设计部分。
由于OV5640、HDMI接口和DDR3引脚数目较多且在前面相应的章节中已经给出它们的管脚列表,这里不再列出管脚分配。
42.4程序设计
根据实验任务,首先我们设计如图 42.4.1所示的系统框图,本章实验的系统框架延续了“OV5640摄像头RGB-LCD显示实验”的整体架构。本次实验包括以下模块:时钟模块、IIC配置模块、IIC驱动模块、DDR3控制器模块、摄像头图像采集模块和HDMI顶层模块。其中IIC配置模块、IIC驱动模块、摄像头图像采集模块和DDR3控制器模块我们没有做任何修改,这些模块在“OV5640摄像头RGB-LCD显示实验”中已经说明过,这里不再详述,本次实验只是将LCD顶层模块替换成了HDMI顶层模块。本次实验也不需要图像尺寸配置模块,因为本次实验摄像头的分辨率是固定的,其分辨率为1280x720。
OV5640摄像头HDMI显示系统框图如下图所示:
图 42.4.1 顶层系统框图
由上图可知,时钟模块为HDMI顶层模块、DDR3控制模块以及I2C驱动模块提供驱动时钟。摄像头驱动模块控制着传感器初始化的开始与结束。传感器初始化完成后图像采集模块将采集到的数据写入DDR3控制模块,HDMI顶层模块从DDR3控制模块中读出数据并驱动显示器显示,这时整个系统才完成了数据的采集、缓存与显示。需要注意的是图像数据采集模块是在DDR3和传感器都初始化完成之后才开始输出数据的,避免了在DDR3初始化过程中向里面写入数据。
顶层模块的代码如下:
1 module ov5640_hdmi(
2 input sys_clk ,
3 input sys_rst_n ,
4
5 output tmds_clk_p , // TMDS 时钟通道
6 output tmds_clk_n ,
7 output [2:0] tmds_data_p , // TMDS 数据通道
8 output [2:0] tmds_data_n ,
9 //摄像头接口
10 input cam_pclk , //cmos 数据像素时钟
11 input cam_vsync , //cmos 场同步信号
12 input cam_href , //cmos 行同步信号
13 input [7:0] cam_data , //cmos 数据
14 output cam_rst_n , //cmos 复位信号,低电平有效
15 output cam_pwdn , //电源休眠模式选择 0:正常模式 1:电源休眠模式
16 output cam_scl , //cmos SCCB_SCL线
17 inout cam_sda , //cmos SCCB_SDA线
18 //DDR3接口
19 input pad_loop_in , //低位温度补偿输入
20 input pad_loop_in_h , //高位温度补偿输入
21 output pad_rstn_ch0 , //Memory复位
22 output pad_ddr_clk_w , //Memory差分时钟正
23 output pad_ddr_clkn_w , //Memory差分时钟负
24 output pad_csn_ch0 , //Memory片选
25 output [15:0] pad_addr_ch0 , //Memory地址总线
26 inout [16-1:0] pad_dq_ch0 , //数据总线
27 inout [16/8-1:0] pad_dqs_ch0 , //数据时钟正端
28 inout [16/8-1:0] pad_dqsn_ch0 , //数据时钟负端
29 output [16/8-1:0] pad_dm_rdqs_ch0 , //数据Mask
30 output pad_cke_ch0 , //Memory差分时钟使
31 output pad_odt_ch0 , //On Die Terminati
32 output pad_rasn_ch0 , //行地址strobe
33 output pad_casn_ch0 , //列地址strobe
34 output pad_wen_ch0 , //写使能
35 output [2:0] pad_ba_ch0 , //Bank地址总线
36 output pad_loop_out , //低位温度补偿输出
37 output pad_loop_out_h //高位温度补偿输出
38 );
39
40 //parameter define
41 parameter V_CMOS_DISP = 11'd720 ; //CMOS分辨率--行
42 parameter H_CMOS_DISP = 11'd1280 ; //CMOS分辨率--列
43 parameter TOTAL_H_PIXEL = 12'd2570 ;
44 parameter TOTAL_V_PIXEL = 12'd980 ;
45 parameter APP_ADDR_MIN = 28'd0 ; //ddr3读写起始地址,以一个16bit的数据为一个单位
46 parameter APP_ADDR_MAX = 28'd921600 ; //ddr3读写结束地址,以一个16bit的数据为一个单位
47 parameter BURST_LENGTH = 8'd160 ; //ddr3读写突发长度,80个128bit的数据
48
49 //wire define
50 //PLL
51 wire pixel_clk ; //像素时钟75M
52 wire pixel_clk_5x ; //5倍像素时钟375M
53 wire clk_50m ; //output 50M
54 wire clk_locked ;
55 //OV5640
56 wire cmos_frame_vsync; //帧有效信号
57 wire cmos_frame_valid; //数据有效使能信号
58 wire [15:0] wr_data ; //OV7725写入DDR3控制器模块的数据
59 //HDMI
60 wire video_vs ; //场同步信号
61 wire [15:0] rd_data ; //DDR3控制器模块读数据给HDMI
62 wire rdata_req ; //DDR3控制器模块读使能
63 //DDR3
64 wire fram_done ; //DDR中已经存入一帧画面标志
65 wire ddr_init_done ; //ddr3初始化完成
66
67 //*****************************************************
68 //** main code
69 //*****************************************************
70
71 //例化PLL IP核
72 pll_clk u_pll_clk(
73 .pll_rst (~sys_rst_n ),
74 .clkin1 (sys_clk ),
75 .clkout0 (pixel_clk ), //像素时钟75M
76 .clkout1 (pixel_clk_5x), //5倍像素时钟375M
77 .clkout2 (clk_50m ), //output 50M
78 .pll_lock (clk_locked )
79 );
80
81 //ov5640 驱动
82 ov5640_dri u_ov5640_dri(
83 .clk (clk_50m ),
84 .rst_n (sys_rst_n ),
85
86 .cam_pclk (cam_pclk ),
87 .cam_vsync (cam_vsync ),
88 .cam_href (cam_href ),
89 .cam_data (cam_data ),
90 .cam_rst_n (cam_rst_n ),
91 .cam_pwdn (cam_pwdn ),
92 .cam_scl (cam_scl ),
93 .cam_sda (cam_sda ),
94
95 .capture_start (ddr_init_done ),
96 .cmos_h_pixel (H_CMOS_DISP ),
97 .cmos_v_pixel (V_CMOS_DISP ),
98 .total_h_pixel (TOTAL_H_PIXEL ),
99 .total_v_pixel (TOTAL_V_PIXEL ),
100 .cmos_frame_vsync (cmos_frame_vsync),
101 .cmos_frame_href ( ),
102 .cmos_frame_valid (cmos_frame_valid),
103 .cmos_frame_data (wr_data )
104 );
105
106 //ddr3
107 ddr3_top u_ddr3_top(
108 .refclk_in (clk_50m ),
109 .rst_n (sys_rst_n ),
110 .app_addr_rd_min (APP_ADDR_MIN ),
111 .app_addr_rd_max (APP_ADDR_MAX ),
112 .rd_bust_len (BURST_LENGTH ),
113 .app_addr_wr_min (APP_ADDR_MIN ),
114 .app_addr_wr_max (APP_ADDR_MAX ),
115 .wr_bust_len (BURST_LENGTH ),
116 .ddr3_read_valid (1'b1 ),
117 .ddr3_pingpang_en (1'b1 ),
118 .wr_clk (cam_pclk ),
119 .rd_clk (pixel_clk ),
120 .datain_valid (cmos_frame_valid),
121 .datain (wr_data ),
122 .rdata_req (rdata_req ),
123 .rd_load (video_vs ),
124 .wr_load (cmos_frame_vsync),
125 .fram_done (fram_done ),
126 .dataout (rd_data ),
127 .pll_lock (pll_lock ),
128 .ddr_init_done (ddr_init_done ),
129 .ddrphy_rst_done ( ),
130 .pad_loop_in (pad_loop_in ),
131 .pad_loop_in_h (pad_loop_in_h ),
132 .pad_rstn_ch0 (pad_rstn_ch0 ),
133 .pad_ddr_clk_w (pad_ddr_clk_w ),
134 .pad_ddr_clkn_w (pad_ddr_clkn_w ),
135 .pad_csn_ch0 (pad_csn_ch0 ),
136 .pad_addr_ch0 (pad_addr_ch0 ),
137 .pad_dq_ch0 (pad_dq_ch0 ),
138 .pad_dqs_ch0 (pad_dqs_ch0 ),
139 .pad_dqsn_ch0 (pad_dqsn_ch0 ),
140 .pad_dm_rdqs_ch0 (pad_dm_rdqs_ch0 ),
141 .pad_cke_ch0 (pad_cke_ch0 ),
142 .pad_odt_ch0 (pad_odt_ch0 ),
143 .pad_rasn_ch0 (pad_rasn_ch0 ),
144 .pad_casn_ch0 (pad_casn_ch0 ),
145 .pad_wen_ch0 (pad_wen_ch0 ),
146 .pad_ba_ch0 (pad_ba_ch0 ),
147 .pad_loop_out (pad_loop_out ),
148 .pad_loop_out_h (pad_loop_out_h )
149
150 );
151
152 //HDMI顶层模块
153 hdmi_top u_hdmi_top(
154 .hdmi_clk (pixel_clk ),
155 .hdmi_clk_5 (pixel_clk_5x ),
156 .sys_rst_n (sys_rst_n ),
157 .fram_done (fram_done ),
158 .clk_locked (clk_locked ),
159 .rd_data (rd_data ),
160 .rd_en (rdata_req ),
161 .video_vs (video_vs ),
162 .h_disp ( ),
163 .v_disp ( ),
164 .pixel_xpos ( ),
165 .pixel_ypos ( ),
166 .tmds_clk_p (tmds_clk_p ),
167 .tmds_clk_n (tmds_clk_n ),
168 .tmds_data_p (tmds_data_p ),
169 .tmds_data_n (tmds_data_n )
170 );
171
172 endmodule
FPGA顶层模块(ov5640_hdmi)例化了以下四个模块:时钟模块(pll_clk)、OV5640驱动模块(ov5640_dri)、DDR3控制顶层模块(ddr3_top)和HDMI顶层模块(hdmi_top)。
时钟模块(pll_clk):时钟模块通过调用PLL IP核实现,为DDR3控制模块以及OV5640驱动模块中的I2C驱动模块提供驱动时钟,为HDMI模块提供像素时钟和5倍像素时钟(频率分别是75Mhz和375Mhz)。
OV5640驱动模块(ov5640_dri):OV5640驱动模块负责驱动OV5640 SCCB接口总线,将像素时钟驱动下的传感器输出的场同步信号、行同步信号以及8位数据转换成DDR3读写控制模块的写使能信号和16位写数据信号,完成对OV5640传感器图像的采集。
DDR3控制模块(ddr3_top):DDR3读写控制器模块负责驱动DDR3片外存储器,缓存图像传感器输出的图像数据。该模块将DDR3复杂的读写操作封装成类似FIFO的用户接口,非常方便用户的使用。有关DDR3控制模块的详细介绍请大家参考“DDR3读写测试实验”章节。
HDMI顶层模块(hdmi_top):HDMI顶层模块负责驱动HDMI显示器的驱动信号的输出,同时为其他模块提供场同步信号和数据请求信号。HDMI顶层模块例化了HDMI视频显示驱动模块(video_driver)和HDMI驱动模块(dvi_transmitter_top)。
HDMI视频显示驱动模块负责产生行场信号和数据有效使能信号和像素点的横纵坐标,并将内部信号data_req(数据请求信号)输出至端口,方便从DD3控制器中读取数据。HDMI驱动模块负责将RGB565格式的视频图像转换成TMDS数据输出。有关HDMI视频显示驱动模块、HDMI驱动模块的详细介绍请大家参考“HDMI彩条显示实验”章节。
42.5下载验证
编译完工程之后我们就可以开始下载程序。将OV5640摄像头模块插在ATK-DFPGL22G开发板的“OLED/CAMERA”插座上,并将HDMI电缆一端连接到开发板上的HDMI插座、另一端连接到显示器。将下载器一端连电脑,另一端与开发板上的JTAG端口连接,连接电源线并打开电源开关。接下来我们下载程序,验证OV5640 HDMI实时显示功能。下载完成后观察HDMI显示器显示的图案如下图所示,说明OV5640 HDMI实时显示程序下载验证成功。
图 42.5.1 HDMI实时显示图像 |
|