学习内容
本文主要关于SD卡相关内容,然后使用SD卡进行TXT文本读写,并用串口打印出读写数据。
开发环境
vivado 18.3&SDK,PYNQ-Z2开发板。
SD卡简介
SD卡(Secure Digital Card):安全数字卡,又叫安全数码卡。有体积小,容量大传输速度快,支持热插拔等特点。在ZYNQ开发板上这里是使用的是TF卡,也就是小卡(micro sd卡)又称TF卡。
SD卡是在 MMC 卡( Multimedia Card,多媒体卡)的基础上发展而来,主要增加了两个特色:更高的安全性和更快的读写速度。SD卡的接口与MMC卡是兼容的,支持SD卡的接口大多支持MMC卡。
下表为不同类型的 SD 卡采用的协议规范、容量等级及支持的文件系统。
SD卡类型 | 协议规范 | 容量等级 | 磁盘格式 |
SDSC | SD1.0 | 上限为2GB | FAT12, FAT16 |
SDHC | SD2.0 | 2GB至32GB | FAT32 |
SDXC | SD3.0 | 32GB至2TB( 2048GB | exFAT |
不同协议规范的 SD 卡有着不同速度等级的表示方法。在 SD1.0 规范中(现已不用),使用“ X”表示不同的速度等级;在 SD2.0 规范中,普通卡和高速卡的速率定义为Class2、Class4、Class6 和Class10 四个等级; SD3.0 规范(又称为超高速卡)使用 UHS( Ultra High Speed)表示不同的速度等级。 不同等级的读写速度和应用如下图所示:
SD 卡共有 9 个引脚线, 共支持三种传输模式:SPI模式(独立序列输入和序列输出),1位SD模式 (独立指令和数据通道,独有的传输格式), 4位SD模式 (使用额外的针脚以及某些重新设置的针脚。支持四位宽的并行传输)。具体的引脚功能定义如下表所示:
MicroSD 卡接口定义以及各引脚功能说明如下图所示。
ZYNQ 内部集成了两个 SD 卡控制器,并且 Xilinx SDK 的 standalone 已经移植好了 FATFS( SDK 软件中叫做 xilffs)文件系统,因此在 SDK 中添加 xilffs 库后, 就可以在程序中使用 FATFS 中的 API 函数来操作 SD 卡。
SD 卡控制器( SD/SDIO Controller)
SD/SDIO控制器与SDIO设备、SD存储卡和MMC卡通信,最多有4条数据线。SD接口可以使用一条 (dat0)或四条(dat0- dat3)行进行数据传输。SDIO接口可以通过MIO多路复用到MIO引脚或通过PL中的EMIO进行lO引脚分配。
ZYNQ 中的 SD 卡控制器符合 SD2.0 协议规范, 接口兼容 eMMC、 MMC3.31、 SDIO2.0、 SD2.0、 SPI,支持 SDHC、 SDHS 器件。 SD 卡控制器支持 SDMA(单操作 DMA)、 ADMA1( 4K 边界限制 DMA)和ADMA2( 在 32 位系统中允许任何位置和任意大小)。
SD/SDIO控制器由ARM处理器通过AHB总线访问。该控制器还包括一个DMA单元与内部FIFO以满足吞吐量要求。
SD/SDIO控制器的框图如下:
SD控制器使用两个512字节深度的双端口FIFO执行写和读操作。SD 控制器读写通道采用独立的 512 字节深度的双缓冲 FIFO 执行读和写操作。在写操作时,处理器向
其中一个 FIFO 写数据,将另一个 FIFO 的数据写到 SD 总线;在读操作时, SD 总线上的数据向其中一个FIFO 写数据,处理器将数据从另一个 FIFO 读出数据。 SD 卡控制器通过双缓冲机制以保证最大带宽。
FATFS文件系统
负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。即在磁盘上组织文件的方法。常见的文件系统有FAT/FATFS(FATFS 是一个完全开源免费的 FAT 文件系统模块)、NTFS(基于安全性的文件系统,是Windows NT采用的独特的文件系统结构)、CDFS(CDFS是大部分光盘的文件系统)、exFAT(扩展性的文件系统)。
FATFS是一个可以裁剪的文件系统,专门为小型的嵌入式系统而设计。它完全用标准 C语言编写,结构清晰,代码量小,文件系统和IO底层分开,所以具有良好的硬件平台独立性,可以很方便的移植到各种嵌入式处理器中,也很适合新手进行入门学习。支持最多10个逻辑盘符和两级文件夹;可以支持FAT12、FAT16和FAT32,支持多个存储媒介。
FATFS 模块的层次结构如下:
- 最顶层:应用层,使用者无需理会 FATFS 的内部结构和复杂的 FAT 协议,只需要调用 FATFS 模块提供给用户的一系列应用接口函数,如 f_open, f_read, f_write 和 f_close 等,就可以像在 PC 上读/写文件那样简单。
- 中间层 :FATFS 模块,实现了 FAT 文件读/写协议。使用者一般不用修改,使用时将头文件直接包含进去即可。
- 底层接口,包括存储媒介读/写接口( disk I/O)和供给文件创建修改时间的实时时钟。需要根据平台和存储介质编写移植代码。关于文件系统的函数API使用可以通过下面这个网址进行学习入门:FATFS 学习网址Xilinx SDK 的standalone 已经移植好了 FATFS 文件系统,因此在 SDK 中添加 xilffs 库后, 就可以在程序中使用 FATFS 中的 API 函数来操作 SD 卡。
系统框图
本次工程只使用了PS端的资源,通过 Xilinx SDK 自带的 FATFS 库,完成对 SD卡中 TXT 文本读写的功能,并将读写测试结果通过串口打印出来。系统框图如下:
硬件平台搭建
新建工程,创建 block design。添加ZYNQ7 IP,对zynq进行初始化配置,勾选sd,uart资源,
设置BANK的电平,
取消勾选多余资源,点击OK,完成硬件设计。如下图:
然后我们进行generate output product 然后生成HDL封装。这里没有进行使用PL资源,也不需要进行综合布局,在导出硬件时也不用包含bit流文件。
SDK软件部分
打开SDK后,新建application project。选中工程右击选中设置板载支持文件模式。
这里选择xilffs模式,
点击standalone下的xilffs,可以对文件系统进行配置,这里可以使能长文件名有效,改变勾选为true。
完成配置后点击ok。
在main.c中输入以下代码:
#include "stdio.h" #include "xparameters.h" #include "ff.h" #include "string.h" #define FILE_NAME "vuko.txt" char str_wr[100]= "this is a sd read and write test~"; char str_rd[100]=""; FATFS fs; void sd_mount(); void sd_write_data(char wr_dat[], u32 wr_len); void sd_read_data(char rd_dat[], u32 rd_len); int main(){ u32 len; sd_mount(); len=strlen(str_wr); //写数据 sd_write_data(str_wr,len); //读数据 sd_read_data(str_rd,len); if(strcmp(str_rd,str_wr)==0){ printf("%s\n",str_rd); printf("sd card test success!\n"); } else printf("sd card test fail!\n"); return 0; } //挂载sd卡 void sd_mount(){ FRESULT status; BYTE work[FF_MAX_SS]; //挂载sd卡,注册文件系统对象 status=f_mount(&fs,"",1); if(status != FR_OK){ printf("%d\n",status); printf("It isn't FAT format\n"); f_mkfs("",FM_FAT32,0,work,sizeof work); f_mount(&fs,"",1); } } //写数据 void sd_write_data(char wr_dat[], u32 wr_len){ FIL fil; UINT bw; //创建或者打开文件 f_open(&fil,FILE_NAME,FA_CREATE_ALWAYS | FA_WRITE | FA_READ); //移动读写指针 f_lseek(&fil, 0); //写数据 f_write(&fil,wr_dat,wr_len,&bw); //关闭文件 f_close(&fil); } //读数据 void sd_read_data(char rd_dat[], u32 rd_len){ FIL fil; UINT br; //创建或者打开文件 f_open(&fil,FILE_NAME,FA_READ); //移动读写指针 f_lseek(&fil, 0); //读取数据 f_read(&fil,rd_dat,rd_len,&br); //关闭文件 f_close(&fil); }
整体代码思路
该工程代码主要实现三个函数,分别是挂载SD卡,读取SD卡和写入SD卡。在main函数中首先完成对SD卡的挂载,然后向指定文件内写入的字符串数据,通过SD卡读取函数把SD卡中指定文件的数据读到数组中,完成数据的读取后将写入的字符串数据和读取出来的字符串数据进行对比,对比一致后,用串口打印测试成功的标识。
部分代码讲解
对于具体的读写函数的使用,我们可以进行参考下面这个网址进行学习:FATFS 学习网址
可以参考对应的读写函数的使用示例进行辅助开发设计。
对于写入SD卡函数编写:
首先我们要进行创建或者打开文件,这里引入文件的结构体,使用f_open()函数进行打开,将读写的指针移动到到指定位置,这里使用f_lseek(&fil, 0);把光标移动到初始位置。然后使用写入函数进行写入数据f_write(&fil,wr_dat,wr_len,&bw);完成写入后,关闭文件f_close(&fil);
读取SD卡函数和写入的思路类似,对于挂载函数来说,使用status=f_mount(&fs,"",1);注册文件系统对象,如果读取返回值不是FAT文件系统,则使用f_mkfs("",FM_FAT32,0,work,sizeof work); 把SD卡进行初始化。
运行结果
串口数据:
Reference
- 正点原子ZYNQ开发视频
- xilinx UG585