基于ROM的VGA图像显示

 1 图片预处理

        在本次实验中,我们用来存储图片的ROM是通过调用IP核,利用FPGA片上资源生成的只读存储器,但FPGA片上资源有限,生成ROM的存储空间也会受限,存储于ROM的图片大小也受到限制。

        FPGA开发板上使用的芯片为Altera公司的EP4CE15F23C8芯片,存储空间为414Kbit;本次实验显示图片分辨率为100*100,色彩格式为RGB565,存储于ROM所占空间为100*100*16=160000bit=156.25Kbit。通过比较发现,芯片可生成满足要求的ROM 用来存储图片。

        ROM作为只读存储器,在进行IP核设置时需要指定初始化文件, 即写入存储器中的图片数据,图片要以规定的格式才能正确写入ROM,这种格式就是MIF文件。MIF是Quartus规定的一种文件格式,文件格式示意图,具体见图:

        若存储数据量较小,我们可以参照上图,手动写入数据。但如果存储量较大,手动输入不太现实。本次实验中要写入100*100个数据,不可能使用手动输入,在这里我们使用Matlab软件将图片转化为MIF文件,具体步骤如下。 

clear %清理命令行窗口
clc %清理工作区

% 使用imread函数读取图片,并转化为三维矩阵
image_array = imread('D:\FPGA\FPGA_Basic_Pro\vga_rom_pic\matlab\curry.bmp');

% 使用size函数计算图片矩阵三个维度的大小
% 第一维为图片的高度,第二维为图片的宽度,第三维为图片维度

