[STM32F1] VSCODE STM32 裸机之 FATFS文件系统(SD和FLASH)

[复制链接]
3547|50
 楼主| zero949079783 发表于 2021-12-12 15:18 | 显示全部楼层 |阅读模式
本帖最后由 zero949079783 于 2021-12-12 15:52 编辑

开发环境:VSCODE(gcc编译链)+STM32CubeMX(也可以使用HUAWEI-LiteOS-Studio) 。
代码文件:SDIO_SD
代码:链接:https://pan.baidu.com/s/1uXfIR0GFQOBZPl1NfQP08w  
提取码:6b0c



1.png
2.png
3.png
diskio.c和diskio.h是硬件层,需要根据存储介质来修改
    ff.c和ff.h是FATFS的文件系统层和文件系统的API层
    移植步骤:
1、数据类型:在integer.h 里面去定义好数据的类型。这里需要了解你用的编译器的数据类型,并根据编译器定义好数据类型。
                     
2、配置:通过ffconf.h配置FATFS的相关功能,以满足你的需要。
                     
3、函数编写:打开diskio.c,进行底层驱动编写,一般需要编写6 个接口函数
   相关配置宏:
        _FS_TINY   mini版本的FATFS
        _FS_READONLY    设置只读,可以减少所占的空间
        _FS_MINIMIZE   削减函数
        _USE_STRFUNC     字符及字符串操作函数
        _USE_MKFS    是否启用格式化
        _USE_FASTSEEK    使能快速定位
        _USE_LABEL    是否支持磁盘盘符的设置和读取
        _CODE_PAGE    设置语言936-中文GBK编码
        _USE_LFN     是否支持长文件名,值不同存储的位置不同
        _MAX_LFN    文件名的最大长度
        _VOLUMES    支持的逻辑设备数目
       _MAX_SS    扇区缓冲最大值,一般为512

文件名                           功能                                          说明
ffconf.h           FATFS模块配置文件                                   需要根据需求来配置参数。

ff.h                  FATFS和应用模块公用的包含文件               不需要修改

ff.c                  FATFS模块源码                                          不需要修改

diskio.h           FATFS和disk I/O模块公用的包含文件         不需要修改

diskio.c           FATFS和disk I/O模块接口层文件                与平台相关的代码,需要用户根据存储介质来编写函数。

interger.h        数据类型定义                                             与编译器有关。

option文件夹     可选的外部功能(比如支持中文等)          汉字实验把字库放到SPI FLASH需要修改

typedef enum {
        FR_OK = 0,                                /* (0) Succeeded   成功*/
        FR_DISK_ERR,                                /* (1) A hard error occured in the low level disk I/O layer   硬盘底层I/O层发生硬错误。  */
        FR_INT_ERR,                                /* (2) Assertion failed由于一个错误的 FAT 结构或一个内部错误,而导致该函数失败。  */
        FR_NOT_READY,                                /* (3) The physical drive cannot work */
        FR_NO_FILE,                                /* (4) Could not find the file */
        FR_NO_PATH,                                /* (5) Could not find the path */
        FR_INVALID_NAME,                                /* (6) The path name format is invalid */
        FR_DENIED,                                /* (7) Acces denied due to prohibited access or directory full */
        FR_EXIST,                                        /* (8) Acces denied due to prohibited access */
        FR_INVALID_OBJECT,                        /* (9) The file/directory object is invalid */
        FR_WRITE_PROTECTED,                        /* (10) The physical drive is write protected */
        FR_INVALID_DRIVE,                                /* (11) The logical drive number is invalid  逻辑驱动器号无效 */
        FR_NOT_ENABLED,                                /* (12) The volume has no work area */
        FR_NO_FILESYSTEM,                        /* (13) There is no valid FAT volume 磁盘上没有有效地 FAT 卷*/
        FR_MKFS_ABORTED,                        /* (14) The f_mkfs() aborted due to any parameter error */
        FR_TIMEOUT,                                /* (15) Could not get a grant to access the volume within defined period */
        FR_LOCKED,                                /* (16) The operation is rejected according to the file shareing policy */
        FR_NOT_ENOUGH_CORE,                        /* (17) LFN working buffer could not be allocated */
        FR_TOO_MANY_OPEN_FILES,                        /* (18) Number of open files > _FS_SHARE */
        FR_INVALID_PARAMETER                        /* (19) Given parameter is invalid */
} FRESULT;


返回值  


FR_OK (0)  

函数成功,该文件对象有效。   

FR_NO_FILE  

找不到该文件。   

FR_NO_PATH  

找不到该路径。   

FR_INVALID_NAME  

文件名无效。   

FR_INVALID_DRIVE  

驱动器号无效。   

FR_EXIST  

该文件已存在。   

