12. ov5640摄像头hdmi图像显示

在上一章节,我们实现了OV5640摄像头VGA显示,在本章节我们与OV7725一样,实现OV5640摄像头HDMI显示。

12.1. 理论学习

参照“OV5640摄像头VGA显示”的“理论学习”小节。

12.2. 实战演练

12.2.1. 实验目标

使用SDRAM做图像数据缓存,将OV5640摄像头采集到的图像数据在HDMI显示屏上实时显示。分辨率1280*720。

12.2.2. 硬件资源

参见“OV7725摄像头VGA图像显示”的“硬件资源”小节。

12.3. 程序设计

12.3.1. 整体说明

在本小节我们分两部分讲解一下实验工程的整体框架,第一部分是OV5640的相关模块,OV5640部分的整体框图和介绍,具体见图 62‑1、表格 62‑1 OV5640各模块功能介绍。

OV5640002

图 62‑1 ov5640整体框图

表格 62‑1 OV5640各模块功能介绍

模块名称

功能描述

ov5640_top

OV5640顶层模块

i2c_ctrl

i2c驱动模块

ov5640_cfg

OV5640寄存器配置模块

ov5640_data

OV5640图像采集模块

由上述图表可知,第一部分的OV5640相关模块包含4个子模块,首先是ov5640_top模块,这一模块作为ov5640部分的顶层模块,内部实例化3个子功能模块,连接各子模块对应信号,外部对摄像头进行相关配置并接收摄像头采集的数据信息;ov5640_cfg模块,是寄存器配置模块,内部包含对ov5640 摄像头的配置信息;i2c_ctrl模块,i2c协议与SCCB协议几乎无差别,使用i2c协议代替SCCB接口协议向ov5640摄像头写入ov5640_cfg模块内部包含的寄存器配置信息;ov5640_data模块,是ov5640摄像头的图像采集模块,将摄像头传入的图像数据处理后写入SDRAM。

第一部分介绍完毕后,我们来说一下实验工程的第二部分。在第二部分中将第一部分的ov5640摄像头部分视为一个子模块,与其他子功能模块构成整个实验工程。整体框图和子功能模块介绍,具体见图 62‑2、表格 62‑2。

OV5640003

图 62‑2 OV5640-HDMI图像显示整体框图

表格 62‑2 OV5640-HDMI图像显示各子模块功能描述

模块名称

功能描述

ov5640_hdmi_1280x720

实验工程顶层模块

clk_gen

时钟生成模块

clk_hdmi

时钟生成模块

ov5640_top

OV5640相关部分

sdram_top

SDRAM读写控制器

vga_ctrl

VGA驱动模块

hdmi_ctrl

HDMI驱动模块

由图表可知,OV5640-HDMI图像显示工程包含表格模块,ov5640_hdmi_1280x720作为实验工程的顶层模块,内部实例化各子功能模块,连接对应信号,对外接收摄像头采集的图像数据,将处理后的数据存入SDRAM,在TFT显示屏上显示出来;clk_gen模块,调用IP核生成,产生实验工程的工 作时钟;clk_hdmi模块,调用IP核生成,产生HDMI控制控制所需时钟;ov5640_top模块,是ov5640部分各子功能模块的集合,实现ov5640摄像头的配置、图像采集与处理;sdram_top模块为SDRAM读写控制器,存储处理后的图像数据;vga_ctrl模块将读出SDRAM的图像数据 按照VGA时序进行处理;hdmi_ctrl模块将VGA传入的图像数据进行HDMI时序处理,并显示再HDMI显示屏上。

到了这里,实验工程的整体框架我们介绍完毕,整体框架与“OV5640摄像头VGA显示”章节的实验工程框架类似,只是寄存器配置参数需要更改,以及添加了HDMI驱动模块。在此我们只简要说明一下改动较大的寄存器配置模块ov5640_cfg其他改动较小或未改动模块不再说明,读者可自行回顾前面相关章节。

12.3.1.1. 寄存器配置模块

模块框图

寄存器配置模块框图,具体见图 62‑3;模块输入输出信号简介,具体见表格 62‑3。

OV5640004

图 62‑3 寄存器配置模块框图

表格 62‑3 寄存器配置模块输入输出信号简介

信号

位宽

类型

功能描述

sys_rst_n

1bit

input

复位信号,低有效

cfg_end

1bit

input

一个寄存器配置完成

sys_clk

1bit

input

模块工作时钟

cfg_start

1bit

output

单个寄存器配置触发信号

cfg_data

23bit

output

寄存器地址+数据

cfg_done

1bit

output

寄存器配置完成信号

代码编写

要想OV5640摄像头正常工作,需要先对摄像头进行寄存器配置,即向摄像头寄存器写入对应指令。由于寄存器数量较多,在此我们只列出参考代码,各寄存器的相关内容,读者可翻阅数据手册进行学习。模块参考代码,具体见代码清单 62‑1。

