VGA显示器驱动设计与验证

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的修改变正确

        pix_data_req:像素点色彩信息请求信号,超前 rgb_valid 信号一个时钟周期,从而使(pix_x,pix_y)=(0,0)提前一个时钟周期。减1使(pix_x,pix_y)=(0,0)提前一个时钟周期场坐标无需减一,若场减一则相当于提前 H_TOTAL 个时钟周期

 ③ 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发光中请勿扰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值