10. ov7725摄像头tft_lcd图像显示

在上面章节,我们实现了OV7725摄像头采集VGA、HDMI图像显示,显示分辨率为640*480。我们知道OV7725摄像头可实现VGA(分辨率640*480)和QVGA(分辨率320*240)两种分辨率的采集和显示,在本章节,我们使用TFT显示屏显示ov7725摄像头采集的图像,显示分辨率为QVG A(分辨率320*240)。

10.1. 理论学习

参见“OV7725摄像头VGA图像显示”的“理论学习”小节。

10.2. 实战演练

10.2.1. 实验目标

使用SDRAM做图像数据缓存,将OV7725摄像头采集到的图像数据在TFT显示屏上实时显示。分辨率为320*240。

10.2.2. 硬件资源

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

10.3. 程序设计

10.3.1. 整体说明

在本小节我们分两部分讲解一下实验工程的整体框架,第一部分是OV7725的相关模块,与OV7725摄像头VGA显示章节中OV7725的相关模块部分相同,具体见图 60‑1、表格 60‑1。

OV7725002

图 60‑1 OV7725整体框图

表格 60‑1 OV7725各模块功能介绍

模块名称

功能描述

ov7725_top

OV7725顶层模块

i2c_ctrl

i2c驱动模块

ov7725_cfg

OV7725寄存器配置模块

ov7725_data

OV7725图像采集模块

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

接下来说一下实验工程的第二部分。在第二部分中将第一部分的ov7725摄像头部分视为一个子模块,与其他子功能模块构成整个实验工程,与OV7725摄像头VGA显示章节的相关部分也类似,只是将VGA显示部分替换成了TFT显示模块。整体框图和子功能模块介绍,具体见图 60‑2、表格 60‑2。

OV7725003

图 60‑2 OV7725-TFT图像显示整体框图

表格 60‑2 OV7725-TFT图像显示各子模块功能描述

模块名称

功能描述

ov7725_tft_320x240

实验工程顶层模块

clk_gen

时钟生成模块

ov7725_top

OV7725相关部分

sdram_top

SDRAM读写控制器

tft_ctrl

tft驱动模块

由图表可知,OV7725-TFT图像显示工程包含表格模块,ov7725_tft_320x240作为实验工程的顶层模块,内部实例化各子功能模块,连接对应信号,对外接收摄像头采集的图像数据,将处理后的数据存入SDRAM,在TFT显示屏上显示出来;clk_gen模块,调用IP核生成,产生整个实验工程的工作 时钟;ov7725_top模块,是ov7725部分各子功能模块的集合,实现ov7725摄像头的配置、图像采集与处理;sdram_top模块为SDRAM读写控制器,存储处理后的图像数据;tft_ctrl模块实现TFT显示屏的驱动控制,读取SDRAM存储的图像数据并在TFT_LCD上显示出来。

本本实验工程中的各子功能模块均是复用前面章节的相关模块,有些模块做了较大改动,在此我们只简要说明一下改动较大的寄存器配置模块ov7725_cfg和TFT驱动模块,其他改动较小或未改动模块不再说明,读者可自行回顾前面相关章节。

10.3.1.1. 寄存器配置模块

模块框图

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

OV7725004

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

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

信号

位宽

类型

功能描述

sys_rst_n

1bit

input

复位信号,低有效

cfg_end

1bit

input

一个寄存器配置完成

sys_clk

1bit

input

模块工作时钟

cfg_start

1bit

output

单个寄存器配置触发信号

cfg_data

16bit

output

寄存器地址+数据

cfg_done

1bit

output

寄存器配置完成信号

代码编写

要想OV7725摄像头正常工作,需要先对摄像头进行寄存器配置,即向摄像头寄存器写入对应指令。由数据手册可知,OV7725摄像头只支持VGA(640*480)和QVGA(320*240)两种显示模式。在OV7725摄像头VGA显示章节,我们通过寄存器的配置实现了分辨率640*480的图像显示。本实验我 们要使用QVGA这一显示模式,对于摄像头的某些寄存器需要重新配置,寄存器配置模块的某些指令需要作出修改。

由于寄存器数量较多,在此我们只列出参考代码,各寄存器的相关内容,读者可翻阅数据手册进行学习。模块参考代码,具体见代码清单 60‑1。

