[RISC-V MCU 应用开发] 二十六、CH32V103应用教程——FATFS文件系统(SD卡)

[复制链接]
 楼主| RISCVLAR 发表于 2020-12-14 17:23 | 显示全部楼层 |阅读模式
本帖最后由 RISCVLAR 于 2020-12-14 17:22 编辑

CH32V103应用教程——FATFS文件系统(SD卡)

本章教程将使用FATFS文件系统来管理SD卡,实现对SD卡文件读写等基本功能。

1、FATFS简介及相关函数介绍
FATFS 是一种免费开源的、且面向小型嵌入式系统的一种通用FAT文件系统。其采用标准C语言编写并完全独立于底层I/O介质,具有良好的硬件平**立性,可以移植到8051、PIC、AVR、SH、Z80、H8、ARM 等系列单片机上而只需做简单的修改。它支持 FATl2、FATl6和FAT32等格式,支持多个存储媒介;有独立的缓冲区,可以对多个文件进行读/写,并特别对8位单片机和16位单片机做了优化。

本章教程在上一章SD卡教程的基础上,将FATFS文件系统代码移植到SD卡工程中,并对其进行读写测试。关于FATFS文件系统源码可从FATFS官网进行下载。

FATFS源码文件夹src文件夹主要包含以下几个文件:
  • option文件夹下文件为一些可选外部c文件,包含多语言支持需要用到的文件和转换函数;
  • diskio.c文件是 FATFS移植最关键的文件,它为文件系统提供了最底层的访问SD卡SPI接口的方法。其包含底层存储介质的操作函数,这些函数需要用户自己实现,主要添加底层驱动函数。
  • diskio.h定义了FATFS用到的宏,以及diskio.c文件内与底层硬件接口相关的函数声明。
  • integer.h文件中包含了一些数值类型定义。
  • ff.c文件是FATFS核心文件,是文件管理的实现方法。该文件独立于底层介质操作文件的函数,利用这些函数实现文件的读写。
  • ffconf.h这个头文件包含了对FATFS功能配置的宏定义, 通过修改这些宏定义就可以裁剪FATFS的功能。

关于FATFS文件系统模块的移植,我们只需把上述几个文件添加到SD卡工程中并进行一些修改即可。

2、硬件设计
本章教程主要在SD卡基础上进行FATFS文件系统模块的移植,所需资源与上一章一致。

3软件设计
本章教程在上一章SD卡测试基础上进行FATFS文件系统模块的移植,将FATFS源码文件夹下文件添加工工程之后,只需进行以下修改即可:

1、由于本款开发板芯片ROM容量限制原因,option文件夹中选用文件ccsbcs.c文件;

2、对ffconf.h文件进行以下修改:
  • #define _USE_MKFS  1,这个用来定时是否使能格式化,本章需要用到,所以设置这里为1。
  • #define _CODE_PAGE 437,此选项指定要在目标系统上使用的OEM代码页,错误的代码页设置可能会导致文件打开失败,此处选择U.S.,语言类型选择为英文,437,此处需要和ccsbcs.c文件同步使用;
  • #define _USE_LFN   1,该选项用于设置是否支持长文件名(还需要_CODE_PAGE 支持),取值范围为 0~3。0,表示不支持长文件名,1~3 是支持长文件名,但是存储地方不一样,我们选择使用1,通过启用BSS上的静态工作缓冲区启用LFN;
  • #define _VOLUMES   2,用于设置FATFS支持的逻辑设备数目,我们设置为 2,即支持2个设备;
  • #define _MIN_SS    512,指定扇区缓冲最小值;
  • #define _MAX_SS   4096,指定扇区缓冲最大值。