[height,width,z]=size(image_array); % 100*100*3

 red = image_array(:,:,1); % 提取红色分量,数据类型为uint8
 green = image_array(:,:,2); % 提取绿色分量,数据类型为uint8
 blue = image_array(:,:,3); % 提取蓝色分量,数据类型为uint8

 % 使用reshape函数将各个分量重组成一个一维矩阵
 %为了避免溢出,将uint8类型的数据扩大为uint32类型

 r = uint32(reshape(red' , 1 ,height*width));
 g = uint32(reshape(green' , 1 ,height*width));
 b = uint32(reshape(blue' , 1 ,height*width));

 % 初始化要写入.mif文件中的RGB颜色矩阵
 rgb=zeros(1,height*width);

 % 导入的图片为24bit真彩色图片,每个像素占用24bit,RGB888
 % 将RGB888转换为RGB565
 % 红色分量右移3位取出高5位,左移11位作为ROM中RGB数据的第15bit到第11bit
 % 绿色分量右移2位取出高6位,左移5位作为ROM中RGB数据的第10bit到第5bit
 % 蓝色分量右移3位取出高5位,左移0位作为ROM中RGB数据的第4bit到第0bit

 for i = 1:height*width

 rgb(i) = bitshift(bitshift(r(i),-3),11) + bitshift(bitshift(g(i),-2),5) + bitshift(bitshift(b(i),-3),0);

 end

 fid = fopen( 'D:\FPGA\FPGA_Basic_Pro\vga_rom_pic\matlab\image.mif', 'w+' );

 % .mif文件字符串打印
 fprintf( fid, 'WIDTH=16;n');
 fprintf( fid, 'DEPTH=%d;nn',height*width);
 fprintf( fid, 'ADDRESS_RADIX=UNS;n');
 fprintf( fid, 'DATA_RADIX=HEX;nn');
 fprintf(fid,'%snt','CONTENT');
 fprintf(fid,'%sn','BEGIN');

 % 写入图片数据

 for i = 1:height*width

 fprintf(fid,'\t\t%d\t:%x\t;\n',i-1,rgb(i));

 end

 % 打印结束字符串
 fprintf(fid,'\tEND;');
 fclose( fid ); % 关闭文件指针

2 模块框图

 3 模块波形图

第一部分:彩条背景色彩信息(pi_data)波形图绘制思路

        根据输入像素点坐标(pix_x,pix_y),在有效显示区域,将pix_x计数范围十等分,在不同的计数部分给pix_data赋值对应的色彩信息,因为采用时序逻辑的赋值方式,pix_data滞后pix_x、pix_y信号一个时钟周期。信号波形图如下:

第二部分:ROM读使能(rd_en)、ROM地址(rom_addr)波形图绘制思路

        我们将要显示的的图片数据是事先写入ROM,ROM为调用IP核生成,写入照片分辨率为100*100。要想将写入ROM的图片读取出来,使能信号和地址信号必不可少,所以模块内部要声明ROM读使能信号(rd_en)和ROM地址(rom_addr)信号。

        我们可以在图片显示区域拉高使能信号,将要读取数据地址写入ROM地址端口,读取地址对应图像数据。但有一点要注意,自ROM读取的数据是滞后使能信号和地址信号一个时钟周期的,比如,当使能信号为高电平,地址写入为999,但与地址999同步输出的数据为地址998的数据,所以ROM读使能信号(rd_en)和RO M地址(rom_addr)信号均要超前图片显示区域一个时钟周期,信号波形图绘制如下:

第三部分:图片显示有效信号(pic_valid)、待显示图像数据(pic_data_out)波形图绘制思路

        想要在彩条图像背景上显示要显示的图片,我们需要在图片显示区域,使用图片数据覆盖彩条背景,那么如何确定图像显示区域呢?我们需要声明一个内部信号,那就是图片显示有效信号(pic_valid),在有效信号为高电平时,将自ROM读出的图片数据赋值给待显示图像数据(pic_data_out),覆盖彩条背景。

        上文中我们提到ROM读使能信号(rd_en)超前图片显示区域一个时钟周期,可以利用此信号 延迟一个时钟周期生成图片显示有效信号(pic_valid);在有效信号为高电平时,将自ROM读出的图片数据赋值给待显示图像数据(pic_data_out),覆盖彩条背景。信号波形图如下:

3 程序资源 

见压缩包。

  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ROM 是一种只读存储器,可以用来存储程序或数据。在 FPGA 中,我们可以使用 ROM 存储图像数据,然后使用 Verilog 代码将图像显示在屏幕上。下面是一个简单的 Verilog 代码示例,用于将 ROM 中存储的图像数据显示VGA 屏幕上: ``` module image_display( input clk, input rst_n, output reg [7:0] red, output reg [7:0] green, output reg [7:0] blue, output reg hsync, output reg vsync ); // 定义 ROM 存储器和地址计数器 reg [7:0] rom [0:1023]; reg [9:0] rom_addr; // 初始化 ROM 存储器 initial begin $readmemh("image_data.hex", rom); end // VGA 时序计数器 reg [9:0] h_count, v_count; // 初始化 VGA 时序计数器 always @(posedge clk) begin if (!rst_n) begin h_count <= 0; v_count <= 0; end else begin if (h_count == 799) begin h_count <= 0; if (v_count == 524) begin v_count <= 0; end else begin v_count <= v_count + 1; end end else begin h_count <= h_count + 1; end end end // 从 ROM 中读取图像数据 always @(posedge clk) begin if (!rst_n) begin rom_addr <= 0; end else begin if (hsync && vsync) begin rom_addr <= rom_addr + 1; end end end // 将图像数据输出到 VGA 屏幕上 always @(posedge clk) begin if (!rst_n) begin red <= 0; green <= 0; blue <= 0; hsync <= 1; vsync <= 1; end else begin if (hsync && vsync) begin red <= rom[rom_addr][7:5]; green <= rom[rom_addr][4:2]; blue <= rom[rom_addr][1:0]; end else begin red <= 0; green <= 0; blue <= 0; end hsync <= (h_count >= 640 && h_count < 800); vsync <= (v_count >= 480 && v_count < 524); end end endmodule ``` 在这个代码中,我们使用一个 ROM 存储器来存储图像数据,并使用一个地址计数器从 ROM 中读取数据。然后,我们使用一个 VGA 时序计数器来生成 VGA 时序信号,并将图像数据输出到 VGA 屏幕上。请注意,这个代码示例假定您已经将图像数据存储在名为 "image_data.hex" 的 HEX 文件中,您需要根据您的实际情况进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Super_WY_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值