ZYNQ+FPGA读取SD卡BMP图片并通过HDMI显示

Change Log

2020年5月5日:初次发布。
2021年2月7日:更新实现细则。

代码下载

https://github.com/qiweiii-git/qwi06_sdp2hdmi

代码编译

1.在linux下使用./makeall.sh即可自动编译vivado工程。
如何使用linux自动编译工程请参考利用Linux自动编译Vivado工程
2.在Windows下打开vivado,运行source run.tcl即可自动创建工程并编译。

1 系统框图

在这里插入图片描述

最终显示的图片
在这里插入图片描述
要实现读取SD卡中的BMP图片并通过HDMI显示这个功能,主要有两个重点:
1.SD卡的BMP图片如何读取出来。
2.BMP图片读取出来之后如何通过HDMI显示。
接下来将会对这两点进行详细说明。需要说明的是,第一点主要涉及的是软件代码,而第二点主要涉及的是逻辑代码。

2 BMP图片格式

BMP是英文Bitmap(位图)的简写,对图像几乎不压缩,因此图片信息较丰富,但缺点也很明显,就是文件占用内存大。普通的JPG的图片可能只有几十或者几百KBytes,而一张1920x1080的RGB888的BMP图片将高达1920x1080x24=49766400bits=6.22Mbytes。
在我们的实例中,我们使用BMP图片的好处是BMP图片转成二进制数据即为像素点数据,而不需要解压缩,而普通的JPEG或PNG图片,我们转成二进制数据后,还需要额外进行解压缩,图片的压缩和解压缩不是我们这个实例的重点。
BMP图片的格式为:
在这里插入图片描述
我们通过实例分析,如下图中我们用到的wildhunt.bmp图片数据。BMP文件头一共54bytes,我们可以选中前54bytes来分析。我们最需要关心的是图片的长宽和色彩模式。第19~22bytes为图像宽度,即80 07 00 00,即00 00 07 80 = 0x780=1920,第23~26bytes为图像高度,即38 04 00 00,即00 00 04 38=0x438=1080,第29~30bytes为图像位宽,即18 00,即00 18=0x18=24位。即本BMP图片为1920x1080的RGB888的未压缩图片。
在这里插入图片描述

3 HDMI显示

HDMI的显示标准不是本实例的重点,将不深入挖掘。但我们需要知道,无论是我们通过何种方式将我们想要显示的数据送到HDMI端口,使其能够在HDMI显示器上显示出来(这里的“方式”指的是将数据转化为HDMI显示标准信号,如TMDS标准电平信号,我们可通过FPGA器件商如Xilinx公司提供的HDMI IP核,或者github中的一些开源代码来实现这一点),需要显示的数据都必须满足一定的格式,我们称之为帧格式。也就是说,我们将满足了HDMI帧格式的数据送到“某些模块”中,那些模块就会将数据转化为HDMI显示标准信号最终输出至HDMI端口上。在本实例中,这个“某些模块”指的是Digilent公司的rgb2dvi模块,这个将HDMI帧格式数据转化为HDMI显示标准信号不是本实例的重点,因此这个rgb2dvi模块将不赘述。
参考标准,EIA-CEA-861-D中对HDMI帧格式的描述,不同分辨率,帧格式是不一样的。
我们以1920x1080p30为例。
在这里插入图片描述
我们看到,1920是一行的有效像素点数,而除了有效像素点数,还存在280的消隐像素点,称为行消隐。1080是一帧的有效像素行数,除了有效像素行数外,还存在45行消隐像素行,称为场消隐。通过HSYNC及VSYNC来表示行场消隐区的位置。也就是说,1920x1080的图像带上消隐是2200x1125的图像。
在我们的数据送到rgb2dvi模块前,需要满足这个格式。在代码中,hdmi_vtg模块专门用来产生不同分辨率的HSYNC,VSYNC,active(即图中的Data Enable)信号等,而axis2native模块则是将AXI-Stream总线形式的数据(本实例中,此AXI-Stream携带的数据即为BMP图片像素数据)填充到画面帧的active区,即2200x125中的1920x1080活动区,并带上vsync,hsync等信号。
在这里插入图片描述
在这里插入图片描述

4 BMP图片读取

第二章中讲到了BMP图片的格式,第三章讲到了如何把一张图片显示到HDMI上,剩下的问题点就是怎么把BMP图片读取出来,以AXI-Stream总线的形式送到axis2native模块了。

第一点,BMP图片从哪里来:从SD卡中来。

我们将需要显示的图片放置在SD卡中,注意ZYNQ必须要使能SD卡接口,不然无法读取。

第二点:BMP图片如何读取:软件代码通过f_open打开图片,通过f_read读取图片。

注意需要编译代码时需要使能xilffs库,才能使用f_open等的文件操作函数。

第三点:BMP图片读取后放到哪里:放到外部DDR缓存中。

通过Xil_DCacheFlushRange函数,将读取出来的图片像素数据全部放入DDR缓存中。

第四点:DDR缓存中的数据如何读出并以AXI-Stream总线的形式送到axis2native模块:通过Xilinx的VDMA IP核。

Xilinx提供的VDMA IP核可将DDR缓存中的某一块区域的数据读出以AXI-Stream总线的形式送出去,我们将这些信号连接至axis2native模块中。

猜你喜欢

转载自blog.csdn.net/u011239266/article/details/105939756