代码清单 60‑1 寄存器配置模块参考代码(ov7725_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
module ov7725_cfg
(
input wire sys_clk , //系统时钟,由iic模块传入
input wire sys_rst_n , //系统复位,低有效
input wire cfg_end , //单个寄存器配置完成

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

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

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

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

//reg define
reg [9:0] cnt_wait ; //寄存器配置等待计数器
reg [6: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 <= 7'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) ? 16'h0000 : cfg_data_reg[reg_num];

//----------------------------------------------------
//cfg_data_reg:寄存器配置数据暂存 ID REG_ADDR REG_VAL
assign cfg_data_reg[00] = {8'h3d, 8'h03};
assign cfg_data_reg[01] = {8'h15, 8'h02};
assign cfg_data_reg[02] = {8'h17, 8'h3f};
assign cfg_data_reg[03] = {8'h18, 8'h50};
assign cfg_data_reg[04] = {8'h19, 8'h07};
assign cfg_data_reg[05] = {8'h1a, 8'h78};
assign cfg_data_reg[06] = {8'h32, 8'h00};
assign cfg_data_reg[07] = {8'h29, 8'h50};
assign cfg_data_reg[08] = {8'h2a, 8'h00};
assign cfg_data_reg[09] = {8'h2b, 8'h00};
assign cfg_data_reg[10] = {8'h2c, 8'h78};
assign cfg_data_reg[11] = {8'h0d, 8'h41};
assign cfg_data_reg[12] = {8'h11, 8'h00};
assign cfg_data_reg[13] = {8'h12, 8'h06};
assign cfg_data_reg[14] = {8'h0c, 8'hd0};
assign cfg_data_reg[15] = {8'h42, 8'h7f};
assign cfg_data_reg[16] = {8'h4d, 8'h09};
assign cfg_data_reg[17] = {8'h63, 8'hf0};
assign cfg_data_reg[18] = {8'h64, 8'hff};
assign cfg_data_reg[19] = {8'h65, 8'h00};
assign cfg_data_reg[20] = {8'h66, 8'h00};
assign cfg_data_reg[21] = {8'h67, 8'h00};
assign cfg_data_reg[22] = {8'h13, 8'hff};
assign cfg_data_reg[23] = {8'h0f, 8'hc5};
assign cfg_data_reg[24] = {8'h14, 8'h11};
assign cfg_data_reg[25] = {8'h22, 8'h98};
assign cfg_data_reg[26] = {8'h23, 8'h03};
assign cfg_data_reg[27] = {8'h24, 8'h40};
assign cfg_data_reg[28] = {8'h25, 8'h30};
assign cfg_data_reg[29] = {8'h26, 8'ha1};
assign cfg_data_reg[30] = {8'h6b, 8'haa};
assign cfg_data_reg[31] = {8'h13, 8'hff};
assign cfg_data_reg[32] = {8'h90, 8'h0a};
assign cfg_data_reg[33] = {8'h91, 8'h01};
assign cfg_data_reg[34] = {8'h92, 8'h01};
assign cfg_data_reg[35] = {8'h93, 8'h01};
assign cfg_data_reg[36] = {8'h94, 8'h5f};
assign cfg_data_reg[37] = {8'h95, 8'h53};
assign cfg_data_reg[38] = {8'h96, 8'h11};
assign cfg_data_reg[39] = {8'h97, 8'h1a};
assign cfg_data_reg[40] = {8'h98, 8'h3d};
assign cfg_data_reg[41] = {8'h99, 8'h5a};
assign cfg_data_reg[42] = {8'h9a, 8'h1e};
assign cfg_data_reg[43] = {8'h9b, 8'h3f};
assign cfg_data_reg[44] = {8'h9c, 8'h25};
assign cfg_data_reg[45] = {8'h9e, 8'h81};
assign cfg_data_reg[46] = {8'ha6, 8'h06};
assign cfg_data_reg[47] = {8'ha7, 8'h65};
assign cfg_data_reg[48] = {8'ha8, 8'h65};
assign cfg_data_reg[49] = {8'ha9, 8'h80};
assign cfg_data_reg[50] = {8'haa, 8'h80};
assign cfg_data_reg[51] = {8'h7e, 8'h0c};
assign cfg_data_reg[52] = {8'h7f, 8'h16};
assign cfg_data_reg[53] = {8'h80, 8'h2a};
assign cfg_data_reg[54] = {8'h81, 8'h4e};
assign cfg_data_reg[55] = {8'h82, 8'h61};
assign cfg_data_reg[56] = {8'h83, 8'h6f};
assign cfg_data_reg[57] = {8'h84, 8'h7b};
assign cfg_data_reg[58] = {8'h85, 8'h86};
assign cfg_data_reg[59] = {8'h86, 8'h8e};
assign cfg_data_reg[60] = {8'h87, 8'h97};
assign cfg_data_reg[61] = {8'h88, 8'ha4};
assign cfg_data_reg[62] = {8'h89, 8'haf};
assign cfg_data_reg[63] = {8'h8a, 8'hc5};
assign cfg_data_reg[64] = {8'h8b, 8'hd7};
assign cfg_data_reg[65] = {8'h8c, 8'he8};
assign cfg_data_reg[66] = {8'h8d, 8'h20};
assign cfg_data_reg[67] = {8'h0e, 8'h65};
assign cfg_data_reg[68] = {8'h09, 8'h00};
//-------------------------------------------------------

endmodule

模块参考代码编写完毕,对于模块的仿真验证,与ov7725摄像头VGA显示章节的寄存器模块的仿真验证相同,读者可自行对模块进行仿真验证,此处不再进行。

10.3.1.2. TFT驱动模块

模块框图

TFT显示时序控制模块,作用是驱动TFT显示屏,将输入模块的彩条图形像素点信息,按照TFT显示时序扫描显示到TFT显示屏上。模块框图,具体见图 60‑4。

OV7725005

图 60‑4 VGA时序控制模块框图

由图 60‑4可知,VGA时序控制模块包含3路输入、8路输出,共11路信号,输入输出信号简介,具体见表格 60‑4。

表格 60‑4 VGA时序控制模块输入输出信号信号功能描述

信号

位宽

类型

功能描述

clk_9m

1Bit

Input

工作时钟,频率9MHz

sys_rst_n

1Bit

Input

复位信号,低电平有效

data_in

16Bit

Input

图像像素点色彩信息

data_req

1Bit

Input

图像数据请求信号

hsync

1Bit

Output

行同步信号

vsync

1Bit

Output

场同步信号

rgb

16Bit

Output

RGB图像色彩信息

tft_bl

1Bit

Output

TFT显示屏背光信号

tft_clk

1Bit

Output

TFT显示屏时钟信号

tft_de

1Bit

Output

TFT显示屏使能信号

输入信号中,时钟信号clk_9m,频率为9MHz,为模块工作时钟,由分频模块产生并输入;复位信号sys_rst_n为顶层模块的rst_n信号输入,低电平有效;data_in为图像像素点色彩信息,由图像数据生成模块产生并传入,在TFT显示器有效图像显示区域赋值给信号RGB图像色彩信息(rgb_tft) 。

输出信号data_req为图像数据请求信号;hsync、vsync为VGA行、场同步信号 ,通过VGA接口传输给VGA显示器;rgb_tft为显示器要显示的图像色彩信息,传输给VGA显示器;tft_bl为TFT显示屏背光信号;tft_clk为TFT显示屏工作时钟;tft_de为TFT显示使能信号。

代码编写

本实验要在4.3寸(分辨率480*272)的TFT_LCD显示屏上实时显示OV7725摄像头采集的图像信息,显示模式为QVGA(320*240)。要想保证图像的正确显示,需要对TFT显示模块做些修改,在显示屏的中心位置显示有效图像,其他显示位置强制显示黑色。

本实验在原有的TFT驱动模块基础上加以修改,以满足实验要求,改动部分理解较为简单,不再进行波形图的绘制,直接在原有代码基础上修改。修改后的TFT驱动模块参考代码,具体见代码清单 60‑2。

代码清单 60‑2 TFT驱动模块参考代码(tft_ctrl.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
module tft_ctrl
(
input wire clk_9m , //输入时钟,频率9MHz
input wire sys_rst_n , //系统复位,低电平有效
input wire [15:0] data_in , //待显示数据

output wire data_req , //数据请求信号
output wire [15:0] rgb_tft , //TFT显示数据
output wire hsync , //TFT行同步信号
output wire vsync , //TFT场同步信号
output wire tft_clk , //TFT像素时钟
output wire tft_de , //TFT数据使能
output wire tft_bl //TFT背光信号
);

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

//parameter define
parameter H_SYNC = 11'd41 , //行同步
H_BACK = 11'd2 , //行时序后沿
H_LEFT = 11'd0 , //行时序左边框
H_VALID = 11'd480 , //行有效数据
H_RIGHT = 11'd0 , //行时序右边框
H_FRONT = 11'd2 , //行时序前沿
H_TOTAL = 11'd525 ; //行扫描周期
parameter V_SYNC = 11'd10 , //场同步
V_BACK = 11'd2 , //场时序后沿
V_TOP = 11'd0 , //场时序左边框
V_VALID = 11'd272 , //场有效数据
V_BOTTOM = 11'd0 , //场时序右边框
V_FRONT = 11'd2 , //场时序前沿
V_TOTAL = 11'd286 ; //场扫描周期
parameter H_PIXEL = 11'd320 , //水平方向有效图像像素个数
V_PIXEL = 11'd240 ; //垂直方向有效图像像素个数
parameter H_BLACK = ((H_VALID - H_PIXEL) / 2),//水平方向黑色边框宽度
V_BLACK = ((V_VALID - V_PIXEL) / 2);//垂直方向黑色边框宽度

//wire define
wire data_valid ; //有效显示区域标志
wire [15:0] data_out ; //输出有效图像数据

//reg define
reg [9:0] cnt_h ; //行扫描计数器
reg [9:0] cnt_v ; //场扫描计数器
reg data_req_dly; //数据请求信号打一拍

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

//tft_clk,tft_de,tft_bl:TFT像素时钟、数据使能、背光信号
assign tft_clk = clk_9m ;
assign tft_de = data_valid;
assign tft_bl = sys_rst_n ;

//cnt_h:行扫描计数器
always@(posedge clk_9m or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_h <= 10'd0;
else if(cnt_h == H_TOTAL - 1'b1)
cnt_h <= 10'd0;
else
cnt_h <= cnt_h + 10'd1;

//cnt_v:场扫描计数器
always@(posedge clk_9m or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_v <= 10'd0;
else if(cnt_h == H_TOTAL - 1'b1)
begin
if(cnt_v == V_TOTAL - 1'b1)
cnt_v <= 10'd0;
else
cnt_v <= cnt_v + 10'd1;
end
else
cnt_v <= cnt_v;

//data_valid:有效显示区域标志
assign data_valid = ((cnt_h >= (H_SYNC + H_BACK + H_LEFT - 1'b1))
&& (cnt_h < (H_SYNC + H_BACK + H_LEFT + H_VALID - 1'b1)))
&&((cnt_v >= (V_SYNC + V_BACK + V_TOP - 1'b1))
&& (cnt_v < (V_SYNC + V_BACK + V_TOP + V_VALID - 1'b1)));

//data_req:图像数据请求
assign data_req = ((cnt_h >= (H_SYNC + H_BACK + H_LEFT + H_BLACK - 2))
&& (cnt_h < ((H_SYNC + H_BACK + H_LEFT + H_BLACK + H_PIXEL - 2))))
&&((cnt_v >= ((V_SYNC + V_BACK + V_TOP + V_BLACK)))
&& (cnt_v < ((V_SYNC + V_BACK + V_TOP + V_BLACK + V_PIXEL))));

//data_req_dly:数据请求信号打一拍,作为输出图像数据约束信号
always@(posedge clk_9m or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_req_dly <= 1'b0;
else
data_req_dly <= data_req;

//data_out:输出有效图像数据
assign data_out = (data_req_dly == 1'b1) ? data_in : 16'h0000;

//hsync,vsync,rgb_tft:行、场同步信号、图像数据
assign rgb_tft = (data_valid == 1'b0) ? 16'hFFFF : data_out;
assign hsync = 1'b1 ;
assign vsync = 1'b1 ;
endmodule

10.3.1.3. 顶层模块

本实验的其他子功能模块均是复用之前章节的模块,且在之前章节已经做了详细介绍,这里只对顶层模块参考代码进行列举,其他模块相关知识请参阅前面章节的相关内容。顶层模块参考代码,具体见代码清单 60‑3。

代码清单 60‑3 顶层模块参考代码(ov7725_tft_320x240.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
 module ov7725_tft_320x240
 (
 input wire sys_clk , //系统时钟
 input wire sys_rst_n , //系统复位,低电平有效
 //摄像头接口
 input wire ov7725_pclk , //摄像头数据像素时钟
 input wire ov7725_vsync, //摄像头场同步信号
 input wire ov7725_href , //摄像头行同步信号
 input wire [7:0] ov7725_data , //摄像头数据
 output wire ov7725_rst_n, //摄像头复位信号,低电平有效
 output wire ov7725_pwdn , //摄像头时钟选择信号
 output wire sccb_scl , //摄像头SCCB_SCL线
 inout wire sccb_sda , //摄像头SCCB_SDA线
 //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_ba , //SDRAM Bank地址
 output wire [1:0] sdram_dqm , //SDRAM 数据掩码
 output wire [12:0] sdram_addr , //SDRAM 地址
 inout wire [15:0] sdram_dq , //SDRAM 数据
 //TFT接口
 output wire tft_clk , //TFT时钟
 output wire tft_de , //TFT使能
 output wire tft_bl , //背光
 output wire tft_hs , //行同步信号
 output wire tft_vs , //场同步信号
 output wire [15:0] tft_rgb //红绿蓝三原色输出
 );

 ////
 //\* Parameter and Internal Signal \//
 ////
 //parameter define
 parameter H_PIXEL = 24'd320 ,//水平方向像素个数,用于设置SDRAM缓存大小
 V_PIXEL = 24'd240 ;//垂直方向像素个数,用于设置SDRAM缓存大小

 //wire define
 wire clk_100m ; //100MHz时钟,SDRAM操作时钟
 wire clk_100m_shift ; //100MHz时钟,SDRAM相位偏移时钟
 wire clk_9m ; //25MHz时钟,提供给vga驱动时钟
 wire locked ; //PLL锁定信号
 wire rst_n ; //复位信号(sys_rst_n & locked)
 wire cfg_done ; //摄像头初始化完成
 wire wr_en ; //sdram写使能
 wire [15:0] wr_data ; //sdram写数据
 wire rd_en ; //sdram读使能
 wire [15:0] rd_data ; //sdram读数据
 wire sdram_init_done ; //SDRAM初始化完成
 wire sys_init_done ; //系统初始化完成(SDRAM初始化+摄像头初始化)

 ////
 //\* Main Code \//
 ////
 //rst_n:复位信号(sys_rst_n & locked)
 assign rst_n = sys_rst_n & locked;

 //sys_init_done:系统初始化完成(SDRAM初始化+摄像头初始化)
 assign sys_init_done = sdram_init_done & cfg_done;

 //ov7725_rst_n:摄像头复位,固定高电平
 assign ov7725_rst_n = 1'b1;

 //ov7725_pwdn:摄像头时钟选择信号,0:使用引脚XCLK提供的时钟 1:使用摄像头自带的晶振
 assign ov7725_pwdn = 1'b0;

 //------------- clk_gen_inst -------------
 clk_gen clk_gen_inst(

 .areset (~sys_rst_n ),
 .inclk0 (sys_clk ),
 .c0 (clk_100m ),
 .c1 (clk_100m_shift ),
 .c2 (clk_9m ),
 .locked (locked )

 );

 //------------- ov7725_top_inst -------------
 ov7725_top ov7725_top_inst(

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

 .ov7725_pclk (ov7725_pclk ), //摄像头像素时钟
 .ov7725_href (ov7725_href ), //摄像头行同步信号
 .ov7725_vsync (ov7725_vsync ), //摄像头场同步信号
 .ov7725_data (ov7725_data ), //摄像头图像数据

 .cfg_done (cfg_done ), //寄存器配置完成
 .sccb_scl (sccb_scl ), //SCL
 .sccb_sda (sccb_sda ), //SDA
 .ov7725_wr_en (wr_en ), //图像数据有效使能信号
 .ov7725_data_out (wr_data ) //图像数据

 );

 //------------- sdram_top_inst -------------
 sdram_top sdram_top_inst(

 .sys_clk (clk_100m ), //sdram 控制器参考时钟
 .clk_out (clk_100m_shift ), //用于输出的相位偏移时钟
 .sys_rst_n (rst_n ), //系统复位
 //用户写端口
 .wr_fifo_wr_clk (ov7725_pclk ), //写端口FIFO: 写时钟
 .wr_fifo_wr_req (wr_en ), //写端口FIFO: 写使能
 .wr_fifo_wr_data (wr_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_9m ), //读端口FIFO: 读时钟
 .rd_fifo_rd_req (rd_en ), //读端口FIFO: 读使能
 .rd_fifo_rd_data (rd_data ), //读端口FIFO: 读数据
 .sdram_rd_b_addr (24'd0 ), //读SDRAM的起始地址
 .sdram_rd_e_addr (H_PIXEL*V_PIXEL), //读SDRAM的结束地址
 .rd_burst_len (10'd512 ), //从SDRAM中读数据时的突发长度
 .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 数据掩码

 );
endmodule

10.3.1.4. RTL视图

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

OV7725006

图 60‑5 RTL视图

10.4. 上板调试

10.4.1. 引脚约束

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

表格 60‑5 引脚分配表

信号名

信号类型

对应引脚

备注

sys_clk

Input

E1

时钟

sys_rst_n

Input

M15

复位

ov7725_data[7]

Input

L13

OV7725摄像头采集图像数据

ov7725_ data[6]

Input

F13

OV7725摄像头采集图像数据

ov7725_ data[5]

Input

B16

OV7725摄像头采集图像数据

ov7725_ data[4]

Input

C15

OV7725摄像头采集图像数据

ov7725_ data[3]

Input

D16

OV7725摄像头采集图像数据

ov7725_ data[2]

Input

F14

OV7725摄像头采集图像数据

ov7725_ data[1]

Input

F15

OV7725摄像头采集图像数据

ov7725_ data[0]

Input

G15

OV7725摄像头采集图像数据

ov7725_href

Input

J13

摄像头行同步信号

ov7725_vsync

Input

C16

摄像头场同步信号

ov7725_pclk

Input

M16

摄像头数据像素时钟

ov7725_pwdn

Output

G11

摄像头时钟选择信号

ov7725_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数据总线

tft_clk

Output

L2

时钟信号

tft_de

Output

K1

使能信号

tft_bl

Output

L3

背光信号

tft_hs

Output

L1

行同步信号

tft_vs

Output

K2

场同步信号

tft_rgb [15]

Output

G1

RGB色彩信息(红)

tft_rgb [14]

Output

F5

RGB色彩信息(红)

tft_rgb [13]

Output

F3

RGB色彩信息(红)

tft_rgb [12]

Output

F2

RGB色彩信息(红)

tft_rgb [11]

Output

F1

RGB色彩信息(红)

tft_rgb [10]

Output

E5

RGB色彩信息(绿)

tft_rgb [9]

Output

D4

RGB色彩信息(绿)

tft_rgb [8]

Output

J6

RGB色彩信息(绿)

tft_rgb [7]

Output

K6

RGB色彩信息(绿)

tft_rgb [6]

Output

L6

RGB色彩信息(绿)

tft_rgb [5]

Output

J2

RGB色彩信息(绿)

tft_rgb [4]

Output

J1

RGB色彩信息(蓝)

tft_rgb [3]

Output

L4

RGB色彩信息(蓝)

tft_rgb [2]

Output

K5

RGB色彩信息(蓝)

tft_rgb [1]

Output

G5

RGB色彩信息(蓝)

tft_rgb [0]

Output

G2

RGB色彩信息(蓝)

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

OV7725007

图 60‑6 管脚分配

OV7725008

图 60‑7 管脚分配

10.4.1.1. 结果验证

如图 60‑8所示,开发板连接12V直流电源、USB-Blaster下载器JTAG端口、TFT_LCD液晶屏和OV7725摄像头。线路正确连接后,打开开关为板卡上电。

OV7725009

图 60‑8 程序下载连线图

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

OV7725010

图 60‑9 程序下载图

程序下载完成后,TFT_LCD显示屏上会显示出OV7725摄像头采集到的图像,分辨率为320*240,如图 60‑10所示。

OV7725011

图 60‑10 OV7725+TFT_LCD图像显示

10.5. 章末总结

本章节详细介绍了OV7725摄像头的相关知识,并将OV7725摄像头与TFT_LCD相结合,实现了OV7725采集图像的实时显示,本章节对于OV7725的使用知识冰山一角,OV7725还有更多强大功能,读者查阅数据手册深入学习。