FR_DENIED  

由于下列原因,所需的访问被拒绝:

n  ▲ 以写模式打开一个只读文件。   

n  ▲ 由于存在一个同名的只读文件或目录,而导致文件无法被创建。   

n  ▲ 由于目录表或磁盘已满,而导致文件无法被创建。   

FR_NOT_READY  

由于驱动器中没有存储介质或任何其他原因,而导致磁盘驱动器无法工作。   

FR_WRITE_PROTECTED  

在存储介质被写保护的情况下,以写模式打开或创建文件对象。   

FR_DISK_ERR  

由于底层磁盘 I/O 接口函数中的一个错误,而导致该函数失败。   

FR_INT_ERR  

由于一个错误的 FAT 结构或一个内部错误,而导致该函数失败。   

FR_NOT_ENABLED  

逻辑驱动器没有工作区。

FR_NO_FILESYSTEM  

磁盘上没有有效地 FAT 卷。


在官网有详细的使用指南,看着使用指南再对照源码就会基本掌握函数的使用。
   几个重要结构体:
        文件对象结构体(FIL类型):存放文件的相关信息,打开关闭读写文件等操作时需要使用其指针
        目录对象结构体(DIR类型):存放目录的相关信息,对目录操作时需要其指针
        文件状态结构体(FILINFO类型):存放文件的大小属性文件名等信息
        文件系统对象结构体(FATFS类型):暂时没见怎么用过

    文件的属性宏定义(用在打开时):
        可以使用或运算符使得该文件具有多种性质,注意在读写时一定要以相应的属性打开文件

    文件夹文件属性宏定义:
        可以使用或运算符使得该文件具有多种性质,提供了函数可以修改文件的属性

    注意:传参时的path(路径)应为一个字符串,是要操作的文件的完整路径,根目录0表示SD 卡,1表示外部SRAM
        要注意数据类型的统一,在integer.h中定义的文件系统所用到的数据类型
        大部分函数若执行成功返回0,若失败会返回一个错误码,该错误码为枚举类型(FRESULT)中的成员,在调试时打印错误码会事半功倍


4.png 5.png 6.png 7.png 8.png 9.png 10.png 11.png 12.png 13.png


  1. printf("SD文件系统测试\r\n");        
  2.         retSD = f_mount(&SDFatFS,(const TCHAR*)SDPath,1);   //挂载
  3.   printf("\r\nmount_res = %d \r\n",retSD);
  4.   printf_fatfs_error(retSD);
  5.         if(retSD == FR_NO_FILESYSTEM)   //无文件系统时,先格式化SD
  6.         {
  7.     //格式化SD�??
  8.                 retSD= f_mkfs((const TCHAR*)SDPath,0,0);   
  9.                 printf("\r\n mkfs_res = %d \r\n",retSD);
  10.      if(retSD == FR_OK)
  11.       {
  12.         printf("\r\n FLASH 格式化成功\r\n");
  13.       }
  14.         }
  15.         

  16.         else if(retSD == FR_OK)
  17.         {
  18.     retSD = f_open(&SDFile,"SD.txt",FA_OPEN_ALWAYS|FA_WRITE|FA_READ);  
  19.           printf("\r\nf_open_res = %d \r\n",retSD);
  20.                 //retUSER = f_write(&USERFile,wData,sizeof(wData),&bw);  //写数据
  21.     f_lseek(&SDFile,0); //文件定位
  22.     f_printf(&SDFile,"Hello wrold\n");
  23.                 printf("\r\n bw  = %d \r\n",bw);
  24.                 if(retSD == FR_OK)
  25.                 {
  26.                          f_lseek(&SDFile,0);  //文件定位
  27.                          retSD = f_read(&SDFile,rData,f_size(&SDFile),&br);  //读取数据
  28.                          if(retSD == FR_OK)
  29.                          {
  30.                                         printf("\r\n 文件内容 %s  br = %d\r\n",rData,br);
  31.                          }
  32.                 }
  33.                 f_close(&SDFile); //关闭和保存文件
  34.         }

  35.   printf("\r\n-------------------------------------------------------\r\n");

  36.   printf("FLASH文件系统测试\r\n");        
  37.         retUSER = f_mount(&USERFatFS,(const TCHAR*)USERPath,1);   //挂载
  38.   printf("\r\nmount_res = %d \r\n",retUSER);
  39.   printf_fatfs_error(retUSER);
  40.         if(retUSER == FR_NO_FILESYSTEM)   //无文件系统时,先格式化SD
  41.         {
  42.     //格式化
  43.                 retUSER= f_mkfs((const TCHAR*)USERPath,0,0);   
  44.                 printf("\r\n mkfs_res = %d \r\n",retUSER);
  45.      if(retUSER == FR_OK)
  46.       {
  47.         printf("\r\n FLASH 格式化成功\r\n");
  48.         retUSER = f_mount(NULL,(const TCHAR*)USERPath,1);   //取消挂载

  49.         retUSER = f_mount(&USERFatFS,(const TCHAR*)USERPath,1);   //重新挂载
  50.       }
  51.         }
  52.         else if(retUSER == FR_OK)
  53.         {
  54.     retUSER = f_open(&USERFile,"FLASH.txt",FA_OPEN_ALWAYS|FA_WRITE|FA_READ);  
  55.           printf("\r\nf_open_res = %d \r\n",retUSER);
  56.                 //retUSER = f_write(&USERFile,wData,sizeof(wData),&bw);  //写数据
  57.     f_lseek(&USERFile,0); //文件定位
  58.     f_printf(&USERFile,"Hello wrold\n");
  59.                 printf("\r\n bw  = %d \r\n",bw);
  60.                 if(retUSER == FR_OK)
  61.                 {
  62.                          f_lseek(&USERFile,0);  //文件定位
  63.                          retUSER = f_read(&USERFile,rData,f_size(&USERFile),&br);  //读取数据
  64.                          if(retUSER == FR_OK)
  65.                          {
  66.                                         printf("\r\n 文件内容 %s  br = %d\r\n",rData,br);
  67.                          }
  68.                 }
  69.                 f_close(&USERFile); //关闭和保存文件
  70.         }
