VGA详解及色块边缘碰撞示例

引言 VGA:video Graphics array,视频图形阵列,阴极射线显像管(CRT)显示器时代产物,很多老显卡、笔记本电脑、投影仪所用接口,已经比较过时。
CRT是模拟设备,所以VGA也采用模拟协议,虽然现在很多液晶显示器仍有VGA接口,但是是内置了AD转换,将模拟信号转换为数字信号。
虽然VGA已经基本被DVI、HDMI、DP等接口替代,但无法否认其学习价值。
介绍 扫描方式分为逐行扫描和隔行扫描。
逐行扫描:左上方开始,左到右,上到下。扫完一行到下一行起始,CRT对电子束消隐;每行结束用行同步信号同步,全部结束用场同步信号同步,扫描回到屏幕左上方,同时场消隐。
隔行扫描:隔一行扫描,扫描完回来扫剩下的行(显示器闪烁严重,用眼疲劳)
消隐信号:针对老式显像管的成像扫描电路而言。电子枪所发出的电子束从屏幕的左上角开始向右扫描,一行扫完需将电子束从右边移回到左边以便扫描第二行。在移动期间就必须有一个信号加到电路上,使得电子束不能发出。不然这个回扫线会破坏屏幕图像的。这个阻止回扫线产生的信号就叫作消隐信号。
显示带宽:可处理的频率范围,60HZ,640X480分辨率,则带宽640X480X60=18.4MHZ(实际上大于这个值,因为648X480是表示显示有效区域,还有相当一部分是无效区域),详见下面时序部分。但这个带宽一般来使不用我们自己来计算,有VESA标准,具体可以查看http://tinyvga.com/vga-timing,或者移步https://download.csdn.net/download/AD7533/12561449下载Proposed VESA and Industry Standards and Guidelines for Computer Display Monitor Timing (DMT)文档,其中包含了几乎所有类型显示器的标准,作为手册使用,如下图。
VGA详解及色块边缘碰撞示例
文章图片


时序 信号:共5个,分别为:R、G、B三基色,HS(行同步),VS(场同步)。
HS信号:信号无效时(即不在有效显示区域)时,为高;信号有效时(即进入有效显示区域内),拉低;VS信号同理。如下图所示。
VGA详解及色块边缘碰撞示例
文章图片


当HS和VS信号同时有效(低电平),即可输出图像。
示例---利用FPGA和VGA实现方块碰撞 环境
1、vivado 2019.02,UE文本编辑器、Modelsim仿真环境
2、Micro phase zynq-7010开发板
3、TM043NDH02 LCD显示屏(开发板自带,有效480X272@60Hz,总525X286,有效区域为42~522、11~283)
思路
1、声明端口、变量及参数。

module vga_lcd( input clk_50M,//系统时钟 input rst_n,//复位 output clk_9M,//vga时钟 output vga_en,//vga数据有效信号,即行同步列同步都处于有效区 output disp_en,//vga显示开关 output reg vga_hs,//行同步 output reg vga_vs,//列同步 output reg[23:0]vga_rgb//三基色 ); parameterH_TOTAL = 525 - 1; //行计数总数 parameterH_SYNC = 41 - 1; //行数据无效计数值 parameterH_START = 43 - 1; //行数据开始有效计数值 parameterH_END = 523 - 1; //行数据结束有效计数值 parameterV_TOTAL = 286 - 1; //列计数总数 parameterV_SYNC = 10 - 1; //列数据无效计数值 parameterV_START = 12 - 1; //列数据开始有效计数值 parameterV_END = 284 - 1; //行数据结束有效计数值 parameterSQUARE_X=150; //方块行 parameterSQUARE_Y=150; //方块列 parameterSCREEN_X=480; //行有效区域大小 parameterSCREEN_Y=272; //列有效区域大小wire rst1; //时钟复位 wire locked; //时钟稳定 reg[10:0]cnt_x; reg[10:0]cnt_y; reg flag_x; //水平移动指示,0为右,1为左 reg flag_y; //垂直移动指示,0为下,1为上 reg [10:0]x; reg [10:0]y; assign rst1=~rst_n; //高电平复位 assign disp_en=1; //开


2、开发板PL端时钟为50MHz,利用PLL IP进行分频(480X272X60≈9MHz)。
clock instance_name(//9M clk .clk_out1(clk_9M), .reset(rst1), .locked(locked), .clk_in1(clk_50M) );

3、利用9MHz时钟分别对行(cnt_x)和列(cnt_y)计数。
always@(posedge clk_9M or negedge rst_n)begin//cnt_y计数 if(~rst_n)begin cnt_x<=0; end else if(cnt_x==H_TOTAL) begin cnt_x<=0; end else cnt_x<=cnt_x+1; end


4、根据计数值得到对应的行同步信号(vga_hs)和列(场)同步信号(vga_vs).
always@(posedge clk_9M or negedge rst_n)begin//行同步信号 if(~rst_n)begin vga_hs<=1; end else if(cnt_x==H_TOTAL)begin vga_hs<=1; end else if(cnt_x==H_SYNC) vga_hs<=0; else ga_hs<=vga_hs; end


5、根据vga_hs和vga_vs得到vgs_en使能信号。
assign vga_en=~(vga_vs||vga_hs); //信号有效使能

6、根据移动标志flag_x和flag_y,设置方块移动方向。
always@(posedge clk_9M or negedge rst_n)begin//方块左右移动 if(~rst_n)begin x<=0; end else if(flag_x==0&&cnt_x==H_TOTAL&&cnt_y==V_TOTAL)begin x<=x+1; end else if(flag_x==1&&cnt_x==H_TOTAL&&cnt_y==V_TOTAL)begin x<=x-1; end end


7、根据方块移动方向及大小,判断是否到达边缘并改变移动标志。
always@(posedge clk_9M or negedge rst_n)begin if(~rst_n)begin flag_x<=0; end else if(flag_x==0&&cnt_x==H_TOTAL&&cnt_y==V_TOTAL&&x==(H_END-H_START-SQUARE_X-1))begin flag_x<=1; end else if(flag_x==1&&cnt_x==H_TOTAL&&cnt_y==V_TOTAL&&x==1) begin flag_x<=0; end end


8、输出色块和背景。
always@(posedge clk_9M or negedge rst_n)begin if(~rst_n)begin vga_rgb<=0; end else if(vga_en==1&&cnt_x>=H_START+x&&cnt_x<=H_START+x+SQUARE_X&&cnt_y>=y+V_START&&cnt_y<=V_START+y+SQUARE_Y)begin ga_rgb<=24'hFFFFFF; end else if(vga_en==1)begin vga_rgb<=24'h000000; end end


总结 VGA的大概内容就这么多,写一个小东西大致就能掌握了。
本次示例中的很多参数都以parameter给出的,对于不同的显示屏只需查手册,在实例化时填入对应参数即可,在移植时很方便。
有什么错误之处还请指出。
源码自取:https://download.csdn.net/download/AD7533/12563311

【VGA详解及色块边缘碰撞示例】

    推荐阅读