VGA显示驱动设计

VGA(Video Graphics Array接口是IBM制定的一种视频数据的传输标准,一种电脑显示器的典型接 口。VGA接口输出的是模拟图像。传统CRT显示器使用的是VGA接口,现在也有不少的液晶显示器或投 影仪也支持VGA接口。

##1. VGA接口外观和引脚

VGA接口是15pin的梯形插头,分成三排,每排五个,接口信号主要有五个:

  • R(Red)
  • G(Green)
  • B(Blue)
  • HS(Horizontal Synchronization)
  • VS(Vertical Synchronization)
    Note:VS和HS又称为帧同步(场同步)和行同步

2. VGA工作原理

图像的显示是以像素点为单位,标准的VGA分辨率是640x480,也有更高的分辨率如1024x768、1280x1024、1920x1200等,VGA显示器的一般刷新率为60Hz。每一帧图像的显示都是从屏幕左上角开始一行一行进行,行同步信号是一个负脉冲,行同步信号有效后,由RGB端输出到当前行显示各像素点的RGB电压值,当一帧显示结束后,由帧同步信号发送一个负脉冲,重新开始从屏幕的左上角开始显示下一帧图像。

image-20220712194620746

由于CRT显示器是靠电子管发射的电子显示信息,因此CRT的电子束从一行的行尾到下一行的行头需要时间、电子束从屏幕的右下角回到左上角开始下一帧也需要时间。这些时间成为电子束的行消隐时间和场消隐时间,行消隐时间以像素为单位,帧消隐时间以行为单位;电子束处于消隐时间时,RGB端输出的电压为0,屏幕此时显示的是黑色。 VGA行扫描、场扫描时序示意图如下:

image-20220712194652584

由上图可知,在标准的 640×480 的VGA上有效地显示一行信号需要96+48+640+16=800个像素点的时间,其中行同步负脉冲宽度为96个像素点时间,行消隐后沿需要48个像素点时间,然后每行显示640个像素点,最后行消隐前沿需要16个像素点的时间。所以一行中显示像素的时间为640个像素点时间,一行消隐时间为160个像素点时间。在标准的 640×480 的VGA上有效显示一帧图像需 2+33+480+10=525行时间,其中场同步负脉冲宽度为2个行显示时间,场消隐后沿需要33个行显示时间,然后每场显示480行,场消隐前沿需要10个行显示时间,一帧显示时间为525行显示时间,一帧消隐时间为45行显示时间。因此,在 640×480 的VGA上的一幅图像需要 525×800=420k 个像素点的时间。而每秒扫描60帧共需要约25M个像素点的时间。

2.1 不同分辨率下的VGA参数:

以分辨率1280*1024、60 FPS为例,此分辨率下的时钟频率

image-20220712195234933

##3. VGA显示的实现

VGA DAC ADV7123芯片完成数字信号到VGA模拟信号的转换,该芯片是三路高速、10bit输入的视频DA转换器,最大采样速度330M Hz(330 MSPS:330 Million Samples per Second),与多种高精度的显示系统兼容,可以广泛应用于HDTV、数字视频系统(1600*1200@100Hz)、高分辨率彩色图像处理、视频信号再现等。FPGA和ADV7123芯片之间的接口引脚包括3组 8bit 的颜色信号;

3.1 ADV7123 芯片

image-20220712194816678

主要引脚功能描述:

芯片与FPGA连接参考:

image-20220712194924198

FPGA开发板和ADV7123芯片之间的接口引脚包括3组8bit的颜色信号VGA_R[7:0], VGA_G[7:0],VGA_B[7:0],行同步信号VGA_HS,帧同步信号VGA_VS,VGA时钟信号VGA_CLK,VGA同步(低有效)VGA_SYNC_N, 和VGA消隐信号(低有效)VGA_BLANK_N

Verilog实现VGA显示:

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
module vga_ctrl(
input pclk, //25MHz时钟
input reset, //置位
input [23:0] vga_data, //上层模块提供的VGA颜色数据
output [9:0] h_addr, //提供给上层模块的当前扫描像素点坐标
output [9:0] v_addr,
output hsync, //行同步和列同步信号
output vsync,
output valid, //消隐信号
output [7:0] vga_r, //红绿蓝颜色信号
output [7:0] vga_g,
output [7:0] vga_b
);

//640x480分辨率下的VGA参数设置
parameter h_frontporch = 96;
parameter h_active = 144;
parameter h_backporch = 784;
parameter h_total = 800;

parameter v_frontporch = 2;
parameter v_active = 35;
parameter v_backporch = 515;
parameter v_total = 525;

//像素计数值
reg [9:0] x_cnt;
reg [9:0] y_cnt;
wire h_valid;
wire v_valid;

always @(posedge reset or posedge pclk) //行像素计数
if (reset == 1'b1)
x_cnt <= 1;
else
begin
if (x_cnt == h_total)
x_cnt <= 1;
else
x_cnt <= x_cnt + 10'd1;
end

always @(posedge pclk) //列像素计数
if (reset == 1'b1)
y_cnt <= 1;
else
begin
if (y_cnt == v_total & x_cnt == h_total)
y_cnt <= 1;
else if (x_cnt == h_total)
y_cnt <= y_cnt + 10'd1;
end
//生成同步信号
assign hsync = (x_cnt > h_frontporch);
assign vsync = (y_cnt > v_frontporch);
//生成消隐信号
assign h_valid = (x_cnt > h_active) & (x_cnt <= h_backporch);
assign v_valid = (y_cnt > v_active) & (y_cnt <= v_backporch);
assign valid = h_valid & v_valid;
//计算当前有效像素坐标
assign h_addr = h_valid ? (x_cnt - 10'd145) : {10{1'b0}};
assign v_addr = v_valid ? (y_cnt - 10'd36) : {10{1'b0}};
//设置输出的颜色值
assign vga_r = vga_data[23:16];
assign vga_g = vga_data[15:8];
assign vga_b = vga_data[7:0];
endmodule
0%