2.10 VGA显示矩阵-明德扬至简设计法原理与应用
本节的文档编号:001700000021
需要看对应的视频,请点击视频编号:001700000442
1、至间原理与应用配套的案例和PPT讲解
2、本设计需要通过VGA线将显示器和开发板进行连接,FPGA在连接成功后产生640*480分辨率,刷新频率为60Hz的VGA时序,使得显示器产生显示一幅完整的矩阵图像。这幅矩阵图像即为显示屏边缘上显示一个宽为20像素的红色边框,在屏幕的中央显示一个长为150像素、高为100像素的绿色矩形。步骤性教学;
3、Altera和Xilinx入门学习案例文档
1项目背景
请参考“VGA显示颜色”案例中的项目背景内容。
2设计目标
通过VGA连接线,将显示器和教学板的VGA接口相连。连接示意图如下。

图371
然后FPGA产生640*480分辨率,刷新频率为60Hz的VGA时序,让显示器产生显示一幅完整的矩阵图像,即下表中的第一种参数。提示:显示器一般都会自适应功能,无须设置就能识别不同分辨率的图像。

其中,行的单位为“基准时钟”,即频率为25MHz、周期为40ns的时钟,注意列的单位为“行”。
矩阵图像是在显示屏边缘上显示一个红色边框(边框宽为20像素),在屏幕的中央显示一个绿色矩形(矩形长为150像素,高为100像素)。

图372
注意,不同显示器会有差别。
3设计实现
3.1顶层接口
新建目录:D:mdy_book ec_exec1。在该目录中,新建一个名为rec_exec1.v的文件,并用GVIM打开,开始编写代码。
我们要实现的功能,概括起来就是FPGA产生VGA时序,即控制VGA_R4~R0、VGA_G5~G0、VGA_B4~B0、VGA_HSYNC和VGA_VSYNC,让显示器显示红色。其中,VGA_HSYNC和VGA_VSYNC,FPGA可根据时序产生高低电平。而颜色数据,由于是固定的红色,FPGA也能自己产生,不需要外部输入图像的数据。那么我们的FPGA工程,可以定义输出信号hys表示行同步,用输出信号vys表示场同步,定义一个16位的信号lcd_rgb,其中lcd_rgb[15:11]表示VGA_R4~0,、lcd_rgb[10:5]表示VGA_G5~0,、lcd_rgb[4:0]表示VGA_B4~0。
我们还需要时钟信号和复位信号来进行工程控制。
综上所述,我们这个工程需要五个信号,时钟clk,复位rst_n,场同步信号vys、行同步信号hys和RGB输出信号lcd_rgb。

将module的名称定义为rec_exec1。并且我们已经知道该模块有五个信号:clk、rst_n、lcd_hs、lcd_vs和lcd_rgb。为此,代码如下:

其中clk、rst_n是输入信号,lcd_hs、lcd_vs和lcd_rgb是输出信号,其中clk、rst_n、lcd_hs、lcd_vs的值是0或者1,一根线即可,lcd_rgb为16位位宽的,根据这些信息,我们补充输入输出端口定义。代码如下:

3.2架构设计
需要注意的是,输入进来的时钟clk是50MHz,而从分辨率参数表可知道,行单位的基准时钟是25 MHz。为此我们需要根据50MHz来产生一个25 MHz的时钟,然后再用于产生VGA时序。
为了得到这个25M时钟,我们需要一个PLL。PLL可以认为是FPGA内的一个硬核,它的功能是根据输入的时钟,产生一个或多个倍频和分频后的输出时钟,同时可以调整这些输出时钟的相位、占空比等。
例如,输入进来是50M时钟,如果我需要一个100M时钟,那么从逻辑上、代码上是不可能产生的,我们就必须用到PLL来产生了。
整个工程的结构图如下。

图373
PLL的生成方式过程,请看本案例的综合工程和上板一节的内容。
3.3VGA驱动模块设计
3.3.1接口信号
在目录:D:mdy_book ec_exec1中,建立一个rectangle.v文件,并用GVIM打开,开始编写代码。
将module的名称定义为rectangle。并且我们已经知道该模块有五个信号:clk、rst_n、hys、vys和lcd_rgb。为此,代码如下:

其中clk、rst_n是输入信号,hys、vys和lcd_rgb是输出信号,其中clk、rst_n、hys、vys的值是0或者1,一根线即可,lcd_rgb为16位位宽的,根据这些信息,我们补充输入输出端口定义。代码如下:

