FPGA零基础学习之Vivado-VGA驱动设计

作者:李西锐,来源:FPGA技术江湖

VGA(Video Graphics Array)视频图形阵列是IBM于1987年提出的一个使用模拟信号的电脑显示标准。VGA接口即电脑采用VGA标准输出数据的专用接口。VGA接口共有15针,分成3排,每排5个孔,显卡上应用最为广泛的接口类型,绝大多数显卡都带有此种接口。它传输红、绿、蓝模拟信号以及同步信号(水平和垂直信号)。

VGA作为视频接口,具有分辨率高、显示速度快、颜色丰富等优点。随着电子产品以及视频图像处理技术的发展,VGA接口应用越来越广泛。

首先我们先来看一下VGA接口,如下图:

在我们的接口中,有很多针脚,我们在驱动之前,首先要了解每一个针脚的作用。接口原理图如下:

如图,我们可以看出在这15个针脚中,只有5个针脚需要我们去驱动,其他的针脚要么是电源或者地,要么就没有接。所以,在我们驱动时,只需要驱动这5个针脚即可。

首先我们在驱动之前,需要了解一下视频显示的扫描方式。平时大家看到的图片是由一个一个的像素点构成的,显示器显示时也是如此,一个点一个点的显示。在扫描显示时,有两种扫描方式:隔行扫描和逐行扫描。第一种扫描方式控制复杂,而且图像闪烁,人眼易疲劳,所以现在很少使用,基本上主流的扫描方式都是逐行扫描。逐行扫描是从左上角第一个点开始一行一行的进行扫描,直至最后一个点。在扫描时就需要我们确定扫描位置然后进行时序约束。vga_hs和vga_vs这两个信号为行列同步信号,用来同步扫描的。在时序上,要求在a段必须为低电平。

行时序每拉低一次即为一行的开始,场时序每拉低一次即为一帧图片的开始。

另外,在了解完扫描的问题之后,还有一个问题需要解决,那就是我们在扫描到显示区域时,要给出颜色数据,使得屏幕显示出我们想看到的颜色。VGA 显示器上每一个像素点可以很多种颜色,由R、G、B 三种颜色构成。如果每个像素点采用3 位二进制数表示,即R 用1bit 表示,G 用1bit 表示,B 用1bit 表示,则此像素点一共可以显示8种颜色;如果每个像素点采用8 位二进制数表示,即R 用3bit 表示,G 用3bit 表示,B 用2bit 表示,则此像素点一共可以显示256 种颜色。此次实验,采用RGB332 的进行表示。

在进行扫描时,不同的分辨率对应不同的扫描时钟,下图为各个常用分辨率的时序参数。

此次实验,我们选择分辨率为640*480,那么我们需要提供一个25Mhz的时钟,这个时钟我们可以通过锁相环输出,代码如下:

1 module vga_ctrl (
2
3 input wire clk,
4 input wire rst_n,
5
6 output reg vga_hs,
7 output reg vga_vs,
8 output reg [7:0] vga_rgb
9 );
10
11 parameter HS_A = 96;
12 parameter HS_B = 48;
13 parameter HS_C = 640;
14 parameter HS_D = 16;
15 parameter HS_E = 800;
16
17 parameter VS_A = 2;
18 parameter VS_B = 33;
19 parameter VS_C = 480;
20 parameter VS_D = 10;
21 parameter VS_E = 525;
22
23 reg [9:0] cnt_hs;
24 reg [9:0] cnt_vs;
25 wire hs_en;
26 wire vs_en;
27
28 always @ (posedge clk, negedge rst_n) begin
29 if (rst_n == 1'b0)
30 cnt_hs <= 10'd0;
31 else
32 if (cnt_hs < HS_E - 1'b1)
33 cnt_hs <= cnt_hs + 1'b1;
34 else
35 cnt_hs <= 10'd0;
36 end
37
38 always @ (posedge clk, negedge rst_n) begin
39 if (rst_n == 1'b0)
40 vga_hs <= 1'b1;
41 else
42 if (cnt_hs < HS_A)
43 vga_hs <= 1'b0;
44 else
45 vga_hs <= 1'b1;
46 end
47
48 always @ (posedge clk, negedge rst_n) begin
49 if (rst_n == 1'b0)
50 cnt_vs <= 10'd0;
51 else
52 if (cnt_hs == HS_E - 1'b1)
53 if (cnt_vs < VS_E - 1'b1)
54 cnt_vs <= cnt_vs + 1'b1;
55 else
56 cnt_vs <= 10'd0;
57 else
58 cnt_vs <= cnt_vs;
59 end
60
61 always @ (posedge clk, negedge rst_n) begin
62 if (rst_n == 1'b0)
63 vga_vs <= 1'b1;
64 else
65 if (cnt_vs < VS_A)
66 vga_vs <= 1'b0;
67 else
68 vga_vs <= 1'b1;
69 end
70
71 assign hs_en = (cnt_hs > HS_A + HS_B - 1'b1) && (cnt_hs < HS_A + HS_B + HS_C);
72 assign vs_en = (cnt_vs > VS_A + VS_B - 1'b1) && (cnt_vs < VS_A + VS_B + VS_C);
73
74 always @ (posedge clk, negedge rst_n) begin
75 if (rst_n == 1'b0)
76 vga_rgb <= 8'd0;
77 else
78 if (hs_en == 1'b1 && vs_en == 1'b1)
79 vga_rgb <= 8'b111_000_00;
80 else
81 vga_rgb <= 8'd0;
82 end
83
84 endmodule

以上代码为显示纯红色的驱动,如果我们想显示不同的纯色,可以修改代码79行的值。

在代码71行和72行分别规定了显示C区,也就是我们能够看到的最大显示区域。如果大家想画出不同形状或者位置的,可以在这两行约束出想要的区域。

最新文章

最新文章