17. 基于sd卡的tft_lcd图像显示

在上面章节,我们利用SDRAM做缓存,使用SD卡读写控制器读取SD卡中存储的图像数据,并将图像通过VGA、HDMI显示器显示。本章节中,我们实现基于SD卡的TFT_LCD图像显示。

17.1. 理论学习

对于本章节涉及的SD卡相关理论知识,读者可查阅“基于SD卡的VGA图像显示”的理论学习小节;对于本章节涉及的TFT_LCD显示的相关理论知识,读者可查阅“TFT_LCD液晶屏驱动设计与验证”的理论学习小节,此处不再赘述。

17.2. 实战演练

17.2.1. 实验目标

使用SD卡数据读写控制器读取事先存储在SD卡的图片数据,将读取的图片数据通过SDRAM数据读写控制器暂存在SDRAM芯片中,通过TFT_LCD显示屏将暂存在SDRAM 的图片显示出来。

SD卡内存储图片有两张,两张图片交替显示在TFT_LCD显示屏上,分辨率为480*272。

17.2.2. 硬件资源

参见“SD卡数据读写控制”、“TFT_LCD液晶屏驱动设计与验证”章节当然“硬件资源”小节。

17.3. 程序设计

17.3.1. 整体说明

在程序设计开始之前,我们先来对实验工程进行一个整体说明,让读者了解整个实验工程的框架结构。工程整体框图,具体见图 67‑1;各子功能模块简介,具体见表格 67‑1。

SDTFT002

图 67‑1 工程整体框图

表格 67‑1 子功能模块功能描述

模块名称

功能描述

clk_gen

时钟生成模块

data_rd_ctrl

图片数据读控制模块

sd_ctrl

SD卡读写控制器

sdram_top

SDRAM读写控制器

tft_ctrl

TFT_LCD显示驱动模块

sd_tft_pic

顶层模块

本实验工程共调用6个模块(SD卡读写控制器和SDRAM读写控制器均视为单个模块),由图标可知,模块sd_tft_pic作为实验工程的顶层模块,内部实例化5个子功能模块。

时钟生成模块clk_gen,为各子功能模块、外部SD卡和SDRAM提供工作时钟;图片数据读控制模块data_rd_ctrl,控制SD卡读写控制器读取SD卡内待显示图片的数据读取;SD卡读写控制器sd_ctrl,读取SD卡内待显示图片数据;SDRAM读写控制器sdram_top,控制SDRAM芯片的数 据读写操作;TFT_LCD显示驱动模块tft_ctrl,读取SDRAM内缓存的图片数据,并将其显示在TFT_LCD显示屏上。

17.3.1.1. 图片数据预处理

图片预处理,读者可参阅“基于SD卡的VGA图像显示”的“图片数据预处理”部分,此处不再赘述,读者要注意的是图片大小为480*272。

17.3.1.2. 时钟生成模块

时钟生成模块clk_gen,为各子功能模块、外部SD卡和SDRAM提供工作时钟。输入50MHz板卡晶振时钟信号,输出5路时钟信号c0-c4,时钟频率为100MHz、100MHz(相位偏移)、50MHz、50MHz(相位偏移)、25MHz,前两路时钟信号输入SDRAM读写控制器和SDRAM存储芯片;中 间两路输入SD卡读写控制器和SD存储卡;最后一路输入VGA显示驱动模块。

时钟生成模块clk_gen,调动IP和生成,具体生成方法,读者可参阅“快速开发的法宝 — IP核”章节,此处不再赘述。

17.3.1.3. SD卡数据读写控制器

SD卡数据读写控制器的相关内容在“SD卡数据读写控制”章节已经做了详细说明,读者若有遗忘可回顾翻阅,此处不再赘述。

17.3.1.4. SDRAM数据读写控制器

SDRAM数据读写控制器的相关内容在“SDRAM读写控制器的设计与验证”章节已经做了详细说明,读者若有遗忘可回顾翻阅,此处不再赘述。

17.3.1.5. 图片数据读控制模块

图片数据读控制模块的相关内容在“基于SD卡的VGA图像显示”章节已经做了详细说明,读者若有遗忘可回顾翻阅,此处不再赘述。

17.3.1.6. TFT_LCD驱动控制模块

TFT_LCD驱动控制模块的相关内容在“TFT_LCD液晶屏驱动设计与验证”章节已经做了详细说明,读者若有遗忘可回顾翻阅,此处不再赘述。

17.3.1.7. 顶层模块

讲到这里,实验工程涉及的子功能模块均已介绍完毕,接下来说明整个实验工程的顶层模块。

模块框图