我们先分析功能。要控制显示器,让其产生红色,也就是让FPGA控制VGA_R0~4、VGA_G0~5、VGA_B0~4、VGA_VSYNC和VGA_HSYNC信号。那么VGA驱动模块,可以定义输出信号hys表示行同步,用输出信号vys表示场同步,定义一个16位的信号lcd_rgb,其中lcd_rgb[15:11]表示VGA_R4~0,、lcd_rgb[10:5]表示VGA_G5~0,、lcd_rgb[4:0]表示VGA_B4~0。
同时该模块的工作时钟为25M,同时需要一个复位信号。
综上所述,我们这个模块需要五个信号,25M时钟clk,复位rst_n,场同步信号vys、行同步信号hys和RGB输出信号lcd_rgb。
3.3.2信号设计
我们先设计场同步信号hys,VGA时序中的场同步信号,其时序图如下:

图374
hys就是一个周期性地高低变化的脉冲。我们使用的是下表中的第一种分辨率,也就是同步脉冲a的时间是96个时钟周期,而显示后沿b是48个时钟周期,显示时序c是640个时钟周期,显示前沿是16个时钟周期,一共是800个时钟周期。

将时间信号填入图中,更新后的时序图如下:

图375
很显然,我们需要1个计数器来产生这个时序,我们将该计数器命名为h_cnt。由于hys是不停地产生的,那么h_cnt就是不停地计数,每个时钟都要计数器,所以认为该计数器的加1条件为“1”,可写成:assign add_h_cnt = 1。从上图可知,该计数器的周期是800。综上所述,该计数器的代码如下:

有了计数器h_cnt,那么hys信号就有了对齐的对象。从时序图可以发现,hys有两个变化点,一个是h_cnt数到96个时,由0变1;另一个是当h_cnt数到800个时,由1变0。所以,场同步信号的代码如下:

接下来设计vys信号。该信号的时序图如下所示。

图376
vys就是一个周期性地高低变化的脉冲。我们使用的是表中的第一种分辨率,查询表可知,同步脉冲a的时间是2行的时间,而显示后沿b是33行,显示时序c是480行,显示前沿是10行,一共是525行。其中,一“行”结束,也就是h_cnt数完了。
将时间信号填入图中,更新后的时序图如下:

图377
很显然,我们还需要1个计数器来产生这个时序,我们将该计数器命名为v_cnt。该计数器是用来数有多少行的,所以加1条件就是一行结束,即end_h_cnt,可写成:assign add_v_cnt = end_h_cnt。从上图可知,该计数器的周期是525。综上所述,该计数器的代码如下:

有了计数器v_cnt,那么vys信号就有了对齐的对象。从时序图可以发现,vys有两个变化点,一个是v_cnt数到2个时,由0变1;另一个是当h_cnt数到525个时,由1变0。所以,场同步信号的代码如下:

最后我们还有一个信号需要设计,那就是lcd_rgb信号。

图378
我们在显示器中一共要显示三种颜色:红色、绿色和白色。lcd_rgb等于16’b11111_000000_00000时表示红色;lcd_rgb等于16’b00000_111111_00000时表示绿色;lcd_rgb等于16’b11111_111111_11111时表示白色。还要注意的是,在非显示区域,lcd_rgb的值要为0,才能正确显示。我们现在要仔细区分,在什么时候分别输出上面的值。结合VGA时序,h_cnt和v_cnt,可以得到下面结论。
显示区域:(h_cnt >=(96+48)&& h_cnt <(96+48+640)),并且(v_cnt>=(2+33) && v_cnt<(2+33+480))
红色区域:(h_cnt >=(96+48)&& h_cnt <(96+48+20))或者
(h_cnt >=(96+48+620)&& h_cnt <(96+48+640))或者
(v_cnt >= (2+33) && v_cnt<(2+33+20))或者
(v_cnt >= (2+33+460) && v_cnt<(2+33+480))
绿色区域:(h_cnt >=(96+48+320-75)&& h_cnt <(96+48+320+75))并且
(v_cnt >= (2+33+240-50) && v_cnt<(2+33+240+50))
白色区域:在显示区域中,非红色区域并且非绿色区域的,就是白色区域。
非显示区域:显示区域之外的,就是非显示区域。
我们可以设计几个信号来表示这些区域。显示区域用valid_area=1表示,红色区域用red_area=1表示,绿色区域用green_area=1表示。可得到代码如下:

有了red_area、green_area和valid_area后,设计lcd_rgb就好办了。
非显示区域(valid_area=0),lcd_rgb输出“16’b0”;
显示区域(valid_area)中的红色区域(red_area=1),lcd_rgb输出“16’b11111_000000_00000”;
显示区域(valid_area)中的绿色区域(green_area=1),lcd_rgb输出“16’b00000_111111_00000”;
显示区域(valid_area)中的非红色区域(red_area=0)且非绿色区域(green_area=0),lcd_rgb输出“16’b11111_111111_11111”。
则可以写出代码如下:

