基于FPGA的VGA控制器设计与验证

基于FPGA的VGA控制器设计与验证

关注微信公众号“FPGA科技室”,获取更多:
在这里插入图片描述

1.VGA标准介绍

计算机的显示器有很多标准,常见的有VGA,SVGA等,在现在,大部分台式机计算机的显示屏都采用VGA接口,VGA的应用之广,那么本文我们就用VGA接口来控制显示器,VGA是video graphics adapter的缩写,即为视频图形阵列,VGA接口使用15针的DB15接口,下面列举该接口引脚的功能:
在这里插入图片描述
VGA扫描方式

VGA标准中,常见的彩色显示器一般由CRT构成,色彩由RGB三基色构成,显示是用逐行扫描的方式解决,阴极射线发射电子束打到涂有荧光粉的显示屏上,这样就产生了RGB三色,合成一个彩色像素,扫描从屏幕左上方开始,从左到右,从上到下进行扫描,每扫完一行,电子束回到屏幕的左边下一行的起始位置,这个过程中,还要进行消隐操作. 每行结束时,用行同步信号进行行同步;扫描完所有行,用场同步信号进行场同步,并使扫描回到屏幕的左上方,同时进行场消隐,预备下一场的扫描。

对于普通的显示器,共有5个信号:RGB三基色信号,行同步信号HS,场同步信号vs,对于时序驱动,VGA显示器要严格遵循标准,即68048060hz模式。

VGA标准时序分析

下图是VGA行扫描,场扫描的时序图。

在这里插入图片描述
行扫描时序要求(单位:输出一个像素的时间间隔,即像素时钟):
Ta (行同步头):96
Tb :40
Tc :8
Td行图像:640
Te :8
Tf :8
Tg :800
场扫描时序要求(单位:输出一行line的时间间隔):
Ta场同步头 :2
Tb :25
Tc :8
Td场图像 :480
Te :8
Tf :2
Tg :525

VGA工业标准所要求的频率如下:时钟频率 25.175Mhz—>(像素输出的频率)行频率—> 31469hz 场频率 —>59.94hz->(每秒图像刷新频率)

在设计时,可用两个计数器进行计数(行,场扫描技数器),行计数器的驱动时钟为25Mhz,场计数器的驱动时钟为行计数器的溢出信号。计数器的同时控制行,场同步信号输出。并在适当的时候送出数据,就能显示相应的图像,显示器的刷新频率为25Mhz/800/525=59.52hz

本开发平台的开发板VGA模块采用的是GM7123芯片,GM7123芯片有3个10位的DAC通道的各高8位作为数据输入的端口,低两位舍弃。默认最高支持RGB888格式,24位色。该模块为开发用户提供了VGA_HS,VGA_VS,CLOCK,BLANK,R[7:0],B[7:0],G[7:0],GND信号,所以在设计VGA控制时应该正确连接这些信号。

控制器使用RGB888的数据模式和GM7123模块连接时,简易连接图如下所示:
在这里插入图片描述
使用此接口时,VGA接口三基色信号RGB使用24位数据线,则可以显示2^24种颜色。RGB数据格式如下表:
在这里插入图片描述
下表是常见的几种颜色对应的数据编码:
在这里插入图片描述
原理小结:

VGA驱动采用行列扫描方法,使用两个计数器分别进行行,场计数,根据计数值确定像素数据内容和行,场同步信号和电平状态。同时,要显示不同颜色,只要给D0-D24不同数据即可。

VGA控制器设计

  1. 行扫描计数器

行扫描计数器即每个像素时钟自动加1,只要加满到799,计数器清零重新计数:
在这里插入图片描述
在这里插入图片描述
2. 场扫描计数器

因为场扫描计数器是在每次一行扫描完成后加1,即场扫描计数器的自加条件是行扫描计数器溢出。即场扫描计数器自加条件为行扫描完成——>hcount_r = 10’d799 :
在这里插入图片描述
3. 行场同步信号

每一个完整的VGA帧都包含了数据段和消隐段,在消隐段期间,行同步信号和场同步信号有一段行同步头和场同步头。在同步期间,对应行同步信号或者场同步信号为低电平,所以可以根据行场计数器的值来确定行场同步信号的电平,行同步头为一行扫描的前96个像素时钟周期,则行同步信号设置为:
在这里插入图片描述
对于场同步信号,其场同步头为一行扫描的前2个像素时钟周期,则场同步信号设置为:
在这里插入图片描述
4. 数据输出

在行,场消隐期间,需要保证输出到VGA的RGB数据线上的数据全为0,因此可以设置一个二选一选择器,只有在非消隐阶段,VGA控制器才直接输出图像数据。

首先产生一个图像数据有效标志信号,然后使用标志信号控制VGA输出数据的内容。
在这里插入图片描述
dat_act为图像数据有效标志信号

消隐输出0的选择器:
在这里插入图片描述
5. 输出行列扫描位置

