导读
VGA (Video Graphics Array) 即视频图形阵列,是IBM于1987年随PS/2机(PersonalSystem 2)一起推出的使用模拟信号的一种视频传输标准。这个标准对于现今的个人电脑市场已经十分过时。但在当时具有分辨率高、显示速率快、颜色丰富等优点,在彩色显示器领域取得了广泛的应用,是众多制造商所共同支持的一个低标准。
LCD ( Liquid Crystal Display 的简称)液晶显示器。LCD 的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。按照背光源的不同,LCD可以分为CCFL显示器和LED显示器两种。LCD已经替代CRT成为主流,价格也已经下降了很多,并已充分普及。
在之前的文章中介绍了如何获取、处理摄像头提供的视频信号,在实际应用中还需要将经过处理的信号显示在显示器上。这个过程与信号处理中的过程上是相反的,将数字信号按照电视信号的制式组成合乎时序、格式要求的信号,并加入用于控制的各种同步信号。本篇将通过 FPGA实现一个 VGA/LCD 显示控制器的实例,并详细介绍实现过程。
第一篇内容摘要:本篇会介绍VGA 显示原理,包括图像显示原理、常用视频显示标准;还会介绍VGA/LCD 显示控制器的基本框架等相关内容。
一、VGA 显示原理
在设计 VGA 显示控制器的实现过程以前,首先需要了解 VGA 的显示原理。
1.1 图像显示原理
VGA 显示控制器控制图像信号通过电缆传输到显示器上并显示出来。目前的显示器技术主要包括两种:CRT(Cathode Ray Tube,阴极射线管)和 LCD(Liquid Crystal Display,液晶显示屏)。CRT 通过帧同步信号和行同步信号控制电子枪的电子束逐行逐点地扫描,将电子打在荧光点上,使之发光。
通过视觉暂留的作用,看到的就是一副完整的画面。LCD 与 CRT 类似,也是动态的扫描。但 CRT 是模拟方式的,通过电路控制,电子束可以任意移动;而 LCD是数字方式的,只有位置固定的电流通路,所以只能通过电路矩阵逐行扫描,而不能逐点,即一行上所有的点同时工作。CRT 显示器连接示意图如图 1 所示。
VGA 显示控制器控制 CRT 显示图像的过程如图 2 所示。
图 2 VGA 显示控制器控制 CRT 显示器的框图
电子枪的扫描过程在行同步、场同步等控制信号的控制下进行,包括水平扫描、水平回扫、垂直扫描、垂直回扫等过程,如图 3 所示。
1.2 常用视频显示标准
视频显示标准随着显示技术和工艺的不断进步而逐步提高:
• 最早用来显示字符的是 MDA 标准(Monochrome Display Adapter,单色显示适配器接口),只支持字符显示方式,只有黑白方式,显示规格 80 列×25 行,分辨率为 720×350。
• CGA 标准(Color Graphic Adapter,彩色图形适配器接口),支持彩色图像方式,显示规格从 40 列×25 行到 80 列×25 行,颜色从黑白到 16 色。
• EGA 标准(Enhanced Graphics Adapter,增强型图形适配器接口),除了兼容 MDA、CGA标准外,还支持增强模式,图形显示规格从 320×200 到 640×350,颜色从黑白到 16 色。
• VGA 标准(Video Graphies Array,视频图形阵列),除了兼容上面各种标准外,还包括 QVGA、VGA、SVGA 等多个子标准,支持从 640×480 到 800×600 等更高的显示规格。目前常用的是 VGA 标准,后面的实例将详细介绍 VGA 标准的显示控制器。
二、VGA/LCD 显示控制器的基本框架
VGA 显示控制器的程序框架如图 4 所示。这个 VGA/LCD 显示控制器提供对 CRT、LCD 的支持,适用于嵌入式系统的开发。
图 8-4 VGA 显示控制器程序框架
VGA 显示控制器的程序框架包括如下几个主要部分:
• 颜色查找表 颜色查找表保存了 256 色分辨率 R、G、B 所有可能颜色,因此它是一块256×24 位的静态 RAM 区,每个像素由 R、G、B 每种颜色 8 位数据组成,程序包括两块这样的颜色查找表,一共 512×24 位。
• 寄存器 包括整个程序需要的各种控制、状态寄存器。
• 颜色处理器 用于将接收到的像素数据转换成 RGB 颜色信息。
• 光标处理器 用于将保存的光标信息转换成可见的光标。
• 输出 FIFO 用于保证连续的数据流输出到 VGA 或者 LCD 显示器上。
• 视频定时产生器 用于产生显示需要的各种同步信号,如场同步、行同步、复合同步信号等。
三、VGA/LCD 显示控制器程序的实现
3.1 顶层程序
顶层程序需要连接并控制各个子模块,顶层vga_top模块代码如下:
3.2 颜色查找表–Color Lookup Table
颜色查找表保存了 256 色分辨率下 R、G、B 所有可能颜色,因此它是一块 256×24 位的静态 RAM 区,每个像素由 R、G、B 每种颜色 8 位数据组成,程序包括两块这样的颜色查找表,一共 512×24 位。
颜色查找表的主要代码如下:
代码中定义了一个通用的存储器,适用于 Altera、Xilinx 的 FPGA 产品。主要代码如下:
3.3 颜色处理器–Color Processor
颜色处理器负责每个像素的颜色的产生。这个功能由颜色处理器与输出 FIFO 共同完成,颜色处理器的内部结构如图 5 所示。
颜色处理器包括地址产生器、数据缓冲和色彩化模块几部分:
• 地址产生器 在产生视频存储器的地址的同时,地址产生器操作存储器块的切换并记载要读取的像素数目。当所有像素读取完成后,切换存储器的块位置。
• 数据缓冲 暂时保存从视频存储器中读取的数据,对数据的访问可以按照连续地址进行。所有的数据按照连续的地址保存。8 位模式下,一个 32 位的字保存 4 个像素的数据;16位模式下,一个 32 位的字保存 2 个像素;24 位模式下,一个 32 位的字保存 1 1/3 个像素;32 位模式下,一个 32 位的字保存 1 个像素。
• 色彩化模块 将保存在数据缓冲区中的数据转换成颜色数据,并输出。
颜色处理器的主要代码如下:
3.4 光标处理器–Cursor Processor
VGA/LCD 显示控制器同时提供了硬件光标,可以为 GUI(图形用户界面,Graphics UserInterface)提供一个箭头一样的光标,如图 6 所示。
图 6 光标处理器提供的光标
光标的形成由光标处理器(Cursor Processor)完成。程序为每个光标模板提供了 16kbit的空间,光标的分辨率可以选择,包括两种模板:
-
32×32 像素模式 在这种模板中,每个像素数据保存在 16 位字节中。 -
64×64 像素模式 在这种模板中,每个像素数据保存在 4 位字节中。
光标处理器的程序结构如图 7 所示。
当拷贝光标到光标数据缓冲区时,地址产生器产生进行写操作需要的存储器地址。光标数据缓冲器提供一块 512×32 位的 SRAM,用来保存光标的数据。光标处理器负责跟踪光标的位置,决定光标模板是否需要更新、光标是否需要显示等。
光标处理器的主要代码如下:
3.5 视频定时产生器–Video Timing Generator
视频定时产生器产生正确显示图像所必需的同步信号—水平同步信号、垂直同步信号。
1) 视频信号的水平同步信号
水平同步信号如图 8 所示。
Thsync 表示水平同步过程的时间,以像素节拍为单位进行测量。Thgdel 是水平门延迟时间,表示从同步结束到水平门信号开始之间的时间。Thgate 表示一条视频线可视区域内的时间。Thlen 表示整个水平同步的时间长度。
2) 视频信号的垂直同步信号
垂直同步信号如图 9 所示。
图 9 垂直同步信号
Tvsync 表示垂直同步过程的时间,以行节拍为单位进行测量。Tvgdel 是垂直门延迟时间,表示从同步结束到垂直门信号开始之间的时间。Tvgate 表示一场视频信号可视区域内的时间。Tvlen 表示整个水平同步的时间长度。
视频定时产生器的主要代码如下:
module vga_tgen(
clk, clk_ena, rst,
Thsync, Thgdel, Thgate, Thlen, Tvsync, Tvgdel, Tvgate, Tvlen,
eol, eof, gate, hsync, vsync, csync, blank
)
//输入输出
input clk;
input clk_ena;
input rst;
//水平定时设置输入信号
input [ 7:0] Thsync; // 水平同步信号宽度
input [ 7:0] Thgdel; // 水平同步门延迟
input [15:0] Thgate; // 水平门(每行视频信号可视像素的数目)
input [15:0] Thlen; // 水平同步信号的长度 (每行视频信号的像素数目)
// 垂直定时设置输入信号
input [ 7:0] Tvsync; // 垂直同步信号宽度
input [ 7:0] Tvgdel; // 垂直同步门研制
input [15:0] Tvgate; // 垂直门(每场视频信号可视像素的数目)
input [15:0] Tvlen; //垂直同步信号的长度 (每场视频信号的像素行数)
//输出
output eol; // 一行信号的结尾
output eof; // 一场图像的结尾
output gate; // 垂直和水平门信号
output hsync; // 水平同步信号
output vsync; // 垂直同步信号
output csync; // 复合同步信号
output blank; // 空白信号
// 变量申明
wire Hgate, Vgate;
wire Hdone;
//程序主体
// 连接水平定时产生器
vga_vtim hor_gen(
.clk(clk),
.ena(clk_ena),
.rst(rst),
.Tsync(Thsync),
.Tgdel(Thgdel),
.Tgate(Thgate),
.Tlen(Thlen),
.Sync(hsync),
.Gate(Hgate),
.Done(Hdone)
);
// 连接垂直定时产生器
wire vclk_ena = Hdone & clk_ena;
vga_vtim ver_gen(
.clk(clk),
.ena(vclk_ena),
.rst(rst),
.Tsync(Tvsync),
.Tgdel(Tvgdel),
.Tgate(Tvgate),
.Tlen(Tvlen),
.Sync(vsync),
.Gate(Vgate),
.Done(eof)
);
// 指定输出
assign eol = Hdone;
assign gate = Hgate & Vgate;
assign csync = hsync | vsync;
assign blank = ~gate;
endmodule
行同步和场同步信号产生的主要代码如下:
module vga_vtim(clk, ena, rst, Tsync, Tgdel, Tgate, Tlen, Sync, Gate, Done);
// 输入输出
input clk; //时钟信号
input ena; // 计数使能
input rst; // 同步复位信号,高有效
input [ 7:0] Tsync; // 同步时间
input [ 7:0] Tgdel; // 门延迟
input [15:0] Tgate; // 门信号的时间
input [15:0] Tlen; // 行时间/场时间
output Sync; // 输出的同步信号
output Gate; // 门信号
output Done; // 行/场的结束标志
reg Sync;
reg Gate;
reg Done;
// 程序主体
//产生定时状态机
reg [15:0] cnt, cnt_len;
wire [16:0] cnt_nxt, cnt_len_nxt;
wire cnt_done, cnt_len_done;
assign cnt_nxt = {1'b0, cnt} -17'h1;
assign cnt_done = cnt_nxt[16];
assign cnt_len_nxt = {1'b0, cnt_len} -17'h1;
assign cnt_len_done = cnt_len_nxt[16];
reg [4:0] state;
parameter [4:0] idle_state = 5'b00001;
parameter [4:0] sync_state = 5'b00010;
parameter [4:0] gdel_state = 5'b00100;
parameter [4:0] gate_state = 5'b01000;
parameter [4:0] len_state = 5'b10000;
always @(posedge clk)
//复位
if (rst)
begin
state <= #1 idle_state;
cnt <= #1 16'h0;
cnt_len <= #1 16'b0;
Sync <= #1 1'b0;
Gate <= #1 1'b0;
Done <= #1 1'b0;
end
else if (ena)
begin
cnt <= #1 cnt_nxt[15:0];
cnt_len <= #1 cnt_len_nxt[15:0];
Done <= #1 1'b0;
case (state)
//空闲状态
idle_state:
begin
state <= #1 sync_state;
cnt <= #1 Tsync;
cnt_len <= #1 Tlen;
Sync <= #1 1'b1;
end
//同步
sync_state:
if (cnt_done)
begin
state <= #1 gdel_state;
cnt <= #1 Tgdel;
Sync <= #1 1'b0;
end
//门延迟
gdel_state:
if (cnt_done)
begin
state <= #1 gate_state;
cnt <= #1 Tgate;
Gate <= #1 1'b1;
end
//门
gate_state:
if (cnt_done)
begin
state <= #1 len_state;
Gate <= #1 1'b0;
end
//总长度
len_state:
if (cnt_len_done)
begin
state <= #1 sync_state;
cnt <= #1 Tsync;
cnt_len <= #1 Tlen;
Sync <= #1 1'b1;
Done <= #1 1'b1;
end
endcase
end
endmodule
3.6 输出 FIFO
输出 FIFO 用于保证连续的数据流输出到 VGA 或者 LCD 显示器上。
输出 FIFO 的主要代码如下:
四、程序的仿真与测试
为了检验程序是否实现预先设定的功能,需要编写仿真程序。仿真程序的主要代码如下:
五、总结
本篇介绍了一个 VGA/LCD 显示控制器的实例。首先介绍了 VGA/LCD 显示的相关知识,然后介绍了程序的主要结构和主要功能模块的实现过程。最后用一个测试程序验证程序的功能是否满足要求。本章为各位大侠设计自己的 VGA/LCD 显示控制器提供了一个可以使用的方案。