1、介绍
VGA全称是Video Graphics Array,即视频图形阵列,是模拟信号的一种视频传输标准。VGA就是如今很多显示器上连接主机的信号传输接口,有三排15个引脚,其中比较重要的是3根RGB彩色分量信号和2根扫描同步信号HSYNC和VSYNC针,其引脚编号图如下所示:
引脚 |
定义 | 引脚 | 定义 |
1 | 红基色(RED) | 9 | 保留(各厂家定义不同) |
2 | 绿基色(GREEN) | 10 | 数字地(GND) |
3 | 蓝基色(BLUE) | 11 | 地址码0(ID BIT0) |
4 | 地址码2(ID BIT2) | 12 | 地址码1(ID BIT1) |
5 | 自测试(各厂家定义不同) | 13 | 行同步(HSYNC) |
6 | 红色地(RGND) | 14 | 场同步(VSYNC) |
7 | 绿色地(GGND) | 15 | 地址码3(ID BIT3) |
8 | 蓝色地(BGND) |
显示器的扫描方式:逐行扫描是扫描从屏幕左上角一点开始,从左像右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,CRT对电子束进行消隐,每行结束时,用行同步信号进行同步;当扫描完所有的行,形成一帧,用场同步信号进行场同步,并使扫描回到屏幕左上方,同时进行场消隐,开始下一帧。
VGA 的行时序是以像素为单位的,场时序是以行为单位的。VGA时序对同步时间、显示后沿时间、视频有效时间和显示前沿时间有特定要求,常用VGA 分辨率时序参数如下表所示。(a行同步脉冲,b行显示后沿,c行显示时序段,d行显示后沿,e行总时序,场时序类同)
行扫描周期 * 场扫描周期 * 刷新频率 = 时钟频率
我们一般使用的屏幕分辨率大小是640*480,也包括我们数逻实验室的板子。分辨率可以理解为像素点的个数,640*480的规格就是显示屏幕上每行有640个像素点,总共有480行。注意,一件很重要的事情是,虽然你看到的屏幕大小是640*480的,但是它的实际大小并不只有那么点,形象一点就是说,VGA扫描的范围是包含了你能够看到的640*480这一块区域的更大区域,他会在周围一圈你看不到的区域部分进行扫描,因此,我们在处理扫描信号的时候一定要注意只有扫描到有效区域的时候才能把像素点数据传给VGA显示。
VGA时序标准图
图中的红色区域表示在一个完整的行扫描周期中,Video图像信息只在此区域有效,黄色区域表示在一个完整的场扫描周期中,Video图像信息只在此区域有效,两者相交的橙色区域,就是VGA图像的最终显示区域。
2、VGA显示器驱动设计与验证
因为vga的每个显示模式下的时钟频率都不一样,在使用的时候我们需要生成相应的时钟频率,这里我们以640x480@60为例,它的时钟频率为25.175MHZ,这边可以使用两种方式来生成时钟频率,一是调用ip核,二是编写分频的rtl代码。这里选择第一种,我的系统时钟频率为50MHZ,调用ip核产生25MHZ。
系统RTL视图如下:
① 顶层代码
module vga_colorbar
(
input wire sys_clk , //输入工作时钟,频率50MHz
input wire sys_rst_n , //输入复位信号,低电平有效
output wire hsync , //输出行同步信号
output wire vsync , //输出场同步信号
output wire [15:0] rgb_rgb //输出像素信息
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//wire define
wire vga_clk ; //VGA工作时钟,频率25MHz
wire locked ; //PLL locked信号
wire rst_n ; //VGA模块复位信号
wire [9:0] pix_x ; //VGA有效显示区域X轴坐标
wire [9:0] pix_y ; //VGA有效显示区域Y轴坐标
wire [15:0] pix_data; //VGA像素点色彩信息
//rst_n:VGA模块复位信号
assign rst_n = (sys_rst_n & locked);
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------- clk_gen_inst -------------
clk_gen clk_gen_inst
(
.areset (~sys_rst_n), //输入复位信号,高电平有效,1bit
.inclk0 (sys_clk), //输入50MHz晶振时钟,1bit
.c0 (vga_clk), //输出VGA工作时钟,频率25Mhz,1bit
.locked (locked) //输出pll locked信号,1bit
);
//------------- vga_ctrl_inst -------------
vga_ctrl vga_ctrl_inst
(
.vga_clk (vga_clk ), //输入工作时钟,频率25MHz,1bit
.sys_rst_n (rst_n ), //输入复位信号,低电平有效,1bit
.pix_data (pix_data), //输入像素点色彩信息,16bit
.pix_x (pix_x), //输出VGA有效显示区域像素点X轴坐标,10bit
.pix_y (pix_y), //输出VGA有效显示区域像素点Y轴坐标,10bit
.hsync (hsync), //输出行同步信号,1bit
.vsync (vsync), //输出场同步信号,1bit
.vga_rgb (vga_rgb) //输出像素点色彩信息,16bit
);
//------------- vga_pic_inst -------------
vga_pic vga_pic_inst
(
.vga_clk (vga_clk), //输入工作时钟,频率25MHz,1bit
.sys_rst_n (rst_n), //输入复位信号,低电平有效,1bit
.pix_x (pix_x), //输入VGA有效显示区域像素点X轴坐标,10bit
.pix_y (pix_y), //输入VGA有效显示区域像素点Y轴坐标,10bit
.pix_data (pix_data) //输出像素点色彩信息,16bit
);
endmodule
② VGA控制器
module vga_ctrl
(
input wire vga_clk, //输入工作时钟,频率25MHz
input wire sys_rst_n,
input wire [15:0]pix_data,
output wire [9:0]pix_x,
output wire [9:0]pix_y,
output wire hsync,
output wire vsync,
output wire [15:0]vga_rgb
);
parameter H_SYNC = 10'd96,
H_BACK = 10'd40,
H_LEFT = 10'd8,
H_VALLD = 10'd640,
H_RIGHT = 10'd8,
H_FRONT = 10'd8,
H_TOTAL = 10'd800;
parameter V_SYNC = 10'd2,
V_BACK =10'd25,
V_TOP =10'd8,
V_VALLD = 10'd480,
V_BOTTOM = 10'd8,
V_FRONT = 10'd2,
V_TOTAL = 10'd525;
reg [9:0] cnt_h;//行同步信号计数器
reg [9:0] cnt_v;//场同步信号计数器
wire pix_data_req;//像素点色彩信息请求信号
wire rgb_valid;//VGA有效显示区域
//cnt_h:行同步信号计数器
always @(posedge vga_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt_h <= 10'd0;
else if(cnt_h == H_TOTAL - 1'b1)
cnt_h <= 10'd0;
else
cnt_h <= cnt_h + 1'b1;
//cnt_v:场同步信号计数器
always @(posedge vga_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt_v <= 10'd0;
else if((cnt_v == V_TOTAL - 1'b1)&&(cnt_h == H_TOTAL - 1'b1))
cnt_v <= 10'd0;
else if (cnt_h == H_TOTAL - 1'b1)
cnt_v <= cnt_v + 1'b1;
else
cnt_v <= cnt_v;
//rgb_valid:VGA有效显示区域
assign rgb_valid = ((cnt_h >= H_SYNC + H_BACK + H_LEFT)
&& (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALLD)
&& (cnt_v >= V_SYNC + V_BACK + V_TOP)
&& (cnt_v < V_SYNC + V_BACK + V_TOP + V_TOTAL))
? 1'b1 : 1'b0;
//pix_data_req:像素点色彩信息请求信号,超前rgb_valid信号一个时钟周期
assign pix_data_req = ((cnt_h >= H_SYNC + H_BACK + H_LEFT - 1'b1)
&& (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALLD - 1'b1)
&& (cnt_v >= V_SYNC + V_BACK + V_TOP)
&& (cnt_v < V_SYNC + V_BACK + V_TOP + V_TOTAL))
? 1'b1 : 1'b0;
//pix_x,pix_y:VGA有效显示区域像素点坐标
assign pix_x = (rgb_valid == 1'b1) ? (cnt_h - (H_SYNC + H_BACK + H_LEFT)) : 10'd0;
assign pix_y = (rgb_valid == 1'b1) ? (cnt_v - (V_SYNC + V_BACK + V_TOP)) : 10'd0;
assign hsync = (cnt_h <= H_SYNC - 1'b1) ? 1'b1 : 1'b0;
assign vsync = (cnt_v <= V_SYNC - 1'b1) ? 1'b1 : 1'b0;
assign vga_rgb = (rgb_valid == 1'b1) ? pix_data : 16'h0000;
endmodule
注:.为什么要将(pix_x,pix_y)=(0,0)提前一个时钟周期?
显示数据产生,会滞后坐标(0,0)一个vga_clk,所以要把坐标(0,0)的出现提前一个vga_clk,修改后,vga_pic模块中产生显示数据,pix_data则可直接使用时序逻辑always语句,并且实际输出至vga显示器的同步信号h/vsync的产生只与cnt_h/v有关,所以使pix_x,y=(0,0)对模块输出的场同步没有影响,而rgb因pix的修改变正确文章来源:https://www.toymoban.com/news/detail-501720.html
pix_data_req:像素点色彩信息请求信号,超前 rgb_valid 信号一个时钟周期,从而使(pix_x,pix_y)=(0,0)提前一个时钟周期。减1使(pix_x,pix_y)=(0,0)提前一个时钟周期场坐标无需减一,若场减一则相当于提前 H_TOTAL 个时钟周期文章来源地址https://www.toymoban.com/news/detail-501720.html
③ VGA图像生成模块
module vga_pic
(
input wire vga_clk,
input wire sys_rst_n,
input wire [9:0]pix_x,
input wire [9:0]pix_y,
output reg [15:0]pix_data
);
parameter H_VALID = 10'd640,
V_VALID = 10'd480;
parameter RED = 16'hF800,
ORANGE = 16'hFC00,
YELLOW = 16'hFFE0,
GREEN = 16'h07E0,
CYAN = 16'h07FF,
BLUE = 16'h001F,
PURPPLE = 16'hF81F,
BLACK = 16'h0000,
WHITE = 16'hFFFF,
GRAY = 16'hD69A;
always @(posedge vga_clk or negedge sys_rst_n)
if(!sys_rst_n)
pix_data <= BLACK;
else if((pix_x >= 0) && (pix_x < (H_VALID/10)*1))
pix_data <= RED;
else if((pix_x >= (H_VALID/10)*1) && (pix_x < (H_VALID/10)*2))
pix_data <= ORANGE;
else if((pix_x >= (H_VALID/10)*2) && (pix_x < (H_VALID/10)*3))
pix_data <= YELLOW;
else if((pix_x >= (H_VALID/10)*3) && (pix_x < (H_VALID/10)*4))
pix_data <= GREEN;
else if((pix_x >= (H_VALID/10)*4) && (pix_x < (H_VALID/10)*5))
pix_data <= CYAN;
else if((pix_x >= (H_VALID/10)*5) && (pix_x < (H_VALID/10)*6))
pix_data <= BLUE;
else if((pix_x >= (H_VALID/10)*6) && (pix_x < (H_VALID/10)*7))
pix_data <= PURPPLE;
else if((pix_x >= (H_VALID/10)*7) && (pix_x < (H_VALID/10)*8))
pix_data <= BLACK;
else if((pix_x >= (H_VALID/10)*8) && (pix_x < (H_VALID/10)*9))
pix_data <= WHITE;
else if((pix_x >= (H_VALID/10)*9) && (pix_x < H_VALID))
pix_data <= GRAY;
else
pix_data <= BLACK;
endmodule
④ testbench文件
`timescale 1ns/1ns
module tb_vga_colorbar();
reg sys_clk;
reg sys_rst_n;
wire hsync;
wire vsync;
wire [15:0]vga_rgb;
initial
begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
always #10 sys_clk = ~sys_clk;
vga_colorbar vga_colorbar_inst
(
.sys_clk(sys_clk) , //输入工作时钟,频率50MHz
.sys_rst_n(sys_rst_n) , //输入复位信号,低电平有效
.hsync(hsync) , //输出行同步信号
.vsync(vsync) , //输出场同步信号
.rgb_rgb(rgb_rgb) //输出像素信息
);
endmodule
到了这里,关于VGA显示器驱动设计与验证的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!