FLASH:
  1. /**
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]  Initializes a Drive
  3.   * @param  pdrv: Physical drive number (0..)
  4.   * @retval DSTATUS: Operation status
  5.   */
  6. DSTATUS USER_initialize (
  7.         BYTE pdrv           /* Physical drive nmuber to identify the drive */
  8. )
  9. {
  10.   /* USER CODE BEGIN INIT */
  11.    Stat = STA_NOINIT;
  12.     SPI_Flash_WAKEUP();
  13.     if(SPI_FLASH_ReadDeviceID()== sFLASH_ID )
  14.     {
  15.       Stat =RES_OK;
  16.     }
  17.     return Stat;
  18.   /* USER CODE END INIT */
  19. }

  20. /**
  21.   * [url=home.php?mod=space&uid=247401]@brief[/url]  Gets Disk Status
  22.   * @param  pdrv: Physical drive number (0..)
  23.   * @retval DSTATUS: Operation status
  24.   */
  25. DSTATUS USER_status (
  26.         BYTE pdrv       /* Physical drive number to identify the drive */
  27. )
  28. {
  29.   /* USER CODE BEGIN STATUS */
  30.     Stat = STA_NOINIT;
  31.     if(SPI_FLASH_ReadDeviceID()== sFLASH_ID )
  32.     {
  33.       Stat =RES_OK;
  34.     }
  35.     return Stat;
  36.   /* USER CODE END STATUS */
  37. }

  38. /**
  39.   * [url=home.php?mod=space&uid=247401]@brief[/url]  Reads Sector(s)
  40.   * @param  pdrv: Physical drive number (0..)
  41.   * @param  *buff: Data buffer to store read data
  42.   * @param  sector: Sector address (LBA)
  43.   * @param  count: Number of sectors to read (1..128)
  44.   * @retval DRESULT: Operation result
  45.   */
  46. DRESULT USER_read (
  47.         BYTE pdrv,      /* Physical drive nmuber to identify the drive */
  48.         BYTE *buff,     /* Data buffer to store read data */
  49.         DWORD sector,   /* Sector address in LBA */
  50.         UINT count      /* Number of sectors to read */
  51. )
  52. {
  53.   /* USER CODE BEGIN READ */
  54.   /* 扇区偏移2MB,外部Flash文件系统空间放在SPI Flash后面6MB空间 */
  55.                 sector += 512;//偏移512扇区
  56.                 SPI_FLASH_BufferRead(sector*4096,buff,count*4096);
  57.     return RES_OK;
  58.   /* USER CODE END READ */
  59. }

  60. /**
  61.   * @brief  Writes Sector(s)
  62.   * @param  pdrv: Physical drive number (0..)
  63.   * @param  *buff: Data to be written
  64.   * @param  sector: Sector address (LBA)
  65.   * @param  count: Number of sectors to write (1..128)
  66.   * @retval DRESULT: Operation result
  67.   */
  68. #if _USE_WRITE == 1
  69. DRESULT USER_write (
  70.         BYTE pdrv,          /* Physical drive nmuber to identify the drive */
  71.         const BYTE *buff,   /* Data to be written */
  72.         DWORD sector,       /* Sector address in LBA */
  73.         UINT count          /* Number of sectors to write */
  74. )
  75. {
  76.   /* USER CODE BEGIN WRITE */
  77.   /* USER CODE HERE */
  78.   /* 扇区偏移2MB,外部Flash文件系统空间放在SPI Flash后面6MB空间 */
  79.                 sector += 512;//偏移512扇区
  80.                 SPI_FLASH_SectorErase(sector*4096);
  81.                 SPI_FLASH_BufferWrite(sector*4096,(uint8_t *)buff,count*4096);
  82.     return RES_OK;
  83.   /* USER CODE END WRITE */
  84. }
  85. #endif /* _USE_WRITE == 1 */

  86. /**
  87.   * @brief  I/O control operation
  88.   * @param  pdrv: Physical drive number (0..)
  89.   * @param  cmd: Control code
  90.   * @param  *buff: Buffer to send/receive control data
  91.   * @retval DRESULT: Operation result
  92.   */
  93. #if _USE_IOCTL == 1
  94. DRESULT USER_ioctl (
  95.         BYTE pdrv,      /* Physical drive nmuber (0..) */
  96.         BYTE cmd,       /* Control code */
  97.         void *buff      /* Buffer to send/receive control data */
  98. )
  99. {
  100.   /* USER CODE BEGIN IOCTL */
  101.     DRESULT res = RES_ERROR;
  102.     switch(cmd)
  103.                 {
  104.                         case GET_SECTOR_COUNT:
  105.                                 *(DWORD*)buff =1536;//返回扇区个数
  106.                         break;
  107.                         
  108.                         case GET_SECTOR_SIZE:
  109.                                         *(WORD*)buff =4096;//返回扇区大小
  110.                         break;
  111.                         
  112.                         case GET_BLOCK_SIZE:        
  113.                                          *(DWORD*)buff =1;                        //返回擦除扇区最小个数
  114.                         break;
  115.                                        
  116.                 }
  117.                 res = RES_OK;
  118.     return res;
  119.   /* USER CODE END IOCTL */
  120. }


   
