SD卡-fatfs文件系统移植
FATFS文件系统移植
上文中完成了sd卡的驱动代码,本文陈述如何系统移植文件系统
源码下载
源码可以登录fatfs官网下载:http://elm-chan.org/fsw/ff/archives.html,我这里下载最新版本的源码包,下载完成后解压到本地大致浏览源码包的文件结构,主目录下有documents与source两个文件夹,其中documents中教会用户如何使用fatfs,source中主要包含三部分代码:
- 物理层接口:diskio.c/diskio.h
- fatfs源码:ff.c/ff.h
- fatfs配置文件:ffconf.h
- 操作系统扩展功能:ffsystem.c
语言编码表:ffunicode.c
我移植时的需求:不使用操作系统,编码语言使用英文,所以我只用到diskio.c/diskio.h、ff.c/ff.h、ffconf.h这五个文件,并将其添加到自己的工程中接口绑定
上文中我们完成了sd卡的驱动代码,预留了如下几个接口:
uint8_t SD_WaitReady(void); uint8_t SD_Init(void); uint32_t SD_GetSectorCount(void); uint8_t SD_ReadDisk(uint8_t*buf,uint32_t sector,uint8_t cnt); uint8_t SD_WriteDisk(const uint8_t*buf,uint32_t sector,uint8_t cnt);
我们将其与diskio.c中的接口文件绑定:
首先需要新建一个我们自己的设备并删除掉代码中的示例设备:
#define DEV_SD 0
在获取磁盘状态的代码中新增我们的设备代码(这里我让我的设备状态无论如何返回OK):DSTATUS disk_status ( BYTE pdrv ) { DSTATUS stat; int result; switch (pdrv) { case DEV_SD : stat = RES_OK; return stat; } return STA_NOINIT; }
在磁盘初始化代码中绑定我们的SD卡初始化代码:
DSTATUS disk_initialize ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { DSTATUS stat; int result; switch (pdrv) { case DEV_SD : result = SD_Init(); if(0 == result) { stat = RES_OK; } return stat; } return STA_NOINIT; }
在设备读扇区接口中绑定我们的读sd卡设备代码:
DRESULT disk_read ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE *buff, /* Data buffer to store read data */ LBA_t sector, /* Start sector in LBA */ UINT count /* Number of sectors to read */ ) { DRESULT res; int result; switch (pdrv) { case DEV_SD : result = SD_ReadDisk(buff, sector, count); if(0 == result) { res = RES_OK; } return res; } return RES_PARERR; }
在设备写数据接口中绑定我们的写sd卡数据代码:
DRESULT disk_write ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ const BYTE *buff, /* Data to be written */ LBA_t sector, /* Start sector in LBA */ UINT count /* Number of sectors to write */ ) { DRESULT res; int result; switch (pdrv) { case DEV_SD : result = SD_WriteDisk(buff, sector, count); if(0 == result) { res = RES_OK; } return res; } return RES_PARERR; }
在设备状态获取接口中返回我们的设备状态代码:
这里总共获取设备的四种状态:
- 设备是否就绪
- 设备的扇区数量,取决于内存卡多大
- 设备的块大小-恒定512
- 设备的扇区大小-恒定512
DRESULT disk_ioctl ( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE cmd, /* Control code */ void *buff /* Buffer to send/receive control data */ ) { DRESULT res; int result; switch (pdrv) { case DEV_SD : switch (cmd) { case CTRL_SYNC: if(0 == SD_WaitReady()) { return RES_OK; } else { printf("not ready\r\n"); return RES_NOTRDY; } case GET_SECTOR_COUNT: *(DWORD * )buff = SD_GetSectorCount();return RES_OK; case GET_SECTOR_SIZE: *(DWORD * )buff = 512 ;return RES_OK; case GET_BLOCK_SIZE: *(WORD * )buff = 512 ;return RES_OK; } return res; } return RES_PARERR; }
fatfs配置
FF_FS_READONLY -是否开启只读功能
FF_FS_MINIMIZE -是否裁剪功能
FF_USE_FIND -是否开启文件寻找功能
FF_USE_MKFS -是否开启格式化功能(重要)
FF_FS_NORTC -关闭RTC功能(如果使用rtc则需要实现获取时间的接口)
FF_CODE_PAGE -使用哪种编码语言
详细的配置说明可以查看官网文档文件系统demo测试
以上完成fatfs的移植,我们就可以在单片机上对SD卡实现PC端一样的文件操作,详细的接口使用还是去看官方文档,我实现了一个demo,挂载sd卡,如果未成功挂载SD卡就将其格式化,然后读取sd卡中的test.jpg,并拷贝一份重命名为copy.jpg:
uint8_t stat; stat=f_mount(&fs,"0:",1);//SD卡挂载 printf("f_mount:%d\r\n",stat); if(stat!=FR_OK) { printf("f_mkfs :FAT32\r\n"); stat = f_mkfs("0:", 0,(void*)f_mkfs_buff,sizeof(f_mkfs_buff)); if(stat!=FR_OK) { printf("f_mkfs failed\r\n"); } else { printf("f_mkfs successed\r\n"); } } else { printf("SD Card init successed\r\n"); } FIL fp; FRESULT res; UINT bw; UINT br; res=f_open(&fp,"0:/test.jpg",FA_READ); printf("read test.jpg:%d\r\n",res); uint32_t size = fp.obj.objsize; printf("test.jpg size is :%d\r\n",size); char *data = (char *)malloc(size); res=f_read(&fp,data,size,&br); f_close(&fp); res=f_open(&fp,"0:/copy.jpg",FA_READ|FA_WRITE|FA_CREATE_ALWAYS); if(res==FR_OK) { printf("creat copy.jpg\r\n"); res=f_write(&fp,data,size,&bw); if(res==FR_OK) { printf("write copy.jpg\r\n"); } } else { printf("error :%d\r\n",res); } f_close(&fp); free(data); printf("over \r\n");
最终再将内存卡插在电脑上可以发现存在被拷贝的图片(为什么是大写名称我也不知道,可能遗漏了某些东西):
其他可能存在的坑:为了保证格式化为FAT32格式,可是又懒滴写配置文件,在f_mkfs源码中修改默认的格式化类型为FAT32格式,这样可以实现windows系统更快的识别内存卡:
static const MKFS_PARM defopt = {FM_FAT32, 0, 0, 0, 0};
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。