将VGA控制器的实时位置输出:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

module VGA_CTRL(
	Clk25M,	//系统输入时钟25MHZ
	Rst_n,	//复位输入,低电平复位
	data_in,	//待显示数据
	hcount,		//VGA行扫描计数器
	vcount,		//VGA场扫描计数器
	VGA_RGB,	//VGA数据输出
	VGA_HS,		//VGA行同步信号
	VGA_VS		//VGA场同步信号
);
			
	//----------------模块输入端口----------------
	input  Clk25M;          //系统输入时钟25MHZ
	input  Rst_n;
	input  [7:0]data_in;     //待显示数据

	//----------------模块输出端口----------------
	output [9:0]hcount;
	output [9:0]vcount;
	output [7:0]VGA_RGB;  //VGA数据输出
	output VGA_HS;           //VGA行同步信号
	output VGA_VS;           //VGA场同步信号

	//----------------内部寄存器定义----------------
	reg [9:0] hcount_r;     //VGA行扫描计数器
	reg [9:0] vcount_r;     //VGA场扫描计数器
	//----------------内部连线定义----------------
	wire hcount_ov;
	wire vcount_ov;
	wire dat_act;//有效显示区标定

	//VGA行、场扫描时序参数表
	parameter VGA_HS_end=10'd95,
				 hdat_begin=10'd143,
				 hdat_end=10'd783,
				 hpixel_end=10'd799,
				 VGA_VS_end=10'd1,
				 vdat_begin=10'd34,
				 vdat_end=10'd514,
				 vline_end=10'd524;

	assign hcount=hcount_r-hdat_begin;
	assign vcount=vcount_r-vdat_begin;

	//**********************VGA驱动部分**********************
	//行扫描
	always@(posedge Clk25M or negedge Rst_n)
	if(!Rst_n)
		hcount_r<=10'd0;
	else if(hcount_ov)
		hcount_r<=10'd0;
	else
		hcount_r<=hcount_r+10'd1;

	assign hcount_ov=(hcount_r==hpixel_end);

	//场扫描
	always@(posedge Clk25M or negedge Rst_n)
	if(!Rst_n)
		vcount_r<=10'd0;
	else if(hcount_ov) begin
		if(vcount_ov)
			vcount_r<=10'd0;
		else
			vcount_r<=vcount_r+10'd1;
	end
	else 
		vcount_r<=vcount_r;
		
	assign 	vcount_ov=(vcount_r==vline_end);

	//数据、同步信号输出
	assign dat_act=((hcount_r>=hdat_begin)&&(hcount_r<hdat_end))
					&&((vcount_r>=vdat_begin)&&(vcount_r<vdat_end));
					
	assign VGA_HS=(hcount_r>VGA_HS_end);
	assign VGA_VS=(vcount_r>VGA_VS_end);
	assign VGA_RGB=(dat_act)?data_in:8'h00;
		
endmodule 

VGA控制器仿真验证

对应testbench只要产生一个25Mhz的时钟信号,在data_in端口上给一个固定的数据编码。

`timescale 1ns/1ns

`define clk_period 40

module VGA_CTRL_tb;

//----------------模块输入端口----------------

reg  Clk25M;          //系统输入时钟25MHZ

reg  Rst_n;

reg  [7:0]data_in;     //待显示数据

//----------------模块输出端口----------------

wire [9:0]hcount;

wire [9:0]vcount;

wire [7:0]VGA_RGB;  //VGA数据输出

wire VGA_HS;           //VGA行同步信号

wire VGA_VS;           //VGA场同步信号



reg [11:0]V_cnt = 0;//扫描行数统计计数器

 

VGA_CTRL VGA_CTRL(

.Clk25M(Clk25M),//系统输入时钟25MHZ

.Rst_n(Rst_n),

.data_in(data_in),//待显示数据

.hcount(hcount),//VGA行扫描计数器

.vcount(vcount),//VGA场扫描计数器

.VGA_RGB(VGA_RGB),//VGA数据输出

.VGA_HS(VGA_HS),//VGA行同步信号

.VGA_VS(VGA_VS)//VGA场同步信号

);



initial Clk25M = 0;

always #(`clk_period/2) Clk25M = ~Clk25M;



initial begin

Rst_n = 0;

data_in = 8'd0;

#(`clk_period *20 +1);

Rst_n = 1;

data_in = 8'hff;

end



initial begin

wait(V_cnt == 3);//等待扫描2帧后结束仿真

$stop;

end



always @(posedge VGA_VS)//统计总扫描帧数

V_cnt <= V_cnt + 1'b1;



endmodule


至此,VGA控制器设计就完成了,编写顶层文件,就可以在VGA上显示图案了。
在这里插入图片描述
关注微信公众号“FPGA科技室”,获取更多内容:
在这里插入图片描述

原创文章 10 获赞 12 访问量 4761

猜你喜欢

转载自blog.csdn.net/weixin_42747385/article/details/89636343