小叶三千 发表于 2021-12-14 08:34 | 显示全部楼层
很详细的说明,当时用的时候踩了好多坑。还有ff版本的问题,支持长文件名等等
两只袜子 发表于 2021-12-14 09:06 | 显示全部楼层
闭坑宝典
 楼主| zero949079783 发表于 2021-12-14 19:01 | 显示全部楼层
小叶三千 发表于 2021-12-14 08:34
很详细的说明,当时用的时候踩了好多坑。还有ff版本的问题,支持长文件名等等 ...

确实是有很多坑,用STM32CubeMX 分别生成VSCODE,和KEIL调试,同一个程序,SD那里居然坑都是不一样,那才是要命的。
 楼主| zero949079783 发表于 2021-12-14 19:02 | 显示全部楼层

文件系统是很常用的,还是要了解一下。日后开发可以用上
zljiu 发表于 2022-1-8 10:16 | 显示全部楼层
这些配置 还需要自己进行更改吗

评论

看你需要什么就进行什么配置,这些都是一些常用的  发表于 2022-1-17 19:10
coshi 发表于 2022-1-8 10:17 | 显示全部楼层
这个还能有什么坑啊
aoyi 发表于 2022-1-8 10:18 | 显示全部楼层
早早晚晚都会完善的
drer 发表于 2022-1-8 10:23 | 显示全部楼层
文件系统真的不好做
gwsan 发表于 2022-1-8 10:24 | 显示全部楼层
这个基本上是最常用的了
yangxiaor520 发表于 2022-1-17 20:37 来自手机 | 显示全部楼层
谢谢分享经验,最近刚好在学文件系统。
gouguoccc 发表于 2022-1-18 08:39 来自手机 | 显示全部楼层
学习了,谢谢楼主分享。
jtracy3 发表于 2022-2-20 14:23 | 显示全部楼层
FATFS文件系统STM32F103单片机应用?
xiaoyaodz 发表于 2022-2-21 14:27 | 显示全部楼层
FatFS 文件系统如何打开任意文件
lzbf 发表于 2022-2-21 18:21 | 显示全部楼层
目前最常使用的文件系统之一
ingramward 发表于 2022-2-21 21:09 | 显示全部楼层
fatfs文件系统支持多少文件
olivem55arlowe 发表于 2022-2-21 21:36 | 显示全部楼层
自己移植的SD卡的FATFS文件系统
ulystronglll 发表于 2022-2-21 22:03 | 显示全部楼层
初识fatfs文件系统   
1988020566 发表于 2022-2-21 22:29 | 显示全部楼层
如何设置FatFs文件系统支持长文件名
hilahope 发表于 2022-2-22 18:41 | 显示全部楼层
怎样在FatFs文件系统上实现快速索引
您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

91

帖子

1

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