百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

正点原子开拓者FPGA开发板资料连载第四十章 SD卡图片显示实验

cac55 2025-06-28 12:27 18 浏览 0 评论

1)实验平台:正点原子开拓者FPGA 开发板

2)摘自《开拓者FPGA开发指南》关注官方微信号公众号,获取更多资料:正点原子

3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-13912-1-1.html

第四十章 SD卡图片显示实验(VGA显示)

在“SD卡读写测试实验”中,我们成功地在开发板上实现了对SD卡的读写测试。本章我们

将使用FPGA开发板实现从SD卡中读取两张图片,并通过VGA接口在显示器上循环切换显示两张

图片的功能。

本章包括以下几个部分:

40.1 SD卡-VGA图片显示简介

40.2 实验任务

40.3 硬件设计

40.4 程序设计

40.5 下载验证

SD卡-VGA图片显示简介

我们在“SD卡读写测试实验”中介绍过,SD卡在SD2.0版本协议下,SPI模式的理论最大传

输速率为50Mbps,在SDIO模式下理论传输速率为200Mbps,加上命令号以及等待SD卡返回响应

信号的时间,实际上的传输速率会比理论传输速率下降不少。对于采用分辨率为640*480@60Hz

的显示器来说,一幅图像的数据量达到640*480*16bit=4915200bit=4800Kbit(1Kbit=1024bit),

每秒钟刷新60次,那么每秒钟需要传输的数据量达到4800Kbit*60=288000Kbit=281.25Mbit

(1Mbit=1024Kbit)。由此可以看出,SD卡的读写速度完全跟不上VGA的数据发送速度,因此

必须先缓存一幅图像,再通过VGA接口显示。我们在前面多次提到过,FPGA的片内存储资源较

少,对于缓存如此大量的数据,只能使用开发板上的SDRAM存储器缓存数据。

本次实验使用SDRAM存储器来缓存图片数据,图片数据来自于SD卡,那么我们就需要事先

向SD卡中导入两张图片,也就是从电脑中拷贝两张图片放入SD卡。如果是Micro SD卡(TF卡),

需要将先将Micro SD卡插入读卡器中,再将读卡器插入电脑的USB接口。如果是SD卡,可以直

接将SD卡插入电脑的SD卡插槽内(有些电脑可能没有此接口),也可以插入支持SD卡的读卡器

中。

VGA的显示格式为16位RGB565格式,为了使SD卡读出的数据可以直接在VGA上显示,我们需

要将图片通过“IMG2LCD”上位机软件转成16位的RGB565格式的bin文件,再将bin文件导入SD

卡中。然后使用WinHex软件查看两个bin文件的扇区地址,此时查询到的扇区地址就是bin文件

存放的起始扇区地址,我们只需要按照这个起始扇区地址,按顺序读出SD卡中的数据即可,直

到读完一张图片中的所有数据。SD卡中一个扇区存放512个字节,也就是256个16位数据,对于

分辨率为640*480的图片来说,共需要读出1200(640*480/256)个扇区数据。

我们在“SD卡读写测试实验”中对SD卡的协议规范作了详细的介绍,包括SD卡的接口说明、

初始化以及读写操作等。如果大家对这部分内容不是很熟悉的话,请参考“SD卡读写测试实验”

中的SD卡简介部分。

实验任务

本节实验任务是使用FPGA开发板循环读取SD卡中存储的两张图片(bin格式图片,分辨率

为640*480),然后将图片存储在SDRAM中并通过VGA接口在显示器上循环切换显示。

硬件设计

SD卡接口部分的硬件设计请参考“SD卡读写测试实验”中的硬件设计部分。

由于SDRAM、SD卡接口和VGA接口的引脚数目较多且在前面相应的章节中已经给出它们的管

脚列表,这里不再列出管脚分配。

程序设计

图 40.4.1是根据本章实验任务画出的系统框图。PLL时钟模块为其它各模块提供驱动时

钟;SD卡读取图片控制模块控制SD卡控制器的读接口;SD卡控制器从SD卡中读出图像数据,并

将读出的数据写入SDRAM控制器;最后VGA驱动模块通过SDRAM控制器读取SDRAM中存储的图片数

据并通过VGA接口显示在显示器上。

图 40.4.1 SD卡图片显示实验(VGA显示)系统框图

顶层模块的原理图如下图所示:

图 40.4.2 顶层模块原理图

