正点原子 发表于 2019-6-1 16:54:27

【正点原子FPGA连载】第二十一章VGA图片显示实验(基于ROM)--摘自【正点原子】开拓者 FPGA 开发指南

本帖最后由 正点原子 于 2020-10-23 11:37 编辑

1)实验平台:正点原子开拓者FPGA开发板
2)平台购买地址:https://item.taobao.com/item.htm?id=579749209820
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-281143-1-1.html
4)本实例源码下载:
5)对正点原子FPGA感兴趣的同学可以加群讨论:712557122点击加入:
6)关注正点原子公众号,获取最新资料更新:

第二十一章 VGA图片显示实验(基于ROM)

我们在“VGA字符显示实验”中利用一个二维数组存储字符的点阵数据, 进而实现汉字的显示。 字符显示时每个像素点采用二维数组中的1位(bit) 数据来表示, 只有0和1的差别, 即只能区分两种颜色。 然而在显示图片时, 由于1bit的数据无法区分各像素点的色彩差异, 因此
二维数组已经不能满足图片存储的需要。 本章我们将通过例化IP核来实现使用ROM存储图片,并将ROM中存储的图片通过VGA接口显示到屏幕上。
本章包括以下几个部分:
21.1 VGA简介
21.2 实验任务
21.3 硬件设计
21.4 程序设计
21.5 下载验证

21.1 VGA简介
我们在“VGA彩条显示实验” 中对VGA视频传输标准作了详细的介绍, 包括VGA接口定义、行场同步时序、以及显示分辨率等。如果大家对这部分内容不是很熟悉的话, 请参考“VGA彩条显示实验” 中的VGA简介部分。
21.2 实验任务
本章的实验任务是使用开拓者开发板上的VGA接口在显示器的屏幕中心位置显示彩色图片。显示分辨率为640*480, 刷新速率为60hz,图片的大小为100*100。
21.3 硬件设计
VGA接口部分的硬件设计原理及本实验中各端口信号的管脚分配与“VGA彩条显示实验” 完全相同, 请参考“VGA彩条显示实验” 中的硬件设计部分。
21.4 程序设计
图 21.4.1是根据本章实验任务画出的系统框图。其中, 时钟分频模块负责产生像素时钟,VGA驱动模块产生行场同步信号及像素点的纵横坐标, VGA显示模块输出图像数据, ROM用于存储需要显示的图片。



图 21.4.1 基于ROM的VGA图片显示实验系统框图

VGA显示模块中的ROM是通过例化IP核来实现的只读存储器,它使用FPGA的片上存储资源。由于FPGA的片上存储资源有限,所以ROM中存储的图片大小也受到限制。由于开拓者开发板上的VGA接口采用RGB565数据格式,即每个像素点的颜色用16bit的数据来表示,因此大小为
100*100的图片占用的存储空间为100*100*16bit=160000bit=156.25Kbit(1Kbit=1024bit)。而开拓者开发板上的FPGA片上存储资源为414Kbit,能够满足实验任务中的图片存储需求。ROM作为只读存储器, 在调用IP核时需要指定初始化文件, 在这里就是写入存储器中的图片数据,各种格式的图片(bmp、jpg等)都是以MIF文件的形式导入到ROM中的。MIF是一种Quartus工具能识别的文件格式, 在文件的开头定义了存储器的位宽和深度、 地址格式、 数据格式等信息, 紧接着列出了存储单元地址以及写入各地址的数据。 例如,一个位宽为16, 深度为5的MIF
文件内容如下图所示:



图 21.4.2 MIF文件示例

当需要存储的数据量较小时,如果我们知道数据的内容, 那么就可以仿照图 21.4.2的格式手动编写MIF文件。但是由于图片的数据量较大,并且我们无法直接看出各个像素点对应的颜色数据, 因此需要借助工具来实现图片到MIF文件的转换。 在这里我们使用正点原子提供的
工具“PicToMif” 来实现这一转换过程,该工具位于开发板所随附的资料中“6_软件资料/1_软件/PicToMif” 目录下。我们在Windows自带的“画图” 工具中将正点原子的LOGO图片大小调整100*100, 并利用工具PicToMif转换得到MIF文件“ZDYZ.mif” 。
双击运行“PicToMif.exe” , 点击“加载图片” 并在弹出的界面中选择需要转换的图片(注意:待转换图片分辨率的大小必须是100*100), 图片加载成功后工具会在图片属性中指示出图片的文件名和大小;接下来选择图片转换的数据格式为RGB565;最后点击“一键转换” 按钮,在弹出的界面中选择MIF文件的存放路径并输入文件名。 PicToMif转换过程中的软件界面
如图 21.4.3所示:




图 21.4.3 PicToMif转换界面

最终转换得到的MIF文件部分截图如下所示:


图 21.4.4 转换得到的MIF文件


程序中各模块端口及信号连接如图 21.4.5所示:






图 21.4.5 顶层模块原理图