此次,主体程序已经完成。接下来是将module补充完整。
3.3.3信号定义
接下来定义信号类型。
h_cnt是用always产生的信号,因此类型为reg。h_cnt计数的最大值为800,需要用10根线表示,即位宽是10位。因此代码如下:

add_h_cnt和end_h_cnt都是用assign方式设计的,因此类型为wire。并且其值是0或者1,1个线表示即可。因此代码如下:

v_cnt是用always产生的信号,因此类型为reg。v_cnt计数的最大值为525,需要用10根线表示,即位宽是10位。因此代码如下:

add_v_cnt和end_v_cnt都是用assign方式设计的,因此类型为wire。并且其值是0或者1,1根线表示即可。因此代码如下:

lcd_rgb是用always方式设计的,因此类型为reg。并且它的位宽是16位,16根线表示即可。因此代码如下:

hys和vys是用always方式设计的,因此类型为reg。并且其值是0或1,需要1根线表示即可。因此代码如下:

red_area、green_area和valid_area是用always方式设计的,因此类型为reg。并且其值是0或1,用一根线表示即可,因此代码如下:

3.4顶层模块设计
3.4.1例化子模块
例化PLL IP核的代码

例化驱动模块的代码

3.4.2信号定义
clk_0是在例化文件中,因此类型为wire。并且其值是0或1,用一根线表示即可。因此代码如下:

lcd_sh和lcd_vs是在例化文件中,因此类型为wire。并且其值是0或1,用一根线表示即可。因此代码如下:

lcd_rgb是在例化文件中,因此类型为wire。它的位宽是16位的,用16根线表示即可。因此代码如下:

至此,整个代码的设计工作已经完成。下一步是新建工程和上板查看现象。
4综合与上板
4.1新建工程
首先在d盘中创建名为“rec_exec1”的工程文件夹,将写的代码命名为“rec_exec1.v”,顶层模块名为“rec_exec1”,例化文件命名为“rectangle.v”。

图379

图380

图381
然后打开QuartusⅡ,点击File下拉列表中的New Project Wzard...新建工程选项。

图382
3.在出现的界面中直接点击最下方的“Next”。

图383
4.之后出现的是工程文件夹、工程名、顶层模块名设置界面。按照之前的命名进行填写,第一栏选择工程文件夹“rec_exec1”,第二栏选择工程文件“rec_exec1.v”,最后一栏选择顶层模块名“rec_exec1”,然后点击”Next”,在出现的界面选择empty project。

图384

图385
5.之后是文件添加界面。在上方一栏中添加之前写的”rec_exec1.v和rectangle.v”文件和生成的“my_pll.v”文件,点击右侧的“Add”按钮,之后文件还会出现在大方框中,之后点击“Next”。

图386
器件型号选择界面。在“Device family”处选择CycloneⅣE,在“Available devices”处选择EP4CE15F23C8,然后点击“Next”。

图387
EDA工具界面。该页面用默认的就行,直接点击最下方“Next”。

图388
8.之后出现的界面是我们前面的设置的总结,确认没有错误后点击“Finish”。

图389
4.2PLL
新建工程后,就要生成PLL IP核。本节的PLL生成过程,与案例“VGA显示颜色”第四点综合工程和上板中的PLL内容一致,注意其中的地址有不同。
4.3综合
1.新建工程步骤完成后,就会出现以下界面。在“Project Navigator”下选中要编译的文件,点击上方工具栏中“Start Compilation”编译按钮(蓝色三角形)。

图390
2.编译成功后会出现以下界面,点击“OK”。

图391
4.4配置管脚

图392
在菜单栏中,选中Assignments,然后选择Pin Planner,就会弹出配置管脚的窗口。

图393
在配置窗口最下方中的location一列,参考下表中最右两列配置好FPGA管脚。

注意注意:与其他案例不同的是,VGA案例中所有管脚的电平必须选用为LVCMOS3.3,而不能是default。如下图所示。
配置完成后,关闭Pin Planner,软件自动会保存管脚配置信息。
4.5再次综合

图394
在菜单栏中,选中Processing,然后选择Start Compilation,再次对整个工程进行编译和综合。

图395
出现上面的界面,就说明编译综合成功。
4.6连接开发板
图中,下载器接入电脑USB接口,电源接入电源,vga线连接显示器,然后摁下电源开关,看到开发板灯亮。

图396
4.7上板
1.双击Tasks一栏中”Program Device”。

图397
2.会出现如下界面,点击add file添加.sof文件,在右侧点击“Start”,会在上方的“Progress”处显示进度。

图398
3.进度条中提示成功后,即可在显示器上观察到相应的现象。