3、关于diskio.c文件,其具体程序如下:

  1. #include "diskio.h"
  2. #include "sd.h"
  3. #include "malloc.h"


  4. #define SD_CARD  0  //SD卡,卷标为0
  5. #define EX_FLASH 1  //外部flash,卷标为1

  6. #define FLASH_SECTOR_SIZE   512

  7. //初始化磁盘
  8. DSTATUS disk_initialize (
  9.     BYTE pdrv               /* Physical drive nmuber (0..) */
  10. )
  11. {
  12.     u8 res=0;
  13.     switch(pdrv)
  14.     {
  15.         case SD_CARD://SD卡
  16.             res = SD_Initialize();//SD_Initialize()
  17.             if(res)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常
  18.             {
  19.                 SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
  20.             }
  21.             break;
  22.         case EX_FLASH://外部flash
  23.             break;
  24.         default:
  25.             res=1;
  26.     }
  27.     if(res)return  STA_NOINIT;
  28.     else return 0; //初始化成功
  29. }

  30. //获得磁盘状态
  31. DSTATUS disk_status (
  32.     BYTE pdrv       /* Physical drive nmuber (0..) */
  33. )
  34. {
  35.     return 0;
  36. }

  37. //读扇区
  38. //drv:磁盘编号0~9
  39. //*buff:数据接收缓冲首地址
  40. //sector:扇区地址
  41. //count:需要读取的扇区数
  42. DRESULT disk_read (
  43.     BYTE pdrv,      /* Physical drive nmuber (0..) */
  44.     BYTE *buff,     /* Data buffer to store read data */
  45.     DWORD sector,   /* Sector address (LBA) */
  46.     UINT count      /* Number of sectors to read (1..128) */
  47. )
  48. {
  49.     u8 res=0;
  50.     if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误
  51.     switch(pdrv)
  52.     {
  53.         case SD_CARD://SD卡
  54.             res=SD_ReadDisk(buff,sector,count);
  55.             if(res)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常
  56.             {
  57.                 SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
  58.             }
  59.             break;
  60.         case EX_FLASH://外部flash
  61.             res=0;
  62.             break;
  63.         default:
  64.             res=1;
  65.     }
  66.    //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值
  67.     if(res==0x00)return RES_OK;
  68.     else return RES_ERROR;
  69. }

  70. //写扇区
  71. //drv:磁盘编号0~9
  72. //*buff:发送数据首地址
  73. //sector:扇区地址
  74. //count:需要写入的扇区数
  75. #if _USE_WRITE
  76. DRESULT disk_write (
  77.     BYTE pdrv,          /* Physical drive nmuber (0..) */
  78.     const BYTE *buff,   /* Data to be written */
  79.     DWORD sector,       /* Sector address (LBA) */
  80.     UINT count          /* Number of sectors to write (1..128) */
  81. )
  82. {
  83.     u8 res=0;
  84.     if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误
  85.     switch(pdrv)
  86.     {
  87.         case SD_CARD://SD卡
  88.             res=SD_WriteDisk((u8*)buff,sector,count);
  89.             break;
  90.         case EX_FLASH://外部flash
  91.             res=0;
  92.             break;
  93.         default:
  94.             res=1;
  95.     }
  96.     //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值
  97.     if(res == 0x00)return RES_OK;
  98.     else return RES_ERROR;
  99. }
  100. #endif


  101. //其他表参数的获得
  102. //drv:磁盘编号0~9
  103. //ctrl:控制代码
  104. //*buff:发送/接收缓冲区指针
  105. #if _USE_IOCTL
  106. DRESULT disk_ioctl (
  107.     BYTE pdrv,      /* Physical drive nmuber (0..) */
  108.     BYTE cmd,       /* Control code */
  109.     void *buff      /* Buffer to send/receive control data */
  110. )
  111. {
  112.     DRESULT res;
  113.     if(pdrv==SD_CARD)//SD卡
  114.     {
  115.         switch(cmd)
  116.         {
  117.             case CTRL_SYNC:
  118.                 SD_CS_L;
  119.                 if(SD_WaitReady()==0)res = RES_OK;
  120.                 else res = RES_ERROR;
  121.                 SD_CS_H;
  122.                 break;
  123.             case GET_SECTOR_SIZE:
  124.                 *(WORD*)buff = 512;
  125.                 res = RES_OK;
  126.                 break;
  127.             case GET_BLOCK_SIZE:
  128.                 *(WORD*)buff = 8;
  129.                 res = RES_OK;
  130.                 break;
  131.             case GET_SECTOR_COUNT:
  132.                 *(DWORD*)buff = SD_GetSectorCount();
  133.                 res = RES_OK;
  134.                 break;
  135.             default:
  136.                 res = RES_PARERR;
  137.                 break;
  138.         }
  139.     }
  140.     else res=RES_ERROR;//其他的不支持
  141.     return res;
  142. }
  143. #endif
  144. //获得时间
  145. //User defined function to give a current time to fatfs module      */
  146. //31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
  147. //15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
  148. DWORD get_fattime (void)
  149. {
  150.     return 0;
  151. }