顶层模块将各子功能模块实例化其中,连接各自对应信号,顶层模块模块框图如所图 67‑2示。

SDTFT003

图 67‑2 顶层模块模块框图

由图可知,顶层模块有输入输出信号共22路,3路输入信号有时钟信号、复位信号、和SD卡传入的主输入从输出信号sd_miso;16路输出信号中有3路输出到SD卡,包括SD卡时钟信号sd_clk、片选信号sd_cs_n和主输出从输入信号sd_mosi; 10路输出到SDRAM,包括时钟信号、使能信号、地址信号和数据信号;6路输出到TFT_LCD驱动控制模块,提供行场同步信号、待显示数据、时钟信号和使能信号。

代码编写

顶层模块的代码较为较为简单,只是对各模块进行实例化以及连接各自对应信号,无需波形图的绘制。编写顶层模块参考代码,具体见代码清单 67‑1。

代码清单 67‑1 顶层模块参考代码(sd_tft_pic.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
module sd_tft_pic
(
input wire sys_clk , //输入工作时钟,频率50MHz
input wire sys_rst_n , //输入复位信号,低电平有效
//SD卡
input wire sd_miso , //主输入从输出信号
output wire sd_clk , //SD卡时钟信号
output wire sd_cs_n , //片选信号
output wire sd_mosi , //主输出从输入信号
//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 [15:0] tft_rgb , //输出像素信息
output wire tft_hs , //输出TFT行同步信号
output wire tft_vs , //输出TFT场同步信号
output wire tft_clk , //输出TFT像素时钟
output wire tft_de , //输出TFT数据使能
output wire tft_bl //输出TFT背光信号
);

////
//\* Parameter and Internal Signal \//
////
//parameter define
parameter H_VALID = 24'd480 ; //行有效数据
parameter V_VALID = 24'd272 ; //列有效数据

//wire define
wire rst_n ; //复位信号
wire clk_100m ; //生成100MHz时钟
wire clk_100m_shift ; //生成100MHz时钟,相位偏移180度
wire clk_50m ; //生成50MHz时钟
wire clk_50m_shift ; //生成50MHz时钟,相位偏移180度
wire clk_9m ; //生成9MHz时钟
wire locked ; //时钟锁定信号
wire sys_init_end ; //系统初始化完成

wire sd_rd_en ; //开始写SD卡数据信号
wire [31:0] sd_rd_addr ; //读数据扇区地址
wire sd_rd_busy ; //读忙信号
wire sd_rd_data_en ; //数据读取有效使能信号
wire [15:0] sd_rd_data ; //读数据
wire sd_init_end ; //SD卡初始化完成信号

wire wr_en ; //sdram_ctrl模块写使能
wire [15:0] wr_data ; //sdram_ctrl模块写数据
wire rd_en ; //sdram_ctrl模块读使能
wire [15:0] rd_data ; //sdram_ctrl模块读数据
wire sdram_init_end ; //SDRAM初始化完成

////
//\* Main Code \//
////
//rdt_n:复位信号,系统复位与时钟锁定取与
assign rst_n = sys_rst_n && locked;
//sys_init_end:系统初始化完成,SD卡和SDRAM均完成初始化
assign sys_init_end = sd_init_end && sdram_init_end;

////
//\* Instantiation \//
////
//------------- clk_gen_inst -------------
clk_gen clk_gen_inst
(
.areset (~sys_rst_n ), //复位信号,高有效
.inclk0 (sys_clk ), //输入系统时钟,50MHz

.c0 (clk_100m ), //生成100MHz时钟
.c1 (clk_100m_shift ), //生成100MHz时钟,相位偏移180度
.c2 (clk_50m ), //生成50MHz时钟
.c3 (clk_50m_shift ), //生成50MHz时钟,相位偏移180度
.c4 (clk_9m ), //生成9MHz时钟
.locked (locked ) //时钟锁定信号
);

//------------- data_rd_ctrl_inst -------------
data_rd_ctrl data_rd_ctrl_inst
(
.sys_clk (clk_50m ), //输入工作时钟,频率50MHz
.sys_rst_n (rst_n & sys_init_end ), //输入复位信号,低电平有效
.rd_busy (sd_rd_busy ), //读操作忙信号

.rd_en (sd_rd_en ), //数据读使能信号
.rd_addr (sd_rd_addr ) //读数据扇区地址
);

//------------- sd_ctrl_inst -------------
sd_ctrl sd_ctrl_inst
(
.sys_clk (clk_50m ), //输入工作时钟,频率50MHz
.sys_clk_shift (clk_50m_shift ), //输入工作时钟,频率50MHz,相位偏移180度
.sys_rst_n (rst_n ), //输入复位信号,低电平有效

.sd_miso (sd_miso ), //主输入从输出信号
.sd_clk (sd_clk ), //SD卡时钟信号
.sd_cs_n (sd_cs_n ), //片选信号
.sd_mosi (sd_mosi ), //主输出从输入信号

.wr_en (1'b0 ), //数据写使能信号
.wr_addr (32'b0 ), //写数据扇区地址
.wr_data (16'b0 ), //写数据
.wr_busy ( ), //写操作忙信号
.wr_req ( ), //写数据请求信号

.rd_en (sd_rd_en ), //数据读使能信号
.rd_addr (sd_rd_addr ), //读数据扇区地址
.rd_busy (sd_rd_busy ), //读操作忙信号
.rd_data_en (sd_rd_data_en ), //读数据标志信号
.rd_data (sd_rd_data ), //读数据

.init_end (sd_init_end ) //SD卡初始化完成信号
);

//------------- 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 (clk_50m ), //写端口FIFO: 写时钟
.wr_fifo_wr_req (sd_rd_data_en ), //写端口FIFO: 写使能
.wr_fifo_wr_data (sd_rd_data ), //写端口FIFO: 写数据
.sdram_wr_b_addr (24'd0 ), //写SDRAM的起始地址
.sdram_wr_e_addr (H_VALID*V_VALID), //写SDRAM的结束地址
.wr_burst_len (10'd512 ), //写SDRAM时的数据突发长度
.wr_rst (~rst_n ), //写端口复位: 复位写地址,清空写FIFO
//用户读端口
.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_VALID*V_VALID), //读SDRAM的结束地址
.rd_burst_len (10'd512 ), //从SDRAM中读数据时的突发长度
.rd_fifo_num ( ), //读fifo中的数据量
.rd_rst (~rst_n ), //读端口复位: 复位读地址,清空读FIFO
//用户控制端口
.read_valid (1'b1 ), //SDRAM 读使能
.pingpang_en (1'b0 ), //SDRAM 乒乓操作使能
.init_end (sdram_init_end ), //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 数据掩码
);

//------------- tft_ctrl_inst -------------
tft_ctrl tft_ctrl_inst
(
.clk_9m (clk_9m ), //输入时钟,频率9MHz
.sys_rst_n (rst_n ), //系统复位,低电平有效
.data_in (rd_data ), //待显示数据

.data_req (rd_en ), //数据请求信号
.rgb_tft (tft_rgb ), //TFT显示数据
.hsync (tft_hs ), //TFT行同步信号
.vsync (tft_vs ), //TFT场同步信号
.tft_clk (tft_clk ), //TFT像素时钟
.tft_de (tft_de ), //TFT数据使能
.tft_bl (tft_bl ) //TFT背光信号
);

endmodule

RTL视图

顶层代码编写完成后,使用Quartus软件对实验工程进行编译,编译通过后查看RTL视图,如图 67‑3所示。RTL视图与实验工程框图一致,各信号连接正确。

SDTFT004

图 67‑3 RTL视图

17.4. 上板调试

17.4.1. 引脚约束

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

表格 67‑2 引脚分配表

信号名

信号类型

对应引脚

备注

sys_clk

Input

E1

时钟

sys_rst_n

Input

M15

复位

sd_miso

input

J16

SD卡主输入从输出信号

sd_clk

output

J12

SD卡时钟信号

sd_cs_n

output

K12

SD卡片选信号

sd_mosi

output

J14

SD卡主输出从输入信号

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色彩信息(蓝)

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

SDTFT005

图 67‑4 管脚分配

SDTFT006

图 67‑5 管脚分配

17.4.1.1. 结果验证

如图 67‑6所示,开发板连接12V直流电源、USB-Blaster下载器JTAG端口、连接TFT_LCD液晶屏、插入SD卡。线路正确连接后,打开开关为板卡上电。

SDTFT007

图 67‑6 程序下载连线图

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

SDTFT008

图 67‑7 程序下载图

程序下载完成后,两幅图片会交替显示再TFT_LCD显示屏上,如图 67‑8、图 67‑9所示。

SDTFT009

图 67‑8 SD卡存储图片显示

SDTFT010

图 67‑9 SD卡存储图片显示

17.5. 章末总结

本章节我们使用前面章节设计的SD卡数据读写控制器,与TFT_LCD显示相结合,并通过实验实现了SD卡存储图片的TFT_LCD液晶屏显示。读者要认真理解相关理论知识,切实掌握SD卡数据读写控制器的设计与实现。