打印
[STM32F1]

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

[复制链接]
2621|50
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 zero949079783 于 2021-12-12 15:52 编辑

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






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)中的成员,在调试时打印错误码会事半功倍





 printf("SD文件系统测试\r\n");        
        retSD = f_mount(&SDFatFS,(const TCHAR*)SDPath,1);   //挂载
  printf("\r\nmount_res = %d \r\n",retSD);
  printf_fatfs_error(retSD);
        if(retSD == FR_NO_FILESYSTEM)   //无文件系统时,先格式化SD
        {
    //格式化SD�??
                retSD= f_mkfs((const TCHAR*)SDPath,0,0);   
                printf("\r\n mkfs_res = %d \r\n",retSD);
     if(retSD == FR_OK)
      {
        printf("\r\n FLASH 格式化成功\r\n");
      }
        }
        

        else if(retSD == FR_OK)
        {
    retSD = f_open(&SDFile,"SD.txt",FA_OPEN_ALWAYS|FA_WRITE|FA_READ);  
          printf("\r\nf_open_res = %d \r\n",retSD);
                //retUSER = f_write(&USERFile,wData,sizeof(wData),&bw);  //写数据
    f_lseek(&SDFile,0); //文件定位
    f_printf(&SDFile,"Hello wrold\n");
                printf("\r\n bw  = %d \r\n",bw);
                if(retSD == FR_OK)
                {
                         f_lseek(&SDFile,0);  //文件定位
                         retSD = f_read(&SDFile,rData,f_size(&SDFile),&br);  //读取数据
                         if(retSD == FR_OK)
                         {
                                        printf("\r\n 文件内容 %s  br = %d\r\n",rData,br);
                         }
                }
                f_close(&SDFile); //关闭和保存文件
        }

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

  printf("FLASH文件系统测试\r\n");        
        retUSER = f_mount(&USERFatFS,(const TCHAR*)USERPath,1);   //挂载
  printf("\r\nmount_res = %d \r\n",retUSER);
  printf_fatfs_error(retUSER);
        if(retUSER == FR_NO_FILESYSTEM)   //无文件系统时,先格式化SD
        {
    //格式化
                retUSER= f_mkfs((const TCHAR*)USERPath,0,0);   
                printf("\r\n mkfs_res = %d \r\n",retUSER);
     if(retUSER == FR_OK)
      {
        printf("\r\n FLASH 格式化成功\r\n");
        retUSER = f_mount(NULL,(const TCHAR*)USERPath,1);   //取消挂载

        retUSER = f_mount(&USERFatFS,(const TCHAR*)USERPath,1);   //重新挂载
      }
        }
        else if(retUSER == FR_OK)
        {
    retUSER = f_open(&USERFile,"FLASH.txt",FA_OPEN_ALWAYS|FA_WRITE|FA_READ);  
          printf("\r\nf_open_res = %d \r\n",retUSER);
                //retUSER = f_write(&USERFile,wData,sizeof(wData),&bw);  //写数据
    f_lseek(&USERFile,0); //文件定位
    f_printf(&USERFile,"Hello wrold\n");
                printf("\r\n bw  = %d \r\n",bw);
                if(retUSER == FR_OK)
                {
                         f_lseek(&USERFile,0);  //文件定位
                         retUSER = f_read(&USERFile,rData,f_size(&USERFile),&br);  //读取数据
                         if(retUSER == FR_OK)
                         {
                                        printf("\r\n 文件内容 %s  br = %d\r\n",rData,br);
                         }
                }
                f_close(&USERFile); //关闭和保存文件
        }
FLASH:
/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  Initializes a Drive
  * @param  pdrv: Physical drive number (0..)
  * @retval DSTATUS: Operation status
  */
DSTATUS USER_initialize (
        BYTE pdrv           /* Physical drive nmuber to identify the drive */
)
{
  /* USER CODE BEGIN INIT */
   Stat = STA_NOINIT;
    SPI_Flash_WAKEUP();
    if(SPI_FLASH_ReadDeviceID()== sFLASH_ID )
    {
      Stat =RES_OK;
    }
    return Stat;
  /* USER CODE END INIT */
}

/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  Gets Disk Status
  * @param  pdrv: Physical drive number (0..)
  * @retval DSTATUS: Operation status
  */
DSTATUS USER_status (
        BYTE pdrv       /* Physical drive number to identify the drive */
)
{
  /* USER CODE BEGIN STATUS */
    Stat = STA_NOINIT;
    if(SPI_FLASH_ReadDeviceID()== sFLASH_ID )
    {
      Stat =RES_OK;
    }
    return Stat;
  /* USER CODE END STATUS */
}

/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  Reads Sector(s)
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data buffer to store read data
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to read (1..128)
  * @retval DRESULT: Operation result
  */