diskio.c文件主要进行磁盘初始化以及进行获取磁盘状态和读写扇区等操作;

4、关于main.c文件
  1. /********************************** (C) COPYRIGHT *******************************
  2. * File Name          : main.c
  3. * Author             : WCH
  4. * Version            : V1.0.0
  5. * Date               : 2020/04/30
  6. * Description        : Main program body.
  7. *******************************************************************************/
  8. #include "debug.h"
  9. #include "spi.h"
  10. #include "sd.h"
  11. #include "ff.h"


  12. //定义变量
  13. FATFS fs;                     /* FatFs文件系统对象 */
  14. FIL fnew;                     /* 文件对象 */
  15. FRESULT res_sd;               /* 文件操作结果 */
  16. UINT fnum;                    /* 文件成功读写数量 */
  17. BYTE ReadBuffer[1024]={0};    /* 读缓冲区 */
  18. BYTE WriteBuffer[] =          /* 写缓冲区*/
  19. "欢迎使用沁恒CH32V103开发板,新建文件系统测试文件\r\n";

  20. /*******************************************************************************
  21. * Function Name  : main
  22. * Description    : Main program.
  23. * Input          : None
  24. * Return         : None
  25. *******************************************************************************/
  26. int main(void)
  27. {
  28.     u32 sd_size;

  29.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  30.     Delay_Init();
  31.         USART_Printf_Init(115200);

  32.         printf("SystemClk:%d\r\n",SystemCoreClock);
  33.         printf("This is SD FATFS example\r\n");

  34.         if(SD_Detect()==0)
  35.         {
  36.             printf("未检测SD卡插入!\n");
  37.         }
  38.         else
  39.         {
  40.             printf("已检测SD卡插入!\n");

  41.             if(SD_Initialize())
  42.             {
  43.                 printf("SD卡初始化出错,请检查!!\n");
  44.                 Delay_Ms(500);
  45.             }
  46.             else
  47.             {
  48.                 printf("SD卡初始化完成!\n");
  49.                 sd_size=SD_GetSectorCount();//得到扇区数
  50.                 printf("SD Card Size(MB):%d\n",sd_size>>11);
  51.             }
  52.         }

  53.     //在外部SPI SD挂载文件系统,文件系统挂载时会对SPI设备初始化
  54.     res_sd = f_mount(&fs,"0:",1);

  55.     /*----------------------- 格式化测试 ---------------------------*/
  56.         /* 如果没有文件系统就格式化创建创建文件系统 */
  57.         if(res_sd == FR_NO_FILESYSTEM)
  58.         {
  59.             printf("》SD卡还没有文件系统,即将进行格式化...\r\n");
  60.         /* 格式化 */
  61.             res_sd=f_mkfs("0:",0,0);

  62.             if(res_sd == FR_OK)
  63.             {
  64.                 printf("》SD卡已成功格式化文件系统。\r\n");
  65.           /* 格式化后,先取消挂载 */
  66.                 res_sd = f_mount(NULL,"0:",1);
  67.           /* 重新挂载   */
  68.                 res_sd = f_mount(&fs,"0:",1);
  69.             }
  70.             else
  71.             {
  72.                 printf("《《格式化失败。》》res_sd =%d\r\n",res_sd);
  73.                 while(1);
  74.             }
  75.         }
  76.       else if(res_sd!=FR_OK)
  77.       {
  78.         printf("!!SD卡挂载文件系统失败。(%d)\r\n",res_sd);
  79.         printf("!!可能原因:SD卡初始化不成功。\r\n");
  80.             while(1);
  81.       }
  82.       else
  83.       {
  84.         printf("》文件系统挂载成功,可以进行读写测试\r\n");
  85.       }
  86.         /*----------------------- 文件系统测试:写测试 -----------------------------*/
  87.             /* 打开文件,如果文件不存在则创建它 */
  88.             printf("\r\n****** 即将进行文件写入测试... ******\r\n");
  89.             res_sd = f_open(&fnew, "0:FatFs读写测试文件.txt",FA_CREATE_ALWAYS | FA_WRITE );
  90.             if ( res_sd == FR_OK )
  91.             {
  92.                 printf("》打开/创建FatFs读写测试文件.txt文件成功,向文件写入数据。\r\n");
  93.             /* 将指定存储区内容写入到文件内 */
  94.                 res_sd=f_write(&fnew,WriteBuffer,sizeof(WriteBuffer),&fnum);
  95.             if(res_sd==FR_OK)
  96.             {
  97.               printf("》文件写入成功,写入字节数据:%d\n",fnum);
  98.               printf("》向文件写入的数据为:\r\n%s\r\n",WriteBuffer);
  99.             }
  100.             else
  101.             {
  102.               printf("!!文件写入失败:(%d)\n",res_sd);
  103.             }
  104.                 /* 不再读写,关闭文件 */
  105.             f_close(&fnew);
  106.             }
  107.             else
  108.             {
  109.                 printf("!!打开/创建文件失败。\r\n");
  110.             }

  111.         while(1)
  112.     {
  113.         }
  114. }