FPGA顶层模块(top_sd_photo_vga)例化了以下五个模块:PLL时钟模块(pll_clk)、SD

卡读取图片控制模块(sd_read_photo)、SD卡控制器模块(sd_ctrl_top)、SDRAM控制器模

块(sdram_top)和VGA驱动模块(vga_driver)。

顶层模块(top_sd_photo_vga):顶层模块主要完成对其余各模块的例化,实现各模块之

间的数据交互。需要注意的是,系统初始化完成是在SD卡以及SDRAM都初始化完成后才开始拉

高的,该信号控制着SD卡读取图片控制模块的复位信号,因此SD卡读取图片控制模块是在系统

初始化完成后才工作的,防止因SD卡或者SDRAM初始化未完成导致数据错误。

PLL时钟模块(pll_clk):PLL时钟模块通过调用锁相环(PLL)IP核实现,总共输出五个

时钟,频率分别为100Mhz、100Mhz(相位偏移-75度)、50Mhz、50Mhz(相位偏移180度)和25Mhz。

两个100Mhz的时钟用于为SDRAM控制器模块提供驱动时钟;两个50Mhz的时钟用于为SD卡控制器

模块提供驱动时钟,其中50mhz为SD卡读取图片控制模块提供驱动时钟;25Mhz用于为VGA驱动

模块提供驱动时钟。

SD卡读取图片控制模块(sd_read_photo):SD卡读取图片控制模块通过控制SD卡控制器

的读接口,从SD卡中读取图像数据,并在读完一张图片后延时一段时间,再去读取另一张图片

数据,实现两张图片的循环切换读取。

SD卡控制器模块(sd_ctrl_top):SD卡控制器模块负责驱动SD卡,该模块将SD卡的SPI读

写操作封装成方便用户使用的接口。有关该模块的详细介绍请大家参考“SD卡读写测试实验”

章节。

SDRAM读写控制模块(sdram_top):SDRAM读写控制器模块负责驱动SDRAM片外存储器,缓

存图像传感器输出的图像数据。该模块将SDRAM复杂的读写操作封装成类似FIFO的用户接口,

非常方便用户的使用。

VGA驱动模块(vga_driver):VGA驱动模块根据VGA时序参数输出行、场同步信号;同时

它还要输出数据请求信号用于读取SDRAM中的图片数据,并将图片通过VGA接口显示。

SD卡读取图片控制模块的代码如下:

1 module sd_read_photo(

2 input clk , //时钟信号

3 input rst_n , //复位信号,低电平有效

4

5 input rd_busy , //SD卡读忙信号

6 output reg rd_start_en , //开始写SD卡数据信号

7 output reg [31:0] rd_sec_addr //读数据扇区地址

8 );

9

10 //parameter define

11 parameter PHOTO_SECCTION_ADDR0 = 32'd8256; //第一张图片扇区起始地址

12 parameter PHOTO_SECTION_ADDR1 = 32'd9472 ; //第二张图片扇区起始地址

13 //640*480/256 = 1200

14 parameter RD_SECTION_NUM = 11'd1200 ; //单张图片总共读出的次数

15

16 //reg define

17 reg [1:0] rd_flow_cnt ; //读数据流程控制计数器

18 reg [10:0] rd_sec_cnt ; //读扇区次数计数器

19 reg rd_addr_sw ; //读两张图片切换

20 reg [25:0] delay_cnt ; //延时切换图片计数器

21

22 reg rd_busy_d0 ; //读忙信号打拍,用来采下降沿

23 reg rd_busy_d1 ;

24

25 //wire define

26 wire neg_rd_busy ; //SD卡读忙信号下降沿

27

28 //*****************************************************

29 //** main code

30 //*****************************************************

31

32 assign neg_rd_busy = rd_busy_d1 & (~rd_busy_d0);

33

34 //对rd_busy信号进行延时打拍,用于采rd_busy信号的下降沿

35 always @(posedge clk or negedge rst_n) begin

