FatFs文件系统移植应用笔记
FatFs 文件系统移植
应用笔记
使单片机拥有按文件访问存储器中数据的能力,要满足两个必要的条件。其一是存储器已完成格式化操作,即存储器按 FAT/FAT16/FAT32 等格式记录数据,其二是软件中实现文件系统功能,即能够按照存储器中文件记录的格式,操作已有的数据或添加新数据。
FatFs 是一个轻量级、可移植的文件系统,主要用于嵌入式系统。它基于 FAT 文件系统架构,具有良好的兼容性和跨平台性能。FatFs 文件系统可以轻松移植到各种操作系统中,并支持多种文件操作,如创建、删除、改名和目录管理等。此外,FatFs 还提供内存管理和文件权限等功能,确保文件系统的稳定性和安全性。总的来说,FatFs 文件系统是一个简单易用、可扩展的文件系统,适用于各种嵌入式应用场景。
目前 FatFs 文件系统最新版本为 R0.15,下载后压缩包中包含了两个文件夹以及一份TXT 格式的许可证书。其中 documents 文件夹中主要存储了文件系统的介绍与帮助文档,而 source 文件夹中存储的是 FatFs 的源码。
在 source 文件夹中,ff.c、ff.h 与 ffconf.h 三个文件实现了 FatFs 文件系统的核心功能,包括文件读写、文件删除、文件属性修改、文件移动等。其中 ff.c 是文件操作的主要实现代码,ff.h是头文件,ffconf.h 用于配置文件系统的参数。
diskio.c 与 diskio.h 两个文件实现了 FatFs 文件系统和存储介质的底层交互功能,包括存储介质的初始化、读写、删除、移动等。其中 diskio.c 是底层磁盘操作的实现代码,diskio.h 是 diskio.c 文件的头文件。
ffunicode.c 文件实现了 FatFs 文件系统的字符编码转换功能,它将文件系统的内部unicode 编码转换为操作系统常用的 ANSI 编码或者将 ANSI 编码转换为 Unicode 编码。
综上所述,在移植的过程中,应重点关注 diskio.c 与 ffconf.h 两个文件,下面就以 CH32V307VCT6芯片为例,基于 SDIO 操作 SD 卡例程,移植 FatFs 文件系统。diskio.c 文件内disk_status 函数中,通过 SD_GetState 函数获取 SD 卡工作状态,并将结果赋值给局部变量进行存储,经卡状态判断后,将文件系统标志位置位。
1. DSTATUS disk_status (
2. BYTE pdrv /* Physical drive nmuber to identify the drive */
3. )
4. {
5. DSTATUS stat = STA_NOINIT;
6. u32 result;
7.
8. switch (pdrv) {
9. // case DEV_RAM :
10. // result = RAM_disk_status();
11. // return stat;
12.
13. case DEV_MMC :
14. result = SD_GetState();
15. if (result < SD_CARD_DISCONNECTED) {
16. stat &= ~STA_NOINIT; // SD已连接
17. } else {
18. stat = STA_NOINIT;
19. }
20. return stat;
21.
22. // case DEV_USB :
23. // result = USB_disk_status();
24. // return stat;
25. }
26. return STA_NOINIT;
27. }
由于 SD 卡在上电后会立即初始化,disk_initialize 函数中不再重复操作,直接调用disk_status 函数返回当前 SD 卡状态。
1. DSTATUS disk_initialize (
2. BYTE pdrv /* Physical drive nmuber to identify the drive */
3. )
4. {
5. DSTATUS stat = STA_NOINIT;
6. // int result;
7.
8. switch (pdrv) {
9. // case DEV_RAM :
10. // result = RAM_disk_initialize();
11. // return stat;
12.
13. case DEV_MMC :
14. // 卡在上电的时候已经完成初始化,不需要再次执行直接返回状态
15. stat = disk_status(DEV_MMC);
16. return stat;
17.
18. // case DEV_USB :
19. // result = USB_disk_initialize();
20. // return stat;
21. }
22. return STA_NOINIT;
23. }
单片机通过 SDIO 接口操作 SD 卡时,有块读写与连续多块读写两种操作方法,在库函数中通过判断 buffer 大小,自动选择使用何种方式进行数据传输。在 disk_read 与disk_write 函数中,分别调用封装后的 SD_ReadDisk 与 SD_WriteDisk 函数,而无需手动选择其具体的操作方法,软件将根据实际情况,提高文件的读写效率。
1. DRESULT disk_read (
2. BYTE pdrv, /* Physical drive nmuber to identify the drive */
3. BYTE *buff, /* Data buffer to store read data */
4. LBA_t sector, /* Start sector in LBA */
5. UINT count /* Number of sectors to read */
6. )
7. {
8. DRESULT res = RES_PARERR;
9. int result;
10.
11. switch (pdrv) {
12. // case DEV_RAM :
13. // result = RAM_disk_read(buff, sector, count);
14. // return res;
15.
16. case DEV_MMC :
17. result = SD_ReadDisk(buff, sector, count);
18.
19. if (result == SD_OK) {
20. res = RES_OK;
21. } else {
22. res = RES_ERROR;
23. }
24.
25. return res;
26.
27. // case DEV_USB :
28. // result = USB_disk_read(buff, sector, count);
29. // return res;
30. }
31.
32. return RES_PARERR;
33. }
disk_ioctl 函数的作用是执行与存储介质相关的控制操作,以及获取、设置存储介质的参数。为了实现文件系统对 SD 卡进行格式化的操作,函数中通过指针的方式,依次传入扇区个数、扇区大小以及每次最少擦写的扇区数共三个基本参数。
1. DRESULT disk_ioctl (
2. BYTE pdrv, /* Physical drive nmuber (0..) */
3. BYTE cmd, /* Control code */
4. void *buff /* Buffer to send/receive control data */
5. )
6. {
7. DRESULT res = RES_PARERR;
8. // int result;
9.
10. switch (pdrv) {
11. // case DEV_RAM :
12. // return res;
13.
14. case DEV_MMC :
15. switch(cmd){
16. case CTRL_SYNC:
17. break;
18. case GET_SECTOR_COUNT: // 扇区个数
19. *(DWORD*)buff = Flash_Sector_Count;
20. break;
21. case GET_SECTOR_SIZE: // 扇区大小
22. *(WORD*)buff = Flash_Sector_Size;
23. break;
24. case GET_BLOCK_SIZE: // 每次最少擦除扇区个数
25. *(WORD*)buff = 1;
26. break;
27. case CTRL_TRIM:
28. break;
29. }
30.
31. res = RES_OK;
32.
33. return res;
34.
35. // case DEV_USB :
36. // return res;
37. }
38.
39. return RES_PARERR;
40. }
在文件的属性中,记录着文件创建的时间,FatFs 通过调用 get_fattime 函数获取 RTC 时钟数据,直接屏蔽 get_fattime 函数会导致工程在编译过程中出现错误。由于没有实际开启芯片 RTC 功能,这里直接填入固定日期及时间进行替代。
1. DWORD get_fattime(void) {
2. return ((DWORD)(2020 - 1980) << 25) /* Year 2020 */
3. | ((DWORD)1 << 21) /* Month 1 */
4. | ((DWORD)1 << 16) /* Mday 1 */
5. | ((DWORD)0 << 11) /* Hour 0 */
6. | ((DWORD)0 << 5) /* Min 0 */
7. | ((DWORD)0 >> 1); /* Sec 0 */
8. }
至此,FatFs 文件系统的移植基本完成,在实际测试前还应根据需要,合理调整 ffconf.h 文件中如 FF_USE_MKFS 置为 1 启用格式化功能、FF_USE_LFN 置为 3 启用长文件名等功能。配置文件中有详细的注释,解释了每个配置项的具体功能,此处不再一一赘述。