DRESULT USER_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 */
)
{
  /* USER CODE BEGIN READ */
  /* 扇区偏移2MB,外部Flash文件系统空间放在SPI Flash后面6MB空间 */
                sector += 512;//偏移512扇区
                SPI_FLASH_BufferRead(sector*4096,buff,count*4096);
    return RES_OK;
  /* USER CODE END READ */
}

/**
  * @brief  Writes Sector(s)
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data to be written
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to write (1..128)
  * @retval DRESULT: Operation result
  */
#if _USE_WRITE == 1
DRESULT USER_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 */
)
{
  /* USER CODE BEGIN WRITE */
  /* USER CODE HERE */
  /* 扇区偏移2MB,外部Flash文件系统空间放在SPI Flash后面6MB空间 */
                sector += 512;//偏移512扇区
                SPI_FLASH_SectorErase(sector*4096);
                SPI_FLASH_BufferWrite(sector*4096,(uint8_t *)buff,count*4096);
    return RES_OK;
  /* USER CODE END WRITE */
}
#endif /* _USE_WRITE == 1 */

/**
  * @brief  I/O control operation
  * @param  pdrv: Physical drive number (0..)
  * @param  cmd: Control code
  * @param  *buff: Buffer to send/receive control data
  * @retval DRESULT: Operation result
  */
#if _USE_IOCTL == 1
DRESULT USER_ioctl (
        BYTE pdrv,      /* Physical drive nmuber (0..) */
        BYTE cmd,       /* Control code */
        void *buff      /* Buffer to send/receive control data */
)
{
  /* USER CODE BEGIN IOCTL */
    DRESULT res = RES_ERROR;
    switch(cmd)
                {
                        case GET_SECTOR_COUNT:
                                *(DWORD*)buff =1536;//返回扇区个数
                        break;
                        
                        case GET_SECTOR_SIZE:
                                        *(WORD*)buff =4096;//返回扇区大小
                        break;
                        
                        case GET_BLOCK_SIZE:        
                                         *(DWORD*)buff =1;                        //返回擦除扇区最小个数
                        break;
                                       
                }
                res = RES_OK;
    return res;
  /* USER CODE END IOCTL */
}


   

使用特权

评论回复
沙发
小叶三千| | 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那里居然坑都是不一样,那才是要命的。

使用特权

评论回复
5
zero949079783|  楼主 | 2021-12-14 19:02 | 只看该作者

文件系统是很常用的,还是要了解一下。日后开发可以用上

使用特权

评论回复
6
zljiu| | 2022-1-8 10:16 | 只看该作者
这些配置 还需要自己进行更改吗

使用特权

评论回复
评论
zero949079783 2022-1-17 19:10 回复TA
看你需要什么就进行什么配置,这些都是一些常用的 
7
coshi| | 2022-1-8 10:17 | 只看该作者
这个还能有什么坑啊

使用特权

评论回复
8
aoyi| | 2022-1-8 10:18 | 只看该作者
早早晚晚都会完善的

使用特权

评论回复
9
drer| | 2022-1-8 10:23 | 只看该作者
文件系统真的不好做

使用特权

评论回复
10
gwsan| | 2022-1-8 10:24 | 只看该作者
这个基本上是最常用的了

使用特权

评论回复
11
yangxiaor520| | 2022-1-17 20:37 | 只看该作者
谢谢分享经验,最近刚好在学文件系统。

使用特权

评论回复
12
gouguoccc| | 2022-1-18 08:39 | 只看该作者
学习了,谢谢楼主分享。

使用特权

评论回复
13
jtracy3| | 2022-2-20 14:23 | 只看该作者
FATFS文件系统STM32F103单片机应用?

使用特权

评论回复
14
xiaoyaodz| | 2022-2-21 14:27 | 只看该作者
FatFS 文件系统如何打开任意文件

使用特权

评论回复
15
lzbf| | 2022-2-21 18:21 | 只看该作者
目前最常使用的文件系统之一

使用特权

评论回复
16
ingramward| | 2022-2-21 21:09 | 只看该作者
fatfs文件系统支持多少文件

使用特权

评论回复
17
olivem55arlowe| | 2022-2-21 21:36 | 只看该作者
自己移植的SD卡的FATFS文件系统

使用特权

评论回复
18
ulystronglll| | 2022-2-21 22:03 | 只看该作者
初识fatfs文件系统   

使用特权

评论回复
19
1988020566| | 2022-2-21 22:29 | 只看该作者
如何设置FatFs文件系统支持长文件名

使用特权

评论回复
20
hilahope| | 2022-2-22 18:41 | 只看该作者
怎样在FatFs文件系统上实现快速索引

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

89

帖子

1

粉丝