main.c文件主要进行相关函数初始化以及读取输出相关信息。


4、下载验证
将编译好的程序下载到开发板并复位,当未插入SD卡时,串口打印情况具体如下:
图片1.png
插入SD卡并复位后,串口打印情况如下:
图片2.png


25、FATFS.rar

715.64 KB, 下载次数: 187

评论

学习。  发表于 2020-12-18 11:47
xdqfc 发表于 2020-12-15 11:59 | 显示全部楼层
楼主能否在磁盘(SD)下多增加几个文件,然后再扫描磁盘下的目录,并且print出来,那样就更加完美了。先期待一下。
 楼主| RISCVLAR 发表于 2020-12-15 14:08 | 显示全部楼层
xdqfc 发表于 2020-12-15 11:59
楼主能否在磁盘(SD)下多增加几个文件,然后再扫描磁盘下的目录,并且print出来,那样就更加完美了。先期 ...

好的,后面有空会搞得
gtbestom 发表于 2021-8-4 13:38 | 显示全部楼层
这个新建的文件,文件名乱码了。
gtbestom 发表于 2021-8-4 14:10 | 显示全部楼层
64K的Flash空间,放不下936对照表,所以中文文件名会显示乱码
sesefadou 发表于 2021-8-11 15:57 | 显示全部楼层
FATFS需要占用多大的内存额   
earlmax 发表于 2021-8-11 15:58 | 显示全部楼层
支持flash芯片吗   
maudlu 发表于 2021-8-11 15:58 | 显示全部楼层
必须用malloc吗?     
mattlincoln 发表于 2021-8-11 15:58 | 显示全部楼层
读取文件的时候特别慢。           
mollylawrence 发表于 2021-8-11 15:58 | 显示全部楼层
FATFS文件系统速度可行?  
geraldbetty 发表于 2021-8-11 15:59 | 显示全部楼层
这个扇区是怎么划分   
macpherson 发表于 2021-8-11 15:59 | 显示全部楼层
哪里是配置空间大小的呢  
jonas222 发表于 2021-8-11 16:00 | 显示全部楼层
可以通过usb管理SD卡吗  
claretttt 发表于 2021-8-11 16:00 | 显示全部楼层
CH32V103可以直接生成fatfs代码吗  
kkzz 发表于 2021-8-11 16:00 | 显示全部楼层
8位单片机没有移植成功过。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

133

主题

296

帖子

44

粉丝
快速回复 在线客服 返回列表 返回顶部

133

主题

296

帖子

44

粉丝
快速回复 在线客服 返回列表 返回顶部