写在前面的话
可能大家觉得之前设计都是各种看波形,比较的单一、乏味。那么本节的内容,一定可以带给大家全新的感受,现代电子技术中,图像处理技术可谓是发展迅猛,其带给大家独特的视觉感受也总是那么的赏心悦目。这里,梦翼师兄和大家一起敲开图像世界的大门,让我们一起为之痴迷,为之陶醉。
什么是VGA?
VGA(Video Graphics Array,视频图形阵列),是 IBM 于1987年提出的一个使用类比讯号的电脑显示标准。这个标准已对于现今的个人电脑市场已经十分过 时。即使如此,VGA 仍然是很多制造商所共同支持的一个低标准,个人电脑在加载自己的独特驱动程式之前,都必须支持VGA 的标准。
VGA 支持在640X480的较高分辨率下同时显示16种色彩或256种灰度,同时在 320X240分辨率下可以同时显示256种颜色。
XGA (Extended Graphics Array,扩展图形阵列),是 IBM 于1990年发明的, XGA 较新的版本 XGA-2以真彩色提供800×600象素的分辨率或以65536种色彩提供1024×768象素的分辨率,这两种图像分辨水平可能是个人和小企业当今最常用的。
VGA接口
各引脚的功能:
开发板电路原理图如下:
由电路图可以看出,我们的VGA并没有特殊的外部芯片,也就是说,我们唯一要关注的可能就是它的显示原理和时序了,那么接下来我们具体来看一下VGA的扫描原理是什么。
8.7.4 VGA显示原理
8.7.4.1 扫描方式
VGA显示器扫描方式分为逐行扫描和隔行扫描:逐行扫描是从屏幕左上角第一个点开始,从左向右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,CRT 对电子束进行消隐,每行结束时,用行同步信号进行同步;当扫描完所有的行,形成一帧,用场同步信号进行场同步,并使扫描回到屏幕左上方,同时进行场消隐,开始下一帧。隔行扫描是指电子束扫描时每隔一行扫一线,扫完一屏后再返回来扫描剩下的线,隔行扫描的显示器闪烁快速,可能会使使用者眼睛疲劳(本实验采用逐行扫描的方式)。
扫描原理清楚以后,紧接着大家再来看看VGA的行、列同步时序
行列时序
列同步时序
行同步时序
VGA 中定义行时序和列时序都需要同步脉冲(a 段)、显示后沿(b 段)、显示时序段(c 段)和显示前沿(d 段)四部分。VGA 工业标准显示模式要求:行同步、列同步都为负极性,即同步脉冲要求是负脉冲。
由 VGA 行时序可知:每一行都有一个负极性行同步脉冲(a 段),是数据行的结束标志,同时也是下一行的开始标志。在同步脉冲之后为显示后沿(b段),在显示时序段(c 段)为显示器亮的过程,RGB 数据驱动一行上的每一个像素点,从而显示一行。在一行的最后为显示前沿(d 段)。在显示时间段之外没有图像投射到屏幕,而是插入消隐信号。同步脉冲、显示后沿和显示前沿都是在行消隐间隔内,当消隐有效时,RGB 信号无效,屏幕不显示数据。
显示标准
VGA有许多的显示标准,如下表:
以本实验的显示标准 800*600*60Hz 为例。(800 为列数,600 为行数,60Hz为刷新一屏的频率)
行时序:屏幕对应的行数为 628(a+b+c+d=e 段),其中 600(c 段)为显示行;每行均有行同步信号(a 段),为4 个行周期的低电平;
列时序:每个显示行包括1056列(a+b+c+d=e段),其中800(c段)为有效显示区,每列均有列同步信号(a段),为128个列周期的低电平。
屏幕显示有效区域如下图:
顶层框架
原理清楚以后,我们本次的任务是设计VGA控制器,驱动液晶屏显示器显示全红色。现设计系统框图如下:
说明:
(1)时钟分频模块(PLL)
我们开发板上使用的晶振为50MHZ,由于我们的显示标准为800*600*60Hz,该显示模式需要的系统时钟频率为40MHz,因此我们通过调用锁相环分频来实现。
(2)VGA行列同步控制模块(VGA)
VGA显示标准需要设定行列同步信号,标定出有效显示区域,这也是整个VGA驱动模块的核心部分
(3)VGA色彩显示控制模块(R_g_b)
在图像有效显示区域内,输出控制颜色的r、g、b信号
顶层模块端口描述
端口名 |
端口说明 |
clk_sys |
系统50MHz时钟输入 |
rst_n |
系统低电平复位 |
vga_r |
输出VGA红基色信号 |
vga_g |
输出VGA绿基色信号 |
vga_b |
输出VGA蓝基色信号 |
vga_hs |
输出VGA列同步信号 |
vga_vs |
输出VGA行同步信号 |
接下来我们学习每个模块的具体代码实现,由于分频模块我们采用的是锁相环,而之前的章节中,我们对锁相环的使用有专门的论述,所以此处我们不再赘述。
8.7.7 代码实现
VGA行列同步控制模块
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:VGA行列同步控制模块 * *****************************************************/ 01 module vga( 02 input clk, //连接至分频时钟,为40MHz 03 input rst_n, //低电平复位 04 05 output reg vga_hs,//VGA列同步信号 06 output reg vga_vs,//VGA行同步信号 07 output en //显示有效区域的使能信号 08 ); 09 10 parameter hy_all = 11‘d1056, //列时序 11 hy_a = 11‘d128, 12 hy_b = 11‘d88, 13 hy_c = 11‘d800, 14 hy_d = 11‘d40, 15 16 vy_all = 11‘d628, //行时序 17 vy_a = 11‘d4, 18 vy_b = 11‘d23, 19 vy_c = 11‘d600, 20 vy_d = 11‘d1; 21 22 //用计数器限定VGA显示相应区域 23 reg [10:0] cnt_h;//列计数器 24 reg [10:0] cnt_v;//行计数器 25 26 //-----------------------列计数----------------- 27 always@(posedge clk or negedge rst_n) 28 if(!rst_n) 29 cnt_h <= 11‘d0;//列计数器复位 30 else if(cnt_h == (hy_all-1))//所有列扫描完毕 31 cnt_h <= 11‘d0;//列计数器清零 32 else 33 cnt_h <= cnt_h + 1‘b1;//列计数器累加 34 35 //-----------------------行计数-------------------- 36 always@(posedge clk or negedge rst_n)//在一列计数完之后将行加1 37 if(!rst_n) 38 cnt_v <= 11‘d0;//行计数器复位 39 else if(cnt_v == (vy_all-1))//所有行扫描完毕 40 cnt_v <= 11‘d0;//行计数器清零 41 else if(cnt_h ==(hy_all-1))//所有列扫描完毕 42 cnt_v <= cnt_v + 1‘b1;//行计数器加一 43 44 //---------------------限定列同步信号--------------- 45 always@(posedge clk or negedge rst_n) 46 if(!rst_n) 47 vga_hs <= 1‘b1; //复位时置列同步信号为高电平 48 else if(cnt_h ==0) //列开始扫描 49 vga_hs <= 1‘b0; //置列同步信号为低电平 50 else if(cnt_h == hy_a) //保持hy_a个时钟周期 51 vga_hs <= 1‘b1; //置列同步信号为高电平 52 53 //---------------限定行同步信号-------------------- 54 always@(posedge clk or negedge rst_n) 55 if(!rst_n) 56 vga_vs <= 1‘b1; //复位时置行同步信号为高电平 57 else if(cnt_v ==0) //行开始扫描 58 vga_vs <= 1‘b0; //置行同步信号为低电平 59 else if(cnt_v == vy_a)//保持vy_a个时钟周期 60 vga_vs <= 1‘b1; //置行同步信号为高电平 61 62 //----------限定显示有效区域,设定使能信号---------- 63 wire [12:0] en1;//列有效标志 64 wire [12:0] en2;//行有效标志 65 //列有效区域 66 assign en1 = (cnt_h >= hy_a + hy_b && cnt_h <= 67 hy_a + hy_b + hy_c)?(cnt_h-hy_a-hy_b):11‘d0; 68 //行有效区域 69 assign en2 = (cnt_v >= vy_a + vy_b && cnt_v <= 70 vy_a + vy_b + vy_c)?(cnt_v-vy_a-vy_b):11‘d0; 71 assign en = (en1 > 0 && en2 > 0 )?1‘b1:1‘b0;//行、列共同有效区域800*600 72 73 endmodule |
代码说明:本模块是VGA行列同步控制模块,第10~20行定义了显示标准为800*600*60的一些参数,第26~42行写的是行列计数器,当计数满一行之后,行计数器清零,当所有列扫面完毕之后,列计数器清零;第45~60行是限定列显示和行显示的控制逻辑;第63~71行定义了2个有效区域,第66~67是列有效区域,69~70是行有效区域,第71行是当列有效区域和行有效区域都有效的区域。
VGA色彩输出控制器模块
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:VGA色彩输出控制器模块 * *****************************************************/ 01 module r_g_b( //颜色控制模块 02 //端口信号:模块的输入输出接口 03 input en, //使能信号 04 05 output [2:0] vga_r, //红色(3位:根据数值的变化,控制颜色的深浅) 06 output [2:0] vga_g, //绿色(3位:根据数值的变化,控制颜色的深浅) 07 output [1:0] vga_b //蓝色(2位:根据数值的变化,控制颜色的深浅) 08 ); 09 10 //-----------在使能区域显示相应的颜色---------- 11 assign vga_r = en?3‘b111:3‘b000;//在使能信号下输出红色 12 assign vga_g = 3‘b000; //无绿色输出 13 assign vga_b = 2‘b00; //无蓝色输出 14 15 endmodule |
第11行在输入en信号有效的情况下,输出全红基色信号,绿色和蓝色都不输出。
VGA显示顶层模块
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:VGA显示顶层模块 * *****************************************************/ 01 module top( //顶层模块:将各个模块组合 02 //外部接口 03 input clk, //系统时钟50MHz 04 input rst_n,//低电平复位 05 output vga_vs,//VGA行同步信号 06 output vga_hs,//VGA列同步信号 07 output [2:0] vga_r,//红色输出信号 08 output [2:0] vga_g,//绿色输出信号 09 output [1:0] vga_b //蓝色输出信号 10 ); 11 //内部信号:模块内部的接口信号,比如模块pll的输出信号c0, 12 //通过内部信号clk_40与模块vga的输入信号clk相连 13 wire clk_40; 14 wire en; 15 16 //模块例化 17 pll pll( //分频时钟,用锁相环产生, 18 .inclk0(clk), //在显示标准800*600*60HZ中,时钟指定为40MHz 19 .c0(clk_40) 20 ); 21 22 vga vga( //接入分频时钟,限定显示的有效区域 23 .clk(clk_40), 24 .rst_n(rst_n), 25 .vga_vs(vga_vs), 26 .vga_hs(vga_hs), 27 .en(en) 28 ); 29 30 r_g_b r_g_b( //在有效区域内,显示相应颜色 31 .en(en), 32 .vga_r(vga_r), 33 .vga_g(vga_g), 34 .vga_b(vga_b) 35 ); 36 37 endmodule |
综合编译以后,我们可以查看RTL视图,查看电路综合结果和预想是否一致,调用RTL视图如下:
由此可以看到电路综合出的结果和我们预先设计的框架相同。接下来我们编写测试代码,用来验证我们设计的正确性。
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:VGA显示测试模块 * *****************************************************/ 01 `timescale 1 ns/ 1 ps //设置仿真时间单位与精度分别为1ns/1ps 02 module test; 03 //端口信号定义,激励信号为reg型 04 reg clk; 05 reg rst_n; 06 wire [2:0] vga_r; 07 wire [2:0] vga_g; 08 wire [1:0] vga_b; 09 wire vga_hs; 10 wire vga_vs; 11 //初始化激励,以及给相应激励赋值 12 initial 13 begin 14 clk = 0; 15 rst_n = 0; //在复位阶段,将激励赋初值 16 #200.1 rst_n = 1; //在延时200ns后将复位信号置为1 17 end 18 always #10 clk = ~clk; //时钟为1/20ns = 50MHZ 19 //模块例化 20 top top( 21 .clk(clk), 22 .rst_n(rst_n), 23 .vga_hs(vga_hs), 24 .vga_vs(vga_vs), 25 .vga_r(vga_r), 26 .vga_g(vga_g), 27 .vga_b(vga_b) 28 ); 29 endmodule |
仿真分析
从波形可以看出,当en有效时,vga_r输出3’b111,说明设计是正确的。
将代码下载到开发板,可以看到整个屏幕全部显示红色,说明我们本次的设计是正确的。
原文地址:https://www.cnblogs.com/mengyi1989/p/11518356.html