基于FPGA的VGA/LCD显示控制器设计 附代码-FPGA CPLD资料源码分享社区-FPGA CPLD-ChipDebug

基于FPGA的VGA/LCD显示控制器设计 附代码

该帖子部分内容已隐藏
付费阅读
3积分
此内容为付费阅读,请付费后查看

导读

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 所示。

图片[1]-基于FPGA的VGA/LCD显示控制器设计 附代码-FPGA CPLD资料源码分享社区-FPGA CPLD-ChipDebug

图 1 CRT 显示器连接示意图

VGA 显示控制器控制 CRT 显示图像的过程如图 2 所示。

图片[2]-基于FPGA的VGA/LCD显示控制器设计 附代码-FPGA CPLD资料源码分享社区-FPGA CPLD-ChipDebug

图 2 VGA 显示控制器控制 CRT 显示器的框图

电子枪的扫描过程在行同步、场同步等控制信号的控制下进行,包括水平扫描、水平回扫、垂直扫描、垂直回扫等过程,如图 3 所示。

图片[3]-基于FPGA的VGA/LCD显示控制器设计 附代码-FPGA CPLD资料源码分享社区-FPGA CPLD-ChipDebug
图 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 的支持,适用于嵌入式系统的开发。

图片[4]-基于FPGA的VGA/LCD显示控制器设计 附代码-FPGA CPLD资料源码分享社区-FPGA CPLD-ChipDebug

图 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 所示。

图片[5]-基于FPGA的VGA/LCD显示控制器设计 附代码-FPGA CPLD资料源码分享社区-FPGA CPLD-ChipDebug

图 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]-基于FPGA的VGA/LCD显示控制器设计 附代码-FPGA CPLD资料源码分享社区-FPGA CPLD-ChipDebug

图 6 光标处理器提供的光标

光标的形成由光标处理器(Cursor Processor)完成。程序为每个光标模板提供了 16kbit的空间,光标的分辨率可以选择,包括两种模板:

  • 32×32 像素模式 在这种模板中,每个像素数据保存在 16 位字节中。
  • 64×64 像素模式 在这种模板中,每个像素数据保存在 4 位字节中。

光标处理器的程序结构如图 7 所示。

图片[7]-基于FPGA的VGA/LCD显示控制器设计 附代码-FPGA CPLD资料源码分享社区-FPGA CPLD-ChipDebug
图 7 光标处理器的程序结构
 

当拷贝光标到光标数据缓冲区时,地址产生器产生进行写操作需要的存储器地址。光标数据缓冲器提供一块 512×32 位的 SRAM,用来保存光标的数据。光标处理器负责跟踪光标的位置,决定光标模板是否需要更新、光标是否需要显示等。

光标处理器的主要代码如下:

3.5 视频定时产生器–Video Timing Generator

视频定时产生器产生正确显示图像所必需的同步信号—水平同步信号、垂直同步信号。

1) 视频信号的水平同步信号

水平同步信号如图 8 所示。

图片[8]-基于FPGA的VGA/LCD显示控制器设计 附代码-FPGA CPLD资料源码分享社区-FPGA CPLD-ChipDebug

图 8 水平同步信号

Thsync 表示水平同步过程的时间,以像素节拍为单位进行测量。Thgdel 是水平门延迟时间,表示从同步结束到水平门信号开始之间的时间。Thgate 表示一条视频线可视区域内的时间。Thlen 表示整个水平同步的时间长度。

2) 视频信号的垂直同步信号

垂直同步信号如图 9 所示。

图片[9]-基于FPGA的VGA/LCD显示控制器设计 附代码-FPGA CPLD资料源码分享社区-FPGA CPLD-ChipDebug

图 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 显示控制器提供了一个可以使用的方案。

请登录后发表评论