微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > SD卡文件读写

SD卡文件读写

时间:10-02 整理:3721RD 点击:
SD卡文件读写

象棋小子    1048272975

SD卡(Secure Digital Memory Card)具有体积小、容量大、数据传输快、可插拔、安全性好等优点,被广泛应用于便携式设备上。例如作为数码相机的存储卡,作为手机、平板多媒体扩展卡用的TF卡(micro sd)等等。

1. SD卡概述

SD卡技术是在MMC卡的基础上发展起来的,其尺寸与MMC卡一样,只是比MMC卡厚了0.7mm,因此SD主机可以识别并存取MMC卡。SD卡接口除了保留MMC卡的7针外,还在两边加了2针,作为数据线,目的是通过把传输方式由串行变成并行,以提高传输速率。此时的规范为SD1.0版本,最高容量只能到4GB。为了跟进产品的更新换代,SD联合协会在06年发布了容量更大、存储更快的下一代SD卡规范SD2.0。该规范重新定义了SD卡的速度等级,分为三档:Class 2、4、6,分别对应写入速度2MB/S、4MB/S、6MB/S。根据卡容量又分为标准卡(小于2GB)和高容量卡(2GB~32GB),目前市面上应用的SD卡绝大部分都是SD2.0版本的卡。为了让储存卡更加迷你,通过SD卡规范标准,又衍生了MiniSD卡和Micro SD卡,这些卡均比标准SD卡尺寸小,通过SD转接套可以当作一般的SD卡使用。尤其是Micro SD卡,可以算是最小的存储卡了,超小的体积可以极大的节省消费电子产品内部设计的空间,基本目前的Android手机均是选用Micro SD卡作为多媒体扩展储存卡。随着科技的进步,SD2.0规范SD卡也渐渐无法满足应用的需求,在10年SD联合协会又发布了新的SD3.0规范,该规范定义了sdxc和uhs,并增加了Class10,容量范围为32GB~2TB。在sdxc卡仍需进一步坐等其价格下降的情况下,SD4.0规范已经开始在紧张的制订中,这已超出本文的讨论范围内了。

2. SD卡驱动

SD卡共支持三种传输模式:SPI模式、1位SD模式、4位SD模式。所有的SD卡都必须支持较老的SPI/MMC模式,这个模式支持慢速的四线SPI接口,使很多微控制器都可以通过SPI或模拟SPI接口来读写SD卡。万利的LPC5411x开发板通过SPI接口扩展了一个TF卡槽,可以用SPI接口读写TF卡。

SD2.0标准定义了物理层相关规范以及主机控制器规范,SD卡驱动的编写必须参考这两个规范,遵循标准的SD卡均可以采用统一的软件驱动实现数据访问。NXP对于其全系列的芯片提供了sdmmc库中间件用于支持SD/MMC卡的读写,可以在官网下载相应的BSP,里面包含sdmmc库,fsl_sdspi.h/fsl_sdspi.c即为SPI模式访问SD卡的标准驱动,可以直接应用到LPC5411x开发环境中。SD卡驱动最主要实现三个接口,分别是SD卡的识别初始化、SD卡的块读、SD卡的块写,具体实现可以参考fsl_sdspi.h/fsl_sdspi.c驱动文件。

3. Fatfs

数据往往以文件的形式保存在储存设备中,对于SD卡,一般采用的是Fat32文件系统,Fatfs由于其开源免费,支持Fat32,受到了广泛的应用。

Fatfs是由日本工程师ChaN所编写的Fat文件系统模块,从06年发布第一个Fatfs版本开始,作者就从未停止维护和更新。Fatfs的编写遵循ANSI C,并且完全与磁盘I/O层分开。它不依赖于硬件架构,代码和工作区占用空间小,使之可以嵌入到各个低成本的微控制器中,如AVR、8051、PIC、ARM、Z80、68K等。由于SD卡一般使用Fat32文件系统,在使用到SD卡的系统中移植Fatfs,将很好地实现对SD卡文件的管理。

Fatfs模块完全独立于磁盘I/O层,因此底层磁盘I/O访问并不属于Fatfs的模块部分,用户必须自己实现这部分用来访问存储设备。通常在diskio.c中实现这几个函数disk_initialize()、disk_status()、disk_read()、disk_wirte()、disk_ioctl()即可,如果使能了OS相关的特性,则还需额外实现进程/内存函数。其中disk_initialize()对应SD卡驱动中的卡识别初始化接口,disk_read()对应SD卡的块读接口,disk_wirte()对应SD卡的块写接口。NXP对于其全系列的芯片提供了Fatfs中间件的支持,Fatfs对应SD卡驱动接口的具体实现可以参考BSP中已移植好的Fatfs中间件。

