一、 项目分析
用VGA显示全屏的红色,VGA(Video Graphics Array,视频图形阵列)是一种电脑显示标准。开发板采用至芯科技zx-1学习板,VGA视频显示接口是256色,颜色位深为8,RGB332的高三位是红色,中间3位是绿色,最低2位是蓝色,当vga_rgb=111_000_000时,显示全红。
1.1 原理分析
1.1.1 硬件电路原理
VGA的硬件电路原理如图1- 1所示,总共有15针接口,主要接口信号包括:颜色信号VGA_RGB[7:0],水平同步信号VGA_HS(列同步信号)和垂直同步信号VGA_VS(场同步信号,行同步信号)。
图1- 1 256色VGA接口
1.1.2 VGA扫描原理
本VGA采用逐行扫描的方式,逐行扫描是扫描从屏幕左上角一点开始,从左向右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,CRT 对电子束进行消隐,每行结束时,用行同步信号进行同步;当扫描完所有的行,形成一帧,用场同步信号进行场同步,并使扫描回到屏幕左上方,同时进行场消隐,开始下一帧。
完成一行扫描的时间为水平扫描时间,倒数为行频率;完成一帧的扫描时间为垂直扫描时间,倒数为场频率。基本上用场频率来表示显示屏的刷新频率。
1.1.3 显示时序和时钟频率
VGA显示时,需要考虑有效显示区域和无效显示区域,以640x480x60的显示标准为例,有效显示区域为640x480,无效显示区域包括行时序/场时序都需要同步脉冲(Sync a)、显示后沿(Back porch b)、显示时序段(Active Video Time c)和显示前沿(Front porch d),根据相应的显示标准,所以总的显示区域包括800x525,时钟频率的计算方法如下:VGA_CLK=800x525x60=25.175MHz。
VGA的行时序(列同步)和场时序(行同步)如图1- 2所示。不同VGA显示标准下的时钟频率和列同步等参数如图1- 3所示,列时序即为水平同步信号时序,行时序即为垂直同步(场同步)信号时序。
图1- 2 VGA列同步和场同步时序
图1- 3 VGA显示标准
1.2 顶层设计
图1- 4 顶层设计
端口说明:
clk:系统时钟50M
rst_n:复位,低电平有效
vga_rgb:颜色信号,高3位为红色,中间3位为绿色,低2位为蓝色
vga_hs:列同步信号,行同步
vga_vs:场同步信号,列同步
1.3 架构设计
图1- 5 VGA的架构
二、代码编写
1、顶层代码如下:
这个模块要注意的是根据显示标准,调用PLL生成相应的时钟频率。
module vga (
input wire clk,
input wire rst_n,
output wire [7:0] vga_rgb,
output wire vga_hs,
output wire vga_vs
);
wire clk_25m;
wire pll_locked;
pll pll_inst (
.areset ( ~rst_n ),
.inclk0 ( clk ),
.c0 ( clk_25m ),
.locked ( pll_locked)
);
vga_ctrl vga_ctrl_inst (
.clk (clk_25m ),
.rst_n (pll_locked ),
.vga_rgb (vga_rgb ),
.vga_hs (vga_hs ),
.vga_vs (vga_vs )
);
endmodule
2、vga_ctrl模块代码如下:
`define VGA_640x480x60 // choose different video standard,revise PLL clk ,alter cnt WIDTH
//`define VGA_680X480X75
//`define VGA_800X600X60
//`define VGA_800X600X75
//`define VGA_1024X768X60
//`define VGA_1024X768X75
//`define VGA_1280X1024X60
//`define VGA_1280X800X60
//`define VGA_1440X900X60
module vga_ctrl (
input wire clk,
input wire rst_n,
output reg [7:0] vga_rgb,
output reg vga_hs,
output reg vga_vs
);
//================ VGA_680X480X60 =========================================================
`ifdef VGA_640x480x60 // PLL clk = 25M = 640x480x60
localparam HS_A = 96; // synchronous pulse, horizontal
localparam HS_B = 48; // back porch pulse
localparam HS_C = 640; // display interval
localparam HS_D = 16; // Front porch
localparam HS_E = 800; // horizontal cycles
localparam VS_A = 2; // synchronous pulse, vertical
localparam VS_B = 33;
localparam VS_C = 480;
localparam VS_D = 10;
localparam VS_E = 525;
localparam HS_WIDTH = 10;
localparam VS_WIDTH = 10;
`endif
//================ VGA_800X600X60 =========================================================
//
//`ifdef VGA_800X600X60 // PLL clk = 40.0M
//
// localparam HS_A = 128;
// localparam HS_B = 88;
// localparam HS_C = 800;
// localparam HS_D = 40;
// localparam HS_E = 1056;
//
// localparam VS_A = 4;
// localparam VS_B = 23;
// localparam VS_C = 600;
// localparam VS_D = 1;
// localparam VS_E = 628;
//
// localparam HS_WIDTH = 11; // different resolution correspond to different couter width
// localparam VS_WIDTH = 10;
//
//`endif
//=====================================================================================================
reg [HS_WIDTH - 1:0] cnt_hs; // counter for horizontal synchronous signal
reg [VS_WIDTH - 1:0] cnt_vs; // counter for vertical synchrous signal
wire en_hs; // dsiplay horizontal enable
wire en_vs; // display vertical enable
wire en; // effective display zone
always @ (posedge clk, negedge rst_n)
if (!rst_n)
cnt_hs <= 0;
else
if (cnt_hs < HS_E - 1)
cnt_hs <= cnt_hs + 1'b1;
else
cnt_hs <= 0;
always @ (posedge clk, negedge rst_n)
if (!rst_n)
cnt_vs <= 0;
else
if (cnt_hs == HS_E - 1)
if (cnt_vs < VS_E - 1)
cnt_vs <= cnt_vs + 1'b1;
else
cnt_vs <= 0;
else
cnt_vs <= cnt_vs;
always @ (posedge clk, negedge rst_n)
if (!rst_n)
vga_hs <= 1'b1;
else
if (cnt_hs < HS_A - 1)
vga_hs <= 1'b0;
else
vga_hs <= 1'b1;
always @ (posedge clk, negedge rst_n)
if (!rst_n)
vga_vs <= 1'b1;
else
if (cnt_vs < VS_A - 1)
vga_vs <= 1'b0;
else
vga_vs <= 1'b1;
assign en_hs = (cnt_hs > HS_A + HS_B - 1) && (cnt_hs < HS_E - HS_D);
assign en_vs = (cnt_vs > VS_A + VS_B - 1) && (cnt_vs < VS_E - VS_D);
assign en = en_hs && en_vs;
always @ (posedge clk, negedge rst_n)
if (!rst_n)
vga_rgb <= 8'b000_000_00;
else
if (en)
vga_rgb <= 8'b111_000_00; // red
else
vga_rgb <= 8'b000_000_00;
endmodule
3、仿真测试模块代码如下:
因为显示器的一帧完整图像扫描完成大概需要16ms,所以只仿真前几行的垂直扫描波形。
`timescale 1ns/1ps
module vga_tb;
reg clk;
reg rst_n;
wire [7:0] vga_rgb;
wire vga_hs;
wire vga_vs;
vga vga_inst (
.clk (clk ),
.rst_n (rst_n ),
.vga_rgb (vga_rgb ),
.vga_hs (vga_hs ),
.vga_vs (vga_vs )
);
initial clk = 1;
always #10 clk = ~ clk;
initial
begin
rst_n = 0;
# 201
rst_n = 1;
repeat (11)
@ (posedge vga_hs);
# 200
$stop;
end
endmodule
四、个人总结
VGA学习需要弄明白的是两个同步信号:水平同步和垂直同步。网上的表达方式各不相同,需要读者自己细细品味。注意PLL时钟速率和不同显示标准之间的关系。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)