图 21.4.5中的顶层模块(vga_blockmove) 、时钟分频模块(vga_pll)以及VGA驱动模块(vga_driver) 均与“VGA彩条显示实验” 完全相同, 只对VGA显示模块(vga_display) 作了修改。因此, 这里我们重点讲解VGA显示模块,其他部分大家可以参考“VGA彩条显示实验” 。
VGA显示模块的代码如下:
1 module vga_display(
2 input vga_clk, //VGA驱动时钟
3 input sys_rst_n, //复位信号
4 5
input [ 9:0] pixel_xpos, //像素点横坐标
6 input [ 9:0] pixel_ypos, //像素点纵坐标
7 output pixel_data //像素点数据
8 );
9
10 //parameter define
11 parameter H_DISP = 10'd640; //分辨率——行
12 parameter V_DISP = 10'd480; //分辨率——列
13
14 localparam POS_X = 10'd270; //图片区域起始点横坐标
15 localparam POS_Y = 10'd190; //图片区域起始点纵坐标
16 localparam WIDTH = 10'd100; //图片区域宽度
17 localparam HEIGHT = 10'd100; //图片区域高度
18 localparam TOTAL = 14'd10000; //图案区域总像素数
19 localparam BLACK = 16'b00000_000000_00000; //屏幕背景色
20
21 //reg define
22 wire rom_rd_en; //读ROM使能信号

23 reg rom_addr; //读ROM地址
24 reg rom_valid; //读ROM数据有效信号
25
26 //wire define
27 wire rom_data; //ROM输出数据
28
29 //*****************************************************
30 //** main code
31 //*****************************************************
32
33 //从ROM中读出的图像数据有效时,将其输出显示
34 assign pixel_data = rom_valid ? rom_data : BLACK;
35
36 //当前像素点坐标位于图片显示区域内时,读ROM使能信号拉高
37 assign rom_rd_en = (pixel_xpos >= POS_X) && (pixel_xpos < POS_X + WIDTH)
38 && (pixel_ypos >= POS_Y) && (pixel_ypos < POS_Y + HEIGHT)
39 ? 1'b1 : 1'b0;
40
41 //控制读地址
42 always @(posedge vga_clk or negedge sys_rst_n) begin
43 if (!sys_rst_n) begin
44 rom_addr <= 14'd0;
45 end
46 else if(rom_rd_en) begin
47 if(rom_addr < TOTAL - 1'b1)
48 rom_addr <= rom_addr + 1'b1; //每次读ROM操作后,读地址加1
49 else
50 rom_addr <= 1'b0; //读到ROM末地址后,从首地址重新开始读操作
51 end
52 else
53 rom_addr <= rom_addr;
54 end
55
56 //从发出读使能到ROM输出有效数据存在一个时钟周期的延时

57 always @(posedge vga_clk or negedge sys_rst_n) begin
58 if (!sys_rst_n)
59 rom_valid <= 1'b0;
60 else
61 rom_valid <= rom_rd_en;
62 end
63
64 //通过调用IP核来例化ROM
65 pic_rom pic_rom_inst(
66 .clock (vga_clk),
67 .address (rom_addr),
68 .rden (rom_rd_en),
69 .q (rom_data)
70 );
71
72 endmodule
代码中14至19行声明了一系列的变量,方便大家修改图片的大小、在屏幕上显示的位置等,其中图片显示的位置由图片显示区域左上角的纵横坐标来指定。由于图片存储在ROM中,因此VGA显示模块的主要任务就是控制ROM的读使能及读地址, 从而在合适的时间段将ROM中的图片数据读出并显示。代码的36至39行判断当前像素点的纵横坐标, 当其位于图片显示区域时将ROM读使能信号rom_rd_en拉高。第41至54行在读操作过程中将读地址依次累加, 从而将图片数据顺序读出; 当读到未地址后读地址清零,重新从ROM中图像的第一个像素点数据开始读取。
读ROM的过程中, 从发出读使能到ROM输出有效数据存在一个时钟周期的延时, 因此ROM数据有效信号rom_valid需要由rom_rd_en延迟一个时钟周期,如程序第56至62行所示。
程序第64~70行例化了ROM IP核,在工程中调用IP核时, 需要设置ROM位宽为16bit,深度为选择16384(不能低于100*100), 如图 21.4.7所示。 此外, 为了保证从ROM的读使能信号拉高到有效数据输出之间仅存在一个时钟周期的延时, 需要取消寄存端口输出, 如图 21.4.8红色
方框所示。




图 21.4.6 新建ROM IP核




图 21.4.7 配置ROM位宽及深度






图 21.4.8 取消寄存端口输出

最后,在“Mem Init” 页选择前面生成的初始化文件“ZDYZ.mif” ,如图 21.4.9所示。注意需要将该MIF文件置于工程目录下,本工程中的MIF文件位于vga_rom_pic/doc文件夹下。





图 21.4.9 选择存储器初始化文件

图 21.4.10为VGA显示模块显示图片时SignalTap抓取的波形图。从图中可以看到,在ROM读使能信号rom_rd_en拉高时, 读地址rom_addr依次累加。 同时数据有效信号rom_valid相对于rom_rd_en延时一个时钟周期。



图 21.4.10 VGA显示模块SignalTap波形图

21.5 下载验证
基于ROM的VGA图片显示实验的工程位于vga_rom_pic/par文件夹下, 工程打开后如图21.5.1所示:




图 21.5.1 基于ROM的VGA图片显示

请大家参考VGA彩条显示实验中的下载验证方法, 将vga_rom_pic/par/output_files目录下的“vga_rom_pic.sof” 文件下载至开发板。下载完成后在VGA显示器上观察显示的图片如图21.5.2所示,说明基于ROM的VGA图片显示程序下载验证成功。



图 21.5.2 基于ROM的VGA图片显示效果图

页: [1]
查看完整版本: 【正点原子FPGA连载】第二十一章VGA图片显示实验(基于ROM)--摘自【正点原子】开拓者 FPGA 开发指南