4. 读写测试

移植好SD卡驱动以及Fatfs底层对应接口后,就可以用Fatfs应用编程接口读写SD卡里面的文件。应用以2KB大小为读写单位,测试读写10MB大小文件的平均读写速度。

uint8_t TestBuffer[2048];

int main()

{

uint32_t i;

FATFS fs;

FIL file;

FRESULT Res;      

uint32_t TimeCount;

uint32_t ByteWrite, ByteRead;

/* Board pin, clock, debug console init */

/*attach 12 MHz clock to FLEXCOMM0 (debug console) */

CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);

/* enable clock for GPIO*/

CLOCK_EnableClock(kCLOCK_Gpio0);

CLOCK_EnableClock(kCLOCK_Gpio1);

BOARD_InitPins();

BOARD_BootClockFROHF96M();

BOARD_InitDebugConsole();     

Gpio_Init();

f_mount(&fs, "4:" , 0);      

/*

Res = f_mkfs("", 0, 4096);

if (Res != RES_OK) {

       PRINTF("f_mkfs error %d\r\n",Res);

       while(1);

}

*/

PRINTF("Writing test.bin, file sise10MB\r\n");

Res= f_open(&file, "4:test.bin", FA_WRITE | FA_CREATE_ALWAYS);

if (Res != RES_OK) {

       PRINTF("Createfile failed\r\n");

       while(1){

              GPIO_TogglePinsOutput(GPIO,0, 1u << 15);

              Delay_ms(300);                 

       }

}

for (i=0; i<sizeof(TestBuffer); i++){

       TestBuffer= i;

}

TimeCount =timer_get_current_milliseconds();

for (i=0;i<10*1024*1024/sizeof(TestBuffer); i++) {

       Res= f_write(&file, &TestBuffer, sizeof(TestBuffer), &ByteWrite);

       if(Res != RES_OK) {

              f_close(&file);

              PRINTF("Writefile error\r\n");

              while(1){

                     GPIO_TogglePinsOutput(GPIO,0, 1u << 15);

                     Delay_ms(300);

              }

       }

}

f_close(&file);

PRINTF("Sd write speed %dKB/s\r\n", 10*1024*1024/(timer_get_current_milliseconds()-TimeCount));

      

PRINTF("Reading test.bin, file sise10MB\r\n");

Res = f_open(&file, "4:test.bin", FA_READ | FA_OPEN_EXISTING);

if (Res != RES_OK) {

       PRINTF("Openfile failed\r\n");

       while(1){

              GPIO_TogglePinsOutput(GPIO,0, 1u << 15);

              Delay_ms(300);

       }

}

TimeCount =timer_get_current_milliseconds();

for (i=0;i<10*1024*1024/sizeof(TestBuffer); i++) {

       Res= f_read(&file, (unsigned char *)&TestBuffer, sizeof(TestBuffer),&ByteRead);

       if(Res != RES_OK) {

              f_close(&file);

              PRINTF("Readfile error\r\n");

              while(1){

                     GPIO_TogglePinsOutput(GPIO,0, 1u << 15);

                     Delay_ms(300);

              }

       }

}

f_close(&file);

PRINTF("Sd read speed %dKB/s\r\n", 10*1024*1024/(timer_get_current_milliseconds()-TimeCount));

while(1) {

       GPIO_TogglePinsOutput(GPIO,0, 1u << 15);

       Delay_ms(1000);

}

}

读写速度测试结果如下:


                              

SD卡写速度为872 KB/S,读速度为1169 KB/S,SD卡通过SPI接口读写,SPI时钟采用FRO 12M时钟,因此这个读写速度是合适的。SD卡读写速度跟卡速度等级、数据传输速率有关,读写多块要比一块一块分多次读写快,此处测试一次性读取8块(512字节/块),2048字节,读写速度主要受限于SPI的传输速率,LPC5411x的SPI接口最高支持48M的时钟,SPI可以通过采用PLL时钟、内部高速时钟,进一步提高SPI的传输速率,从而进一步提高SD卡的读写速度。

5. 附录

MDK工程,包含SPI模式的SD驱动,Fatfs文件系统模块,SD卡读写速度测试应用例程。

https://pan.baidu.com/s/1cMz1G6


上一篇:仿真时WDT的问题
下一篇:WAV音频文件

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top