36 if(rst_n == 1'b0) begin

37 rd_busy_d0 <= 1'b0;

38 rd_busy_d1 <= 1'b0;

39 end

40 else begin

41 rd_busy_d0 <= rd_busy;

42 rd_busy_d1 <= rd_busy_d0;

43 end

44 end

45

46 //循环读取SD卡中的两张图片(读完之后延时1s再读下一个)

47 always @(posedge clk or negedge rst_n) begin

48 if(!rst_n) begin

49 rd_flow_cnt <= 2'd0;

50 rd_addr_sw <= 1'b0;

51 rd_sec_cnt <= 11'd0;

52 rd_start_en <= 1'b0;

53 rd_sec_addr <= 32'd0;

54 end

55 else begin

56 rd_start_en <= 1'b0;

57 case(rd_flow_cnt)

58 2'd0 : begin

59 //开始读取SD卡数据

60 rd_flow_cnt <= rd_flow_cnt + 2'd1;

61 rd_start_en <= 1'b1;

62 rd_addr_sw <= ~rd_addr_sw; //读数据地址切换

63 if(rd_addr_sw == 1'b0)

64 rd_sec_addr <= PHOTO_SECCTION_ADDR0;

65 else

66 rd_sec_addr <= PHOTO_SECTION_ADDR1;

67 end

68 2'd1 : begin

69 //读忙信号的下降沿代表读完一个扇区,开始读取下一扇区地址数据

70 if(neg_rd_busy) begin

71 rd_sec_cnt <= rd_sec_cnt + 11'd1;

72 rd_sec_addr <= rd_sec_addr + 32'd1;

73 //单张图片读完

74 if(rd_sec_cnt == RD_SECTION_NUM - 11'b1) begin

75 rd_sec_cnt <= 11'd0;

76 rd_flow_cnt <= rd_flow_cnt + 2'd1;

77 end

78 else

79 rd_start_en <= 1'b1;

80 end

81 end

82 2'd2 : begin

83 delay_cnt <= delay_cnt + 26'd1; //读取完成后延时1秒

84 if(delay_cnt == 26'd50_000_000 - 26'd1) begin //50_000_000*20ns = 1s

85 delay_cnt <= 26'd0;

86 rd_flow_cnt <= 2'd0;

87 end

88 end

89 default : ;

90 endcase

91 end

92 end

93

94 endmodule

在代码的第11行至第14行定义了三个参数,PHOTO_SECTION_ADDR0(第一张图片扇区起始

地址)、PHOTO_SECTION_ADDR1(第二张图片扇区起始地址)和RD_SECTION_NUM(单张图片总

共读出的次数)。其中PHOTO_SECTION_ADDR0和PHOTO_SECTION_ADDR1是由WinHex软件查看得到

的两 张图 片的 扇区 起始 地址 ,具 体查 看的 方法 我们 在下 载验 证部 分再 详细 讲解。

RD_SECTION_NUM是读取单张图片总共需要读取的次数,即扇区数。单张图片的分辨率为640*480,

位宽为16位,读取一个扇区的字节数为512个字节,共256个16bit,所以单张图片需要读取的

扇区数为640*480/256=1200。

在代码的第47行开始的always语句块中,实现的功能是根据第一张图片的扇区地址向SD卡

控制器模块发送读命令,读完后延时1秒钟,并根据第二张图片的扇区地址向SD卡控制器模块

发送读命令,读完后再次延时1秒钟,并根据第一张图片的扇区地址向SD卡控制器模块再次发

送读命令,就这样循环往复读取SD卡中的两张图片。这个功能是由代码中定义的读流程控制计

数器(rd_flow_cnt)来实现,读忙信号的下降沿(neg_rd_busy)表示当前扇区读取完成,可

以进行其它操作。


图 40.4.3为控制SD卡读取图片过程中SignalTap抓取的波形图。

由图可知,在rd_sec_cnt(读扇区个数计数器)的值为1199(1200-1)时表示当前读取的是图片的最后一个扇区的数据,

rd_busy(读忙信号)拉低后,单张图片的最后一个扇区地址读完,此时rd_flow_cnt加1,延

时计数器(delay_cnt)开始计数,等待延时完成后读取下一张图片。

图 40.4.3 控制SD卡读取图片SignalTap波形图

下载验证

首先我们打开SD卡图片显示实验(VGA显示)工程,在工程所在的路径下打开

top_sd_photo_vga/par文件夹,在里面找到“top_sd_photo_vga.qpf”并双击打开。注意工程

所在的路径名只能由字母、数字以及下划线组成,不能出现中文、空格以及特殊字符等。工程

打开后如图 40.5.1所示:

图 40.5.1 SD卡图片显示实验(VGA显示)工程

在打开下载界面之前,我们还需要先做一些准备工作,也就是向SD卡中导入bin格式的图

片。首先来介绍一下如何利用工具“Img2Lcd”将图片转成bin文件,该工具位于开发板所随附

的资料“6_软件资料/1_软件/Img2Lcd”目录下找到“Img2Lcd.exe”并双击打开,软件打开后

界面如图40.5.2所示。

在菜单栏中点击“打开”,然后在弹出的界面中选择一幅分辨率为640*480的jpg格式图片。

图片加载进来之后,在工具界面左侧设置输出数据类型为“二进制(*.bin)”,输出灰度为“16

位真彩色”,最大宽度和高度分别为“640”和“480”,选中高位在前(MSB First)。设置

完成后在菜单栏中点击“保存”,并在弹出的界面中选择bin文件的保存路径并输入文件名。

图 40.5.2 Img2Lcd工具界面

到这里我们已经成功地将第一张图片转成了bin文件,因为我们实现的功能是两张图片循

环切换显示,因此需要通过上面的方法再生成一个bin文件。此时,两张bin格式的图片文件制

作完成。

SD卡在经过多次存放数据与删除数据之后,存入的文件有可能不是按照连续的扇区地址存

储的,为了避免图片显示错误,我们将bin文件导入SD卡之前,先把SD卡格式化,格式化的设

置如图 40.5.3所示,然后点击开始按钮完成格式化。

图 40.5.3 SD卡格式化界面

接下来我们将生成的两个bin文件拷贝到SD卡中,拷贝完成后如下图所示:


图 40.5.4 SD卡bin文件拷贝完成

文件拷贝完成后,接下来我们使用WinHex工具软件查看这两个文件的扇区起始地址,该工

具位于开发板所随附的资料中“6_软件资料/1_软件/WinHex”目录下,双击“WinHex.exe”或

者“WinHex64.exe”打开软件。软件打开后,在菜单栏中点击“工具”,然后点击“打开磁盘”,

如下图所示。

图 40.5.5 WinHex打开界面


图 40.5.6 WinHex磁盘打开界面

在“物理驱动器”下,我们看到箭头2所指的地方有RM2、SD/MMC(7.5GB,USB)的字样,

可知该物理驱动器对应的是SD卡,标号为RM2,我们找到标号RM2在逻辑驱动器中的位置,即箭

头1所指的地方,选中后点击“确定”按钮即可查看文件的起始扇区地址,打开后的界面如下图所示:


图 40.5.7 WinHex查看扇区起始地址界面

由 上图可知,两张 bin 格式图片的起始扇区地址分别为 8256 和 9472 , 这和我们

sd_read_photo 模 块 定 义 的 PHOTO_SECTION_ADDR0 = 32'd8256 , PHOTO_SECTION_ADDR1 =

32'd9472是一致的。如果查看的值不是上图中的值,需要将代码中定义的这两个参数值改成

WinHex查看的扇区地址,然后重新编译工程。

接下来我们将SD卡适配器(用于插入MicroSD卡)或者SD卡插入开发板的SD卡插槽,注意

带有金属引脚的一面朝上;然后将VGA连接线一端连接显示器,另一端与开发板上的VGA接口连

接;接下来将下载器一端连接电脑,另一端与开发板上对应端口连接,最后连接电源线并打开

电源开关。

接下来我们下载程序,验证SD卡的VGA图片显示功能。工程打开后通过点击工具栏中的

“Programmer” 图 标 打 开 下 载 界 面 , 通 过 “Add File” 按 钮 选 择 top_sd_photo_vga

/par/output_files目录下的“top_sd_photo_vga.sof”文件。开发板电源打开后,在程序下

载界面点击 “Hardware Setup” ,在弹出的对话框中选择当前的硬件连接为“USB

Blaster[USB-0]”。然后点击“Start”将工程编译完成后得到的sof文件下载到开发板中,如

图 40.5.所示:

图 40.5.8 程序下载完成界面

程序下载完成后,此时显示器上循环切换显示SD卡中的两张图片,说明SD卡图片显示实验

(VGA显示)下载验证成功。如图 40.5.8和图 40.5.9所示:


图 40.5.8 VGA器显示第一张图片

图 40.5.9 VGA器显示第二张图片

相关推荐

Mac电脑强制删除任何软件方法-含自启动应用

对于打工者来说,进入企业上班使用的电脑大概率是会被监控起来,比如各种流行的数据防泄漏DLP,奇安信天擎,甚至360安全卫士,这些安全软件你想卸载是非常困难的,甚至卸载后它自己又安装回来了,并且还在你不...

Linux基础知识 | 文件与目录大全讲解

1.linux文件权限与目录配置1.文件属性Linux一般将文件可存取的身份分为三个类别,分别是owner/group/others,且三种身份各read/write/execute等权限文...

文件保护不妥协:2025 年 10 款顶级加密工具推荐

数据安全无小事,2025年这10款加密工具凭借独特功能脱颖而出,从个人到企业场景全覆盖,第一款为Ping32,其余为国外英文软件。1.Ping32企业级加密核心工具,支持200+文件格...

省心省力 一个软件搞定系统维护_省心安装在哪里能找到

◆系统类似于我们居住的房间,需要经常打理才能保持清洁、高效。虽然它本身也自带一些清理和优化的工具,但借助于好用的第三方工具来执行这方面的任务,会更让人省心省力。下面笔者就为大家介绍一款集多项功能于一身...

JAVA程序员常用的几个工具类_java程序员一般用什么软件写程序

好的工具做起事来常常事半功倍,下面介绍几个开发中常用到的工具类,收藏一下,也许后面真的会用到。字符串处理:org.apache.commons.lang.StringUtilsisBlank(Char...

手工解决Windows10的若干难题_windows10系统卡顿怎么解决

【电脑报在线】很多朋友已经开始使用Win10,估计还只是测试版本的原因,使用过程中难免会出现一些问题,这里介绍解决一些解决难题的技巧。技巧1:让ProjectSpartan“重归正途”从10074...

System32文件夹千万不能删除,看完这篇你就知道为什么了

C:\Windows\System32目录是Windows操作系统的关键部分,重要的系统文件存储在该目录中。网上的一些恶作剧者可能会告诉你删除它,但你不应该尝试去操作,如果你尝试的话,我们会告诉你会发...

Windows.old 文件夹:系统备份的解析与安全删除指南

Windows.old是Windows系统升级(如Win10升Win11)或重装时,系统自动在C盘创建的备份文件夹,其核心作用是保留旧系统的文件、程序与配置,为“回退旧系统”提供保...

遇到疑难杂症?Windows 10回收站问题巧解决

回收站是Windows10的一个重要组件。然而,我们在使用过程中,可能会遇到一些问题。例如,不论回收站里有没有文件,都显示同一个图标,让人无法判别回收站的空和满的真实情况;没有了像Windows7...

卸载软件怎么彻底删掉?简单几个步骤彻底卸载,电脑小白看过来

日常工作学习生活中,我们需要在安装一些软件程序,但随着软件的更新迭代速度,很多时候我们需要重新下载安装新的程序,这时就需要将旧的一些软件程序进行卸载。但是卸载软件虽然很简单,但是很多小伙伴们表示卸载不...

用不上就删!如何完全卸载OneDrive?

作为Windows10自带的云盘,OneDrive为资料的自动备份和同步提供了方便。然而,从隐私或其他方面考虑,有些人不愿意使用OneDrive。但Windows10本身不提供直接卸载OneDri...

【Linux知识】Linux下快速删除大量文件/文件夹方法

在Linux下,如果需要快速删除大量文件或文件夹,可以使用如下方法:使用rm命令删除文件:可以使用rm命令删除文件,例如:rm-rf/path/to/directory/*这个命令会递...

清理系统不用第三方工具_清理系统垃圾用什么软件

清理优化系统一定要借助于优化工具吗?其实,手动优化系统也没有那么神秘,掌握了方法和技巧,系统清理也是一件简单和随心的事。一方面要为每一个可能产生累赘的文件找到清理的方法,另一方面要寻找能够提高工作效率...

系统小技巧:软件卸载不了?这里办法多

在正常情况下,我们都是通过软件程序组中的卸载图标,或利用控制面板中的“程序和功能”模块来卸载软件的。但有时,我们也会发现利用卸载图标无法卸载软件或者卸载图标干脆丢失找不到了,甚至控制面板中卸载软件的功...

麒麟系统无法删除文件夹_麒麟系统删除文件权限不够

删除文件夹方法例:sudorm-rf文件夹名称。删除文件方法例:sudorm-r文件名包括扩展名。如果没有权限,给文件夹加一下权限再删。加最高权限chmod775文件名加可执行权限...

取消回复欢迎 发表评论: