赞
踩
本专栏争取每周三更新直到更新完成,期待大家的订阅关注,欢迎互相学习交流。
本文需要一些SD卡的前置知识,后续文章会介绍,这里先介绍一下FATFS文件系统。关于FATFS的文章分为上下两篇,上篇主要介绍什么是FAT文件系统以及FATFS的移植,下篇主要介绍FATFS的一些API函数。
通常我们买来一张全新的SD卡时,如果我们想把它通过读卡器插入到电脑使用,我们需要先对其格式化,这是因为Windows系统使用的是FAT文件系统,我们格式化SD卡,实际也就是在SD卡中建立一个FAT文件系统,这样我们的电脑才能识别它。
FAT是一个专门为小型的嵌入式系统设计的,完全用标准C语言编写,完全免费开源的文件系统。FAT具有良好的硬件平台独立性,可以移植到C51、PIC、ARM等单片机上,而且只需要做一些简单的修改,使用起来非常方便。
FATFS有以下特点
这里简单说明一下几个名词,仅供参考,大家可以自行搜索了解更多详细内容。
上面提到的卷指的是是硬盘上的存储空间,一个硬盘包括好多卷,一卷也可以跨越许多磁盘。卷又分为很多种,比如启动卷、跨区卷、带区卷等。此外还有簇,指的是磁盘文件存储管理的最小单位。
Unicode(Universal Multiple-Octet Coded Character Set)简称UCS,中文意思是统一码,或者叫万国码,可以简单理解为他就是一个数字映射表,每一个数字代表不同的字符或文字。
下面我们介绍一下如何移植FATFS。首先我们需要下载到它的源码,有需要的友友可以私信获取。下载完成后打开其中的“src”文件夹,其中是我们需要的源码。我们在移植FATFS模块的时候,一般只需要修改ffconf.h 和 diskio.c这两个文件。
上面在介绍源码文件时提到,FATFS模块的所有配置项都是存放在 ffconf.h 里面,我们这里再介绍一些重要的配置选项。
想要将FATFS移植到STM32实际并不复杂,主要分为三步
通常最后一步我们需要编写六个底层的接口函数,下面我们来详细地介绍一下它们。
//初始化磁盘 DSTATUS disk_initialize ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { u8 res=0; switch(pdrv) { case SD_CARD://SD卡 res=SD_Init();//SD卡初始化 break; case EX_FLASH://外部flash W25QXX_Init(); FLASH_SECTOR_COUNT=2048*12;//W25Q1218,前12M字节给FATFS占用 break; default: res=1; } if(res)return STA_NOINIT; else return 0; //初始化成功 }
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
FATFS只使用前两个返回值。
//获得磁盘状态
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
return RES_OK;
}
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
//读扇区 //pdrv:磁盘编号0~9 //*buff:数据接收缓冲首地址 //sector:扇区地址 //count:需要读取的扇区数 DRESULT disk_read ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE *buff, /* Data buffer to store read data */ DWORD sector, /* Sector address in LBA */ UINT count /* Number of sectors to read */ ) { u8 res=0; if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误 switch(pdrv) { case SD_CARD://SD卡 res=SD_ReadDisk(buff,sector,count); while(res)//读出错 { SD_Init(); //重新初始化SD卡 res=SD_ReadDisk(buff,sector,count); //printf("sd rd error:%d\r\n",res); } break; case EX_FLASH://外部flash for(;count>0;count--) { W25QXX_Read(buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE); sector++; buff+=FLASH_SECTOR_SIZE; } res=0; break; default: res=1; } //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值 if(res==0x00)return RES_OK; else return RES_ERROR; }
//写扇区 //pdrv:磁盘编号0~9 //*buff:发送数据首地址 //sector:扇区地址 //count:需要写入的扇区数 #if _USE_WRITE DRESULT disk_write ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ const BYTE *buff, /* Data to be written */ DWORD sector, /* Sector address in LBA */ UINT count /* Number of sectors to write */ ) { u8 res=0; if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误 switch(pdrv) { case SD_CARD://SD卡 res=SD_WriteDisk((u8*)buff,sector,count); while(res)//写出错 { SD_Init(); //重新初始化SD卡 res=SD_WriteDisk((u8*)buff,sector,count); //printf("sd wr error:%d\r\n",res); } break; case EX_FLASH://外部flash for(;count>0;count--) { W25QXX_Write((u8*)buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE); sector++; buff+=FLASH_SECTOR_SIZE; } res=0; break; default: res=1; } //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值 if(res == 0x00)return RES_OK; else return RES_ERROR; } #endif
这里贴一下一些命令的宏定义
/* Command code for disk_ioctrl fucntion */ /* Generic command (Used by FatFs) */ #define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ #define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ #define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ /* Generic command (Not used by FatFs) */ #define CTRL_POWER 5 /* Get/Set power status */ #define CTRL_LOCK 6 /* Lock/Unlock media removal */ #define CTRL_EJECT 7 /* Eject media */ #define CTRL_FORMAT 8 /* Create physical format on the media */ /* MMC/SDC specific ioctl command */ #define MMC_GET_TYPE 10 /* Get card type */ #define MMC_GET_CSD 11 /* Get CSD */ #define MMC_GET_CID 12 /* Get CID */ #define MMC_GET_OCR 13 /* Get OCR */ #define MMC_GET_SDSTAT 14 /* Get SD status */ /* ATA/CF specific ioctl command */ #define ATA_GET_REV 20 /* Get F/W revision */ #define ATA_GET_MODEL 21 /* Get model name */ #define ATA_GET_SN 22 /* Get serial number */
//其他表参数的获得 //pdrv:磁盘编号0~9 //ctrl:控制代码 //*buff:发送/接收缓冲区指针 #if _USE_IOCTL DRESULT disk_ioctl ( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE cmd, /* Control code */ void *buff /* Buffer to send/receive control data */ ) { DRESULT res; if(pdrv==SD_CARD)//SD卡 { switch(cmd) { case CTRL_SYNC: res = RES_OK; break; case GET_SECTOR_SIZE: *(DWORD*)buff = 512; res = RES_OK; break; case GET_BLOCK_SIZE: *(WORD*)buff = SDCardInfo.CardBlockSize; res = RES_OK; break; case GET_SECTOR_COUNT: *(DWORD*)buff = SDCardInfo.CardCapacity/512; res = RES_OK; break; default: res = RES_PARERR; break; } }else if(pdrv==EX_FLASH) //外部FLASH { switch(cmd) { case CTRL_SYNC: res = RES_OK; break; case GET_SECTOR_SIZE: *(WORD*)buff = FLASH_SECTOR_SIZE; res = RES_OK; break; case GET_BLOCK_SIZE: *(WORD*)buff = FLASH_BLOCK_SIZE; res = RES_OK; break; case GET_SECTOR_COUNT: *(DWORD*)buff = FLASH_SECTOR_COUNT; res = RES_OK; break; default: res = RES_PARERR; break; } }else res=RES_ERROR;//其他的不支持 return res; } #endif
通过上述步骤,我们就完成了对于FATFS的移植,FATFS 提供了很多 API 函数,这些函数 FATFS 的自带介绍文件里面都有详细的介绍。这里需要注意的是,在使用FATFS的时候,必须先通过f_mount函数注册一个工作区,才能开始后续 API 的使用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。