代码清单 62‑1 寄存器配置模块参考代码(ov5640_cfg.v)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
module ov5640_cfg
(
input wire sys_clk , //系统时钟,由iic模块传入
input wire sys_rst_n , //系统复位,低有效
input wire cfg_end , //单个寄存器配置完成

output reg cfg_start , //单个寄存器配置触发信号
output wire [23:0] cfg_data , //ID,REG_ADDR,REG_VAL
output reg cfg_done //寄存器配置完成
);

////
//\* Parameter and Internal Signal \//
////

//parameter define
parameter REG_NUM = 8'd251 ; //总共需要配置的寄存器个数
parameter CNT_WAIT_MAX = 10'd1023 ; //寄存器配置等待计数最大值

//wire define
wire [23:0] cfg_data_reg[REG_NUM-1:0] ; //寄存器配置数据暂存

//reg define
reg [9:0] cnt_wait ; //寄存器配置等待计数器
reg [7:0] reg_num ; //配置寄存器个数


////
//\* Main Code \//
////

//cnt_wait:寄存器配置等待计数器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_wait <= 15'd0;
else if(cnt_wait < CNT_WAIT_MAX)
cnt_wait <= cnt_wait + 1'b1;

//reg_num:配置寄存器个数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
reg_num <= 8'd0;
else if(cfg_end == 1'b1)
reg_num <= reg_num + 1'b1;

//cfg_start:单个寄存器配置触发信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cfg_start <= 1'b0;
else if(cnt_wait == (CNT_WAIT_MAX - 1'b1))
cfg_start <= 1'b1;
else if((cfg_end == 1'b1) && (reg_num < REG_NUM))
cfg_start <= 1'b1;
else
cfg_start <= 1'b0;

//cfg_done:寄存器配置完成
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cfg_done <= 1'b0;
else if((reg_num == REG_NUM) && (cfg_end == 1'b1))
cfg_done <= 1'b1;

//cfg_data:ID,REG_ADDR,REG_VAL
assign cfg_data = (cfg_done == 1'b1) ? 24'b0 : cfg_data_reg[reg_num];

//----------------------------------------------------
//cfg_data_reg:寄存器配置数据暂存 ID REG_ADDR REG_VAL
assign cfg_data_reg[000] = {16'h3103, 8'h11};
assign cfg_data_reg[001] = {16'h3008, 8'h82};
assign cfg_data_reg[002] = {16'h3008, 8'h42};
assign cfg_data_reg[003] = {16'h3103, 8'h03};
assign cfg_data_reg[004] = {16'h3017, 8'hff};
assign cfg_data_reg[005] = {16'h3018, 8'hff};
assign cfg_data_reg[006] = {16'h3034, 8'h1A};
assign cfg_data_reg[007] = {16'h3037, 8'h13};
assign cfg_data_reg[008] = {16'h3108, 8'h01};
assign cfg_data_reg[009] = {16'h3630, 8'h36};
assign cfg_data_reg[010] = {16'h3631, 8'h0e};
assign cfg_data_reg[011] = {16'h3632, 8'he2};
assign cfg_data_reg[012] = {16'h3633, 8'h12};
assign cfg_data_reg[013] = {16'h3621, 8'he0};
assign cfg_data_reg[014] = {16'h3704, 8'ha0};
assign cfg_data_reg[015] = {16'h3703, 8'h5a};
assign cfg_data_reg[016] = {16'h3715, 8'h78};
assign cfg_data_reg[017] = {16'h3717, 8'h01};
assign cfg_data_reg[018] = {16'h370b, 8'h60};
assign cfg_data_reg[019] = {16'h3705, 8'h1a};
assign cfg_data_reg[020] = {16'h3905, 8'h02};
assign cfg_data_reg[021] = {16'h3906, 8'h10};
assign cfg_data_reg[022] = {16'h3901, 8'h0a};
assign cfg_data_reg[023] = {16'h3731, 8'h12};
assign cfg_data_reg[024] = {16'h3600, 8'h08};
assign cfg_data_reg[025] = {16'h3601, 8'h33};
assign cfg_data_reg[026] = {16'h302d, 8'h60};
assign cfg_data_reg[027] = {16'h3620, 8'h52};
assign cfg_data_reg[028] = {16'h371b, 8'h20};
assign cfg_data_reg[029] = {16'h471c, 8'h50};
assign cfg_data_reg[030] = {16'h3a13, 8'h43};
assign cfg_data_reg[031] = {16'h3a18, 8'h00};
assign cfg_data_reg[032] = {16'h3a19, 8'hf8};
assign cfg_data_reg[033] = {16'h3635, 8'h13};
assign cfg_data_reg[034] = {16'h3636, 8'h03};
assign cfg_data_reg[035] = {16'h3634, 8'h40};
assign cfg_data_reg[036] = {16'h3622, 8'h01};
assign cfg_data_reg[037] = {16'h3c01, 8'h34};
assign cfg_data_reg[038] = {16'h3c04, 8'h28};
assign cfg_data_reg[039] = {16'h3c05, 8'h98};
assign cfg_data_reg[040] = {16'h3c06, 8'h00};
assign cfg_data_reg[041] = {16'h3c07, 8'h08};
assign cfg_data_reg[042] = {16'h3c08, 8'h00};
assign cfg_data_reg[043] = {16'h3c09, 8'h1c};
assign cfg_data_reg[044] = {16'h3c0a, 8'h9c};
assign cfg_data_reg[045] = {16'h3c0b, 8'h40};
assign cfg_data_reg[046] = {16'h3810, 8'h00};
assign cfg_data_reg[047] = {16'h3811, 8'h10};
assign cfg_data_reg[048] = {16'h3812, 8'h00};
assign cfg_data_reg[049] = {16'h3708, 8'h64};
assign cfg_data_reg[050] = {16'h4001, 8'h02};
assign cfg_data_reg[051] = {16'h4005, 8'h1a};
assign cfg_data_reg[052] = {16'h3000, 8'h00};
assign cfg_data_reg[053] = {16'h3004, 8'hff};
assign cfg_data_reg[054] = {16'h300e, 8'h58};
assign cfg_data_reg[055] = {16'h302e, 8'h00};
assign cfg_data_reg[056] = {16'h4300, 8'h61};
assign cfg_data_reg[057] = {16'h501f, 8'h01};
assign cfg_data_reg[058] = {16'h440e, 8'h00};
assign cfg_data_reg[059] = {16'h5000, 8'ha7};
assign cfg_data_reg[060] = {16'h3a0f, 8'h30};
assign cfg_data_reg[061] = {16'h3a10, 8'h28};
assign cfg_data_reg[062] = {16'h3a1b, 8'h30};
assign cfg_data_reg[063] = {16'h3a1e, 8'h26};
assign cfg_data_reg[064] = {16'h3a11, 8'h60};
assign cfg_data_reg[065] = {16'h3a1f, 8'h14};
assign cfg_data_reg[066] = {16'h5800, 8'h23};
assign cfg_data_reg[067] = {16'h5801, 8'h14};
assign cfg_data_reg[068] = {16'h5802, 8'h0f};
assign cfg_data_reg[069] = {16'h5803, 8'h0f};
assign cfg_data_reg[070] = {16'h5804, 8'h12};
assign cfg_data_reg[071] = {16'h5805, 8'h26};
assign cfg_data_reg[072] = {16'h5806, 8'h0c};
assign cfg_data_reg[073] = {16'h5807, 8'h08};
assign cfg_data_reg[074] = {16'h5808, 8'h05};
assign cfg_data_reg[075] = {16'h5809, 8'h05};
assign cfg_data_reg[076] = {16'h580a, 8'h08};
assign cfg_data_reg[077] = {16'h580b, 8'h0d};
assign cfg_data_reg[078] = {16'h580c, 8'h08};
assign cfg_data_reg[079] = {16'h580d, 8'h03};
assign cfg_data_reg[080] = {16'h580e, 8'h00};
assign cfg_data_reg[081] = {16'h580f, 8'h00};
assign cfg_data_reg[082] = {16'h5810, 8'h03};
assign cfg_data_reg[083] = {16'h5811, 8'h09};
assign cfg_data_reg[084] = {16'h5812, 8'h07};
assign cfg_data_reg[085] = {16'h5813, 8'h03};
assign cfg_data_reg[086] = {16'h5814, 8'h00};
assign cfg_data_reg[087] = {16'h5815, 8'h01};
assign cfg_data_reg[088] = {16'h5816, 8'h03};
assign cfg_data_reg[089] = {16'h5817, 8'h08};
assign cfg_data_reg[090] = {16'h5818, 8'h0d};
assign cfg_data_reg[091] = {16'h5819, 8'h08};
assign cfg_data_reg[092] = {16'h581a, 8'h05};
assign cfg_data_reg[093] = {16'h581b, 8'h06};
assign cfg_data_reg[094] = {16'h581c, 8'h08};
assign cfg_data_reg[095] = {16'h581d, 8'h0e};
assign cfg_data_reg[096] = {16'h581e, 8'h29};
assign cfg_data_reg[097] = {16'h581f, 8'h17};
assign cfg_data_reg[098] = {16'h5820, 8'h11};
assign cfg_data_reg[099] = {16'h5821, 8'h11};
assign cfg_data_reg[100] = {16'h5822, 8'h15};
assign cfg_data_reg[101] = {16'h5823, 8'h28};
assign cfg_data_reg[102] = {16'h5824, 8'h46};
assign cfg_data_reg[103] = {16'h5825, 8'h26};
assign cfg_data_reg[104] = {16'h5826, 8'h08};
assign cfg_data_reg[105] = {16'h5827, 8'h26};
assign cfg_data_reg[106] = {16'h5828, 8'h64};
assign cfg_data_reg[107] = {16'h5829, 8'h26};
assign cfg_data_reg[108] = {16'h582a, 8'h24};
assign cfg_data_reg[109] = {16'h582b, 8'h22};
assign cfg_data_reg[110] = {16'h582c, 8'h24};
assign cfg_data_reg[111] = {16'h582d, 8'h24};
assign cfg_data_reg[112] = {16'h582e, 8'h06};
assign cfg_data_reg[113] = {16'h582f, 8'h22};
assign cfg_data_reg[114] = {16'h5830, 8'h40};
assign cfg_data_reg[115] = {16'h5831, 8'h42};
assign cfg_data_reg[116] = {16'h5832, 8'h24};
assign cfg_data_reg[117] = {16'h5833, 8'h26};
assign cfg_data_reg[118] = {16'h5834, 8'h24};
assign cfg_data_reg[119] = {16'h5835, 8'h22};
assign cfg_data_reg[120] = {16'h5836, 8'h22};
assign cfg_data_reg[121] = {16'h5837, 8'h26};
assign cfg_data_reg[122] = {16'h5838, 8'h44};
assign cfg_data_reg[123] = {16'h5839, 8'h24};
assign cfg_data_reg[124] = {16'h583a, 8'h26};
assign cfg_data_reg[125] = {16'h583b, 8'h28};
assign cfg_data_reg[126] = {16'h583c, 8'h42};
assign cfg_data_reg[127] = {16'h583d, 8'hce};
assign cfg_data_reg[128] = {16'h5180, 8'hff};
assign cfg_data_reg[129] = {16'h5181, 8'hf2};
assign cfg_data_reg[130] = {16'h5182, 8'h00};
assign cfg_data_reg[131] = {16'h5183, 8'h14};
assign cfg_data_reg[132] = {16'h5184, 8'h25};
assign cfg_data_reg[133] = {16'h5185, 8'h24};
assign cfg_data_reg[134] = {16'h5186, 8'h09};
assign cfg_data_reg[135] = {16'h5187, 8'h09};
assign cfg_data_reg[136] = {16'h5188, 8'h09};
assign cfg_data_reg[137] = {16'h5189, 8'h75};
assign cfg_data_reg[138] = {16'h518a, 8'h54};
assign cfg_data_reg[139] = {16'h518b, 8'he0};
assign cfg_data_reg[140] = {16'h518c, 8'hb2};
assign cfg_data_reg[141] = {16'h518d, 8'h42};
assign cfg_data_reg[142] = {16'h518e, 8'h3d};
assign cfg_data_reg[143] = {16'h518f, 8'h56};
assign cfg_data_reg[144] = {16'h5190, 8'h46};
assign cfg_data_reg[145] = {16'h5191, 8'hf8};
assign cfg_data_reg[146] = {16'h5192, 8'h04};
assign cfg_data_reg[147] = {16'h5193, 8'h70};
assign cfg_data_reg[148] = {16'h5194, 8'hf0};
assign cfg_data_reg[149] = {16'h5195, 8'hf0};
assign cfg_data_reg[150] = {16'h5196, 8'h03};
assign cfg_data_reg[151] = {16'h5197, 8'h01};
assign cfg_data_reg[152] = {16'h5198, 8'h04};
assign cfg_data_reg[153] = {16'h5199, 8'h12};
assign cfg_data_reg[154] = {16'h519a, 8'h04};
assign cfg_data_reg[155] = {16'h519b, 8'h00};
assign cfg_data_reg[156] = {16'h519c, 8'h06};
assign cfg_data_reg[157] = {16'h519d, 8'h82};
assign cfg_data_reg[158] = {16'h519e, 8'h38};
assign cfg_data_reg[159] = {16'h5480, 8'h01};
assign cfg_data_reg[160] = {16'h5481, 8'h08};
assign cfg_data_reg[161] = {16'h5482, 8'h14};
assign cfg_data_reg[162] = {16'h5483, 8'h28};
assign cfg_data_reg[163] = {16'h5484, 8'h51};
assign cfg_data_reg[164] = {16'h5485, 8'h65};
assign cfg_data_reg[165] = {16'h5486, 8'h71};
assign cfg_data_reg[166] = {16'h5487, 8'h7d};
assign cfg_data_reg[167] = {16'h5488, 8'h87};
assign cfg_data_reg[168] = {16'h5489, 8'h91};
assign cfg_data_reg[169] = {16'h548a, 8'h9a};
assign cfg_data_reg[170] = {16'h548b, 8'haa};
assign cfg_data_reg[171] = {16'h548c, 8'hb8};
assign cfg_data_reg[172] = {16'h548d, 8'hcd};
assign cfg_data_reg[173] = {16'h548e, 8'hdd};
assign cfg_data_reg[174] = {16'h548f, 8'hea};
assign cfg_data_reg[175] = {16'h5490, 8'h1d};
assign cfg_data_reg[176] = {16'h5381, 8'h1e};
assign cfg_data_reg[177] = {16'h5382, 8'h5b};
assign cfg_data_reg[178] = {16'h5383, 8'h08};
assign cfg_data_reg[179] = {16'h5384, 8'h0a};
assign cfg_data_reg[180] = {16'h5385, 8'h7e};
assign cfg_data_reg[181] = {16'h5386, 8'h88};
assign cfg_data_reg[182] = {16'h5387, 8'h7c};
assign cfg_data_reg[183] = {16'h5388, 8'h6c};
assign cfg_data_reg[184] = {16'h5389, 8'h10};
assign cfg_data_reg[185] = {16'h538a, 8'h01};
assign cfg_data_reg[186] = {16'h538b, 8'h98};
assign cfg_data_reg[187] = {16'h5580, 8'h06};
assign cfg_data_reg[188] = {16'h5583, 8'h40};
assign cfg_data_reg[189] = {16'h5584, 8'h10};
assign cfg_data_reg[190] = {16'h5589, 8'h10};
assign cfg_data_reg[191] = {16'h558a, 8'h00};
assign cfg_data_reg[192] = {16'h558b, 8'hf8};
assign cfg_data_reg[193] = {16'h501d, 8'h40};
assign cfg_data_reg[194] = {16'h5300, 8'h08};
assign cfg_data_reg[195] = {16'h5301, 8'h30};
assign cfg_data_reg[196] = {16'h5302, 8'h10};
assign cfg_data_reg[197] = {16'h5303, 8'h00};
assign cfg_data_reg[198] = {16'h5304, 8'h08};
assign cfg_data_reg[199] = {16'h5305, 8'h30};
assign cfg_data_reg[200] = {16'h5306, 8'h08};
assign cfg_data_reg[201] = {16'h5307, 8'h16};
assign cfg_data_reg[202] = {16'h5309, 8'h08};
assign cfg_data_reg[203] = {16'h530a, 8'h30};
assign cfg_data_reg[204] = {16'h530b, 8'h04};
assign cfg_data_reg[205] = {16'h530c, 8'h06};
assign cfg_data_reg[206] = {16'h5025, 8'h00};
assign cfg_data_reg[207] = {16'h3008, 8'h02};

assign cfg_data_reg[208] = {16'h3035, 8'h21};
assign cfg_data_reg[209] = {16'h3036, 8'h69};
assign cfg_data_reg[210] = {16'h3c07, 8'h07};
assign cfg_data_reg[211] = {16'h3820, 8'h47};//图像翻转
assign cfg_data_reg[212] = {16'h3821, 8'h00};//镜像
assign cfg_data_reg[213] = {16'h3814, 8'h31};
assign cfg_data_reg[214] = {16'h3815, 8'h31};
assign cfg_data_reg[215] = {16'h3800, 8'h00};
assign cfg_data_reg[216] = {16'h3801, 8'h00};
assign cfg_data_reg[217] = {16'h3802, 8'h00};
assign cfg_data_reg[218] = {16'h3803, 8'hfa};
assign cfg_data_reg[219] = {16'h3804, 8'h0a};
assign cfg_data_reg[220] = {16'h3805, 8'h3f};
assign cfg_data_reg[221] = {16'h3806, 8'h06};
assign cfg_data_reg[222] = {16'h3807, 8'ha9};
assign cfg_data_reg[223] = {16'h3808, 8'h05};
assign cfg_data_reg[224] = {16'h3809, 8'h00};
assign cfg_data_reg[225] = {16'h380a, 8'h02};
assign cfg_data_reg[226] = {16'h380b, 8'hd0};
assign cfg_data_reg[227] = {16'h380c, 8'h07};
assign cfg_data_reg[228] = {16'h380d, 8'h64};
assign cfg_data_reg[229] = {16'h380e, 8'h02};
assign cfg_data_reg[230] = {16'h380f, 8'he4};
assign cfg_data_reg[231] = {16'h3813, 8'h04};
assign cfg_data_reg[232] = {16'h3618, 8'h00};
assign cfg_data_reg[233] = {16'h3612, 8'h29};
assign cfg_data_reg[234] = {16'h3709, 8'h52};
assign cfg_data_reg[235] = {16'h370c, 8'h03};
assign cfg_data_reg[236] = {16'h3a02, 8'h02};
assign cfg_data_reg[237] = {16'h3a03, 8'he0};
assign cfg_data_reg[238] = {16'h3a14, 8'h02};
assign cfg_data_reg[239] = {16'h3a15, 8'he0};
assign cfg_data_reg[240] = {16'h4004, 8'h02};
assign cfg_data_reg[241] = {16'h3002, 8'h1c};
assign cfg_data_reg[242] = {16'h3006, 8'hc3};
assign cfg_data_reg[243] = {16'h4713, 8'h03};
assign cfg_data_reg[244] = {16'h4407, 8'h04};
assign cfg_data_reg[245] = {16'h460b, 8'h37};
assign cfg_data_reg[246] = {16'h460c, 8'h20};
assign cfg_data_reg[247] = {16'h4837, 8'h16};
assign cfg_data_reg[248] = {16'h3824, 8'h04};
assign cfg_data_reg[249] = {16'h5001, 8'h83};
assign cfg_data_reg[250] = {16'h3503, 8'h00};

//-------------------------------------------------------

endmodule

12.3.1.2. 顶层模块

顶层模块部分只列出参考代码,不再进行模块框图讲解和波形图的绘制,参考代码具体见代码清单 62‑2。

代码清单 62‑2 顶层模块参考代码(ov5640_hdmi_1280x720.v)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
module ov5640_hdmi_1280x720
(
input wire sys_clk , //输入系统时钟,50MHz
input wire sys_rst_n , //输入复位信号,低电平有效
//CMOS
input wire [7:0] ov5640_data , //摄像头采集图像数据
input wire ov5640_vsync , //摄像头采集图像场同步信号
input wire ov5640_href , //摄像头采集图像行同步信号
input wire ov5640_pclk , //摄像头像素时钟
output wire ov5640_rst_n , //
output wire ov5640_pwdn , //
output wire sccb_scl , //SCCB串行时钟
inout wire sccb_sda , //SCCB串行数据
//SDRAM
output wire sdram_clk , //SDRAM 芯片时钟
output wire sdram_cke , //SDRAM 时钟有效
output wire sdram_cs_n , //SDRAM 片选
output wire sdram_ras_n , //SDRAM 行有效
output wire sdram_cas_n , //SDRAM 列有效
output wire sdram_we_n , //SDRAM 写有效
output wire [1:0] sdram_dqm , //SDRAM 数据掩码
output wire [1:0] sdram_ba , //SDRAM Bank地址
output wire [12:0] sdram_addr , //SDRAM 行/列地址
inout wire [15:0] sdram_dq , //SDRAM 数据
//HDMI
output wire tmds_clk_p ,
output wire tmds_clk_n , //HDMI时钟差分信号
output wire [2:0] tmds_data_p ,
output wire [2:0] tmds_data_n //HDMI图像差分信号
);

////
//\* Parameter and Internal Signal \//
////
//parameter define
parameter H_PIXEL = 1280;
parameter V_PIXEL = 720 ;

//wire define
wire clk_125m ;
wire clk_125m_shift ;
wire clk_25m ;
wire locked1 ;
wire clk_74m ;
wire clk_371m ;
wire locked2 ;
wire rst_n ;
wire sdram_init_done ;
wire cfg_done ;
wire sys_init_done ;
wire [15:0] image_data ;
wire image_data_en ;
wire [15:0] vga_rgb ;
wire rdreq ;
wire vga_hs ;
wire vga_vs ;
wire vga_de ;
wire [7:0] vga_r ;
wire [7:0] vga_g ;
wire [7:0] vga_b ;


assign ov5640_pwdn = 1'b0;
assign ov5640_rst_n = 1'b1;
assign rst_n = (sys_rst_n & locked1 & locked2);
assign sys_init_done = sdram_init_done & cfg_done;

////
//\* Instantiate \//
////
//------------- clk_gen_inst -------------
clk_gen clk_gen_inst
(
.areset (~sys_rst_n ),
.inclk0 (sys_clk ),
.c0 (clk_125m ),
.c1 (clk_125m_shift ),
.c2 (clk_25m ),
.locked (locked1 )
);

//------------- clk_hdmi_inst -------------
clk_hdmi clk_hdmi_inst
(
.areset (~sys_rst_n),
.inclk0 (sys_clk ),
.c0 (clk_74m ),
.c1 (clk_371m ),
.locked (locked2 )
);

//------------- ov5640_top_inst -------------
ov5640_top ov5640_top_inst
(
.sys_clk (clk_25m ), //系统时钟
.sys_rst_n (rst_n ), //复位信号
.sys_init_done (sys_init_done ), //系统初始化完成(SDRAM + 摄像头)

.ov5640_pclk (ov5640_pclk ), //摄像头像素时钟
.ov5640_href (ov5640_href ), //摄像头行同步信号
.ov5640_vsync (ov5640_vsync ), //摄像头场同步信号
.ov5640_data (ov5640_data ), //摄像头图像数据

.cfg_done (cfg_done ), //寄存器配置完成
.sccb_scl (sccb_scl ), //SCL
.sccb_sda (sccb_sda ), //SDA
.ov5640_wr_en (image_data_en ), //图像数据有效使能信号
.ov5640_data_out (image_data ) //图像数据

);

//------------- sdram_top_inst -------------
sdram_top sdram_top_inst
(
.sys_clk (clk_125m ), //sdram 控制器参考时钟
.clk_out (clk_125m_shift ), //用于输出的相位偏移时钟
.sys_rst_n (rst_n ), //系统复位
//用户写端口
.wr_fifo_wr_clk (ov5640_pclk ), //写端口FIFO: 写时钟
.wr_fifo_wr_req (image_data_en ), //写端口FIFO: 写使能
.wr_fifo_wr_data (image_data ), //写端口FIFO: 写数据
.sdram_wr_b_addr (24'd0 ), //写SDRAM的起始地址
.sdram_wr_e_addr (H_PIXEL*V_PIXEL), //写SDRAM的结束地址
.wr_burst_len (10'd512 ), //写SDRAM时的数据突发长度
.wr_rst (~rst_n ), //写端口复位
//用户读端口
.rd_fifo_rd_clk (clk_74m ), //读端口FIFO: 读时钟
.rd_fifo_rd_req (rdreq ), //读端口FIFO: 读使能
.rd_fifo_rd_data (vga_rgb ), //读端口FIFO: 读数据
.sdram_rd_b_addr (24'd0 ), //读SDRAM的起始地址
.sdram_rd_e_addr (H_PIXEL*V_PIXEL), //读SDRAM的结束地址
.rd_burst_len (10'd512 ), //从SDRAM中读数据时的突发长度
.rd_fifo_num ( ), //读fifo中的数据量
.rd_rst (~rst_n ), //读端口复位
//用户控制端口
.read_valid (1'b1 ), //SDRAM 读使能
.pingpang_en (1'b1 ), //SDRAM 乒乓操作使能
.init_end (sdram_init_done), //SDRAM 初始化完成标志
//SDRAM 芯片接口
.sdram_clk (sdram_clk ), //SDRAM 芯片时钟
.sdram_cke (sdram_cke ), //SDRAM 时钟有效
.sdram_cs_n (sdram_cs_n ), //SDRAM 片选
.sdram_ras_n (sdram_ras_n ), //SDRAM 行有效
.sdram_cas_n (sdram_cas_n ), //SDRAM 列有效
.sdram_we_n (sdram_we_n ), //SDRAM 写有效
.sdram_ba (sdram_ba ), //SDRAM Bank地址
.sdram_addr (sdram_addr ), //SDRAM 行/列地址
.sdram_dq (sdram_dq ), //SDRAM 数据
.sdram_dqm (sdram_dqm ) //SDRAM 数据掩码
);

//------------- vga_ctrl_inst -------------
vga_ctrl vga_ctrl_inst
(
.vga_clk (clk_74m ), //输入工作时钟,频率25MHz
.sys_rst_n (rst_n ), //输入复位信号,低电平有效
.pix_data ({vga_rgb[15:11], 3'd0, vga_rgb[10:5], 2'd0,
vga_rgb[4:0], 3'd0}), //输入像素点色彩信息

.pix_data_req(rdreq ), //
.hsync (vga_hs ), //输出行同步信号
.vsync (vga_vs ), //输出场同步信号
.rgb_valid (vga_de ), //
.red (vga_r ),
.green (vga_g ),
.blue (vga_b )
);

//------------- hdmi_ctrl_inst -------------
hdmi_ctrl hdmi_ctrl_inst
(
.clk_1x (clk_74m ), //输入系统时钟
.clk_5x (clk_371m ), //输入5倍系统时钟
.sys_rst_n (rst_n ), //复位信号,低有效
.rgb_blue (vga_b ), //蓝色分量
.rgb_green (vga_g ), //绿色分量
.rgb_red (vga_r ), //红色分量
.hsync (vga_hs ), //行同步信号
.vsync (vga_vs ), //场同步信号
.de (vga_de ), //使能信号
.hdmi_clk_p (tmds_clk_p ),
.hdmi_clk_n (tmds_clk_n ), //时钟差分信号
.hdmi_r_p (tmds_data_p[2]),
.hdmi_r_n (tmds_data_n[2]), //红色分量差分信号
.hdmi_g_p (tmds_data_p[1]),
.hdmi_g_n (tmds_data_n[1]), //绿色分量差分信号
.hdmi_b_p (tmds_data_p[0]),
.hdmi_b_n (tmds_data_n[0]) //蓝色分量差分信号
);

endmodule

12.3.1.3. RTL视图

至此实验工程基本完成,在Quartus中对代码进行编译,编译若有错误,请读者根据错误提示信息作出更改,直至编译通过,编译通过后查看RTL视图,与顶层模块框图对比,两者一致,各信号连接正确。RTL视图,具体见图 62‑4。

OV5640005

图 62‑4 RTL视图

12.4. 上板调试

12.4.1. 引脚约束

仿真验证通过后,准备上板验证,上板验证之前先要进行引脚约束。工程中各输入输出信号与开发板引脚对应关系如表格 62‑4所示。

表格 62‑4 引脚分配表

信号名

信号类型

对应引脚

备注

sys_clk

Input

E1

时钟

sys_rst_n

Input

M15

复位

ov5640_data[7]

Input

L13

OV5640摄像头采集图像数据

ov5640_ data[6]

Input

F13

OV5640摄像头采集图像数据

ov5640_ data[5]

Input

B16

OV5640摄像头采集图像数据

ov5640_ data[4]

Input

C15

OV5640摄像头采集图像数据

ov5640_ data[3]

Input

D16

OV5640摄像头采集图像数据

ov5640_ data[2]

Input

F14

OV5640摄像头采集图像数据

ov5640_ data[1]

Input

F15

OV5640摄像头采集图像数据

ov5640_ data[0]

Input

G15

OV5640摄像头采集图像数据

ov5640_href

Input

J13

摄像头行同步信号

ov5640_vsync

Input

C16

摄像头场同步信号

ov5640_pclk

Input

M16

摄像头数据像素时钟

ov5640_pwdn

Output

G11

摄像头时钟选择信号

ov5640_rst_n

Output

F16

摄像头复位信号

sccb_scl

Output

P15

摄像头SCCB_SCL线

sccb_sda

Inout

N14

摄像头SCCB_SDA线

sdram_clk

Output

R4

SDRAM芯片时钟

sdram_cke

Output

R9

SDRAM时钟有效信号

sdram_cs_n

Output

R12

SDRAM片选信号

sdram_cas_n

Output

R10

SDRAM列地址选通脉冲

sdram_ras_n

Output

R11

SDRAM行地址选通脉冲

sdram_we_n

Output

L9

SDRAM写允许位

sdram_ba[0]

Output

R13

SDRAM的L-Bank地址线

sdram_ba[1]

Output

R14

SDRAM的L-Bank地址线

sdram_addr[0]

Output

P11

SDRAM地址总线

sdram_addr[1]

Output

P14

SDRAM地址总线

sdram_addr[2]

Output

N9

SDRAM地址总线

sdram_addr[3]

Output

N11

SDRAM地址总线

sdram_addr[4]

Output

T14

SDRAM地址总线

sdram_addr[5]

Output

T13

SDRAM地址总线

sdram_addr[6]

Output

T12

SDRAM地址总线

sdram_addr[7]

Output

T11

SDRAM地址总线

sdram_addr[8]

Output

T10

SDRAM地址总线

sdram_addr[9]

Output

P9

SDRAM地址总线

sdram_addr[10]

Output

T15

SDRAM地址总线

sdram_addr[11]

Output

N12

SDRAM地址总线

sdram_addr[12]

Output

M11

SDRAM地址总线

sdram_dqm[0]

Output

M10

SDRAM数据掩码

sdram_dqm[1]

Output

M9

SDRAM数据掩码

sdram_dq[0]

Output

R3

SDRAM数据总线

sdram_dq[1]

Output

T9

SDRAM数据总线

sdram_dq[2]

Output

R5

SDRAM数据总线

sdram_dq[3]

Output

R6

SDRAM数据总线

sdram_dq[4]

Output

R7

SDRAM数据总线

sdram_dq[5]

Output

M8

SDRAM数据总线

sdram_dq[6]

Output

R8

SDRAM数据总线

sdram_dq[7]

Output

N8

SDRAM数据总线

sdram_dq[8]

Output

P8

SDRAM数据总线

sdram_dq[9]

Output

T8

SDRAM数据总线

sdram_dq[10]

Output

T7

SDRAM数据总线

sdram_dq[11]

Output

T6

SDRAM数据总线

sdram_dq[12]

Output

T5

SDRAM数据总线

sdram_dq[13]

Output

T4

SDRAM数据总线

sdram_dq[14]

Output

T3

SDRAM数据总线

sdram_dq[15]

Output

T2

SDRAM数据总线

tmds_clk_p

Output

R16

时钟差分信号

tmds_clk_n

Output

P16

时钟差分信号

tmds_data_p[2]

Output

K15

红色分量差分信号

tmds_data_n[2]

Output

K16

红色分量差分信号

tmds_data_p[1]

Output

L15

绿色分量差分信号

tmds_data_n[1]

Output

L15

绿色分量差分信号

tmds_data_p[0]

Output

N15

蓝色分量差分信号

tmds_data_n[0]

Output

N16

蓝色分量差分信号

下面进行管脚分配,管脚的分配方法在前面章节已有所讲解,在此就不再过多叙述,管脚的分配如下图 62‑5、图 62‑6所示。

OV5640006

图 62‑5 管脚分配

OV5640007

图 62‑6 管脚分配

12.4.1.1. 结果验证

如图 62‑7所示,开发板连接12V直流电源、USB-Blaster下载器JTAG端口、HDMI显示器和OV5640摄像头。线路正确连接后,打开开关为板卡上电。

OV5640008

图 62‑7 程序下载连线图

如图 62‑8所示,使用“Programmer”为开发板下载程序。

OV5640009

图 62‑8 程序下载图

程序下载完成后,HDMI显示屏上会显示出OV5640摄像头采集到的图像,分辨率为1280*720,如图 62‑9所示。

OV5640010 OV5640011

图 62‑9 OV5640+HDMI图像显示

12.5. 章末总结

本章节详细介绍了OV5640摄像头的相关知识,并将OV5640摄像头与HDMI相结合,实现了OV5640采集图像的实时显示,OV5640相比OV7725功能更加强大,读者可查阅数据手册深入学习。