当前位置:   article > 正文

9.2CubeMx配置SD卡FATFS系统_stm32H7系列 SD卡 FR_NO_FILESYSTEM 找不到FatFs系统的问题

fr_no_filesystem

重要说明:首先SD可以开启DMA读取或者单纯的SD的中断,但是其中优先级一定要为SD > SD DMA Rx/Tx > USB,不然当SD卡在读写的时候被其他中断打断,会直接导致U盘掉盘,中途卡顿

问题现象:

通过CubeMx配置SDMMC、Fatfs、使能内置DMA;此时配置生成工程可以正常挂载SD卡、访问文件;
接着添加FMC,此时需要开启MPU内存保护单元、开启Cache;生成工程,此时【retSD = f_mount(&SDFatFS,SDPath,1);//挂载盘符A】会出现f_mount挂载SD卡返回没有文件系统FR_NO_FILESYSTEM,但是SD卡是有文件系统的,即使接着格式化SD卡你会出现问题(retSD = f_mkfs(SDPath,0,0,work,sizeof(work));),会返回无效参数FR_INVALID_PARAMETER。

FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume /
FR_INVALID_PARAMETER /
(19) Given parameter is invalid */

问题原因及解决方案:

stm32h7系列的sd卡内置了dma部分,所以需要考虑字节对齐的问题。
当我们在使用stm32cubemx生成代码时,没有字节对齐的选项;这时,就需要手动打开两个宏定义ENABLE_SD_DMA_CACHE_MAINTENANCE 、ENABLE_SCRATCH_BUFFER
文件:sd_diskio.c

/*
 * when using cacheable memory region, it may be needed to maintain the cache
 * validity. Enable the define below to activate a cache maintenance at each
 * read and write operation.
 * Notice: This is applicable only for cortex M7 based platform.
 */
/* USER CODE BEGIN enableSDDmaCacheMaintenance */
#define ENABLE_SD_DMA_CACHE_MAINTENANCE  1
/* USER CODE END enableSDDmaCacheMaintenance */

/*
* Some DMA requires 4-Byte aligned address buffer to correctly read/write data,
* in FatFs some accesses aren't thus we need a 4-byte aligned scratch buffer to correctly
* transfer data
*/
/* USER CODE BEGIN enableScratchBuffer */
#define ENABLE_SCRATCH_BUFFER
/* USER CODE END enableScratchBuffer */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

机器翻译:
ENABLE_SD_DMA_CACHE_MAINTENANCE :当使用可缓存内存区域时,可能需要维护缓存有效性。启用下面的定义来激活每个缓存的维护读写操作。注意:这只适用于基于cortex M7的平台。
ENABLE_SCRATCH_BUFFER:一些DMA需要4字节对齐的地址缓冲区来正确读写数据。在fatf中,一些访问不是这样,因此我们需要一个4字节对齐的刮擦缓冲区来正确传输数据
此时就可以解决了
参考:https://blog.csdn.net/kavieen/article/details/124025353

CubeMx SD卡工程配置:

#原理图

在这里插入图片描述
/**SDMMC1 GPIO Configuration
PC8 ------> SDMMC1_D0
PC9 ------> SDMMC1_D1
PC10 ------> SDMMC1_D2
PC11 ------> SDMMC1_D3
PC12 ------> SDMMC1_CK
PD2 ------> SDMMC1_CMD
+Vmcu = +3.3V
注:CD引脚用于检测SD卡插拔,按需添加

CubeMx配置

在这里插入图片描述
在这里插入图片描述
选择外部晶振25MHz
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
SDMMC时钟110MHz
在这里插入图片描述
在这里插入图片描述
可以看到SDMMC需要小于25MHz
SDMMC_CK frequency = sdmmc_ker_ck / [2 * CLKDIV].
sdmmc_ker_ck = 110MHz
所以CLKDIV 最大等于3
SDMMC_CK frequency = 110MHz / (2*3) = 18.333MHz
在这里插入图片描述
配置SDMMC引脚所有都上拉
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注:如果带RTOS,则必须使能FS_REENTRANT (Re-Entrancy)
CODE_PANGE:也可以选Chinese(需要占用较大RAM)的。直接用英文的防止了cubeide报出RAM用完的错误
FS_EXFAT:如果sd卡的格式不是fat32,而是exfat的话,这里一定要enable,不然会挂载失败,爆出FR_NOFILESYSTEM的错误
FS_REENTRANT (Re-Entrancy) FS_REENTRANT (Re-Entrancy) Parameter Description:FS_REENTRANT选项切换FatFs模块的可重入性(线程安全)。—0:禁止重入。SYNC_t和FS_TIMEOUT不起作用。依赖:当freeertos被禁用时强制禁用。

使能DMA
在这里插入图片描述
注意H7内置DMA,如果是其他型号,还需配置相对应的DMA
比如F4的还需配置四这里的DMA在这里插入图片描述
在这里插入图片描述
添加个串口
在这里插入图片描述
生成工程

工程源码编写:

主要提示:cortex M7系列开启MPU和Cache后务必需要此操作:

sd_diskio.c
开启宏ENABLE_SD_DMA_CACHE_MAINTENANCE、ENABLE_SCRATCH_BUFFER

/*
 * when using cacheable memory region, it may be needed to maintain the cache
 * validity. Enable the define below to activate a cache maintenance at each
 * read and write operation.
 * Notice: This is applicable only for cortex M7 based platform.
 */
/* USER CODE BEGIN enableSDDmaCacheMaintenance */
#define ENABLE_SD_DMA_CACHE_MAINTENANCE  1
/* USER CODE END enableSDDmaCacheMaintenance */

/*
* Some DMA requires 4-Byte aligned address buffer to correctly read/write data,
* in FatFs some accesses aren't thus we need a 4-byte aligned scratch buffer to correctly
* transfer data
*/
/* USER CODE BEGIN enableScratchBuffer */
#define ENABLE_SCRATCH_BUFFER
/* USER CODE END enableScratchBuffer */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

代码编写:

添加已经写好的文件disk_driver.c、disk_driver.h
disk_driver文件用于挂载SD卡文件系统、格式化、读写文件示例函数
disk_driver.c

/**********************************************************************
*file:磁盘文件
*author:残梦
*versions:V1.0
*date:2023.10.10
*note:
**********************************************************************/
#include "disk_driver.h"
#include "sdmmc.h"

static int32_t Disk_Mount_SD(void);
static int Disk_File_Read_SystemParameter(void);

static status_EnumDef disk_state[eDisk_Num] = {eStatus_Invalid};//磁盘状态

/****************************************
@function:磁盘挂载
@param:void
@return:-1--失败,0--正常
@note:
****************************************/
int32_t Disk_Mount(void)
{
  if(Disk_Mount_SD() < 0)
  {
    disk_state[eDisk_SD] = eStatus_Invalid;
    return -1;
  }else{disk_state[eDisk_SD] = eStatus_Valid;}

  //Disk_File_Read_SystemParameter();
  return 0;
}

/****************************************
@function:挂载磁盘-SD卡
@param:void
@return:-1--失败,0--正常
@note:
****************************************/
static int32_t Disk_Mount_SD(void)
{
  BYTE work[_MAX_SS];
  HAL_SD_CardInfoTypeDef SdCard;

  retSD = f_mount(&SDFatFS,SDPath,1);//挂载盘符A
  if(retSD == FR_NO_FILESYSTEM)//没有文件系统就格式化创建创建文件系统
  {
      retSD = f_mkfs(SDPath,0,0,work,sizeof(work));
      if(retSD == FR_OK)
      {
          retSD = f_mount(NULL,SDPath,1);//格式化后,先取消挂载
          retSD = f_mount(&SDFatFS,SDPath,1);//挂载
      }
      else//格式化失败
      {
        printf("Description Failed to format the SD card...%d\n",retSD);
        goto SD_FAIL;
      }
  }
  else if(retSD != FR_OK)//挂载失败
  {
    printf("Mount failure=%d\n",retSD);
    goto SD_FAIL;
  }

  retSD = f_mount(&SDFatFS,SDPath,1);
  if(retSD != FR_OK){printf("f_mount():retSD=%d\n",retSD);goto SD_FAIL;}

  if(HAL_SD_GetCardInfo(&hsd1,&SdCard) != HAL_OK){printf("HAL_SD_GetCardInfo()\n");goto SD_FAIL;}
  printf("SD卡容量:%.2fGB\n",(float)((uint64_t)SdCard.BlockNbr * (uint64_t)SdCard.BlockSize / 1024.0f / 1024.0f / 1024.0f));

  return 0;
  SD_FAIL:
  {
    printf("Error[Disk_Mount_SD()]:The disk fails to be mounted...\n");
    return -1;
  }
}

/****************************************
@function:获取磁盘状态
@param:void
@return:见status_EnumDef
@note:
****************************************/
status_EnumDef Disk_Status_Get(Disk_List_EnumDef disk)
{
    return disk_state[disk];
}

/****************************************
@function:读取板参数文件
@param:
@return:-1--读取失败,0--成功
@note:
****************************************/
static int Disk_File_Read_SystemParameter(void)
{
    FRESULT res_sd;
    UINT fnum;
    char string[200];
    int32_t ByteNum = 0,value = 0;
    uint32_t line = 0;

    if(!Disk_Status_Get(eDisk_SD))return -1;
    memset(string,0,sizeof(string));
    sprintf(string,"%sSystemParameter.txt",SDPath);
    res_sd = f_open(&SDFile, string, FA_OPEN_EXISTING | FA_READ);
    if(res_sd == FR_NO_FILE)//文件不存在
    {
        printf("file does not exist:%s\n",string);

        //创建默认文件
        res_sd = f_open(&SDFile, string,FA_CREATE_ALWAYS | FA_WRITE );
        if(res_sd != FR_OK)
        {
            printf("[%d]:Failed to create the file!%s\n",res_sd,string);
            return -1;
        }

        memset(string,0,sizeof(string));
        sprintf(string,"%s\n",bsp_BoardVersion);
        ByteNum = strlen(string);
        res_sd=f_write(&SDFile,string,ByteNum,&fnum);
        if(&SDFile != NULL){res_sd = f_close(&SDFile);}
    }
    else if(res_sd != FR_OK)
    {
        printf("[%d]:File opening failure!%s\n",res_sd,string);
        return -1;
    }

    line = 0;
    while(!(f_eof(&SDFile)))
    {
        memset(string,0,sizeof(string));f_gets(string,sizeof(string),&SDFile);if(strlen(string) == 0){break;}
        switch(line++)
        {
            case 0:
            {
                //sscanf(string,"RemoteControlID[%d]:{set range:0xFA-0xFD}\n",&value);
                printf("%s\n",string);
            }break;
            default:break;
        }
    }
    if(&SDFile != NULL){res_sd = f_close(&SDFile);}
    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150

disk_driver.h

#ifndef _disk_driver_H_
#define _disk_driver_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "fatfs.h"

typedef enum
{
  eDisk_SD = 0,
  eDisk_Num
}Disk_List_EnumDef;//磁盘资源列表

int32_t Disk_Mount(void);
status_EnumDef Disk_Status_Get(Disk_List_EnumDef disk);

#ifdef __cplusplus
}
#endif
#endif

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

补充:

typedef enum
{
    eStatus_Invalid = 0,
    eStatus_Valid = 1
}status_EnumDef;
  • 1
  • 2
  • 3
  • 4
  • 5

主函数main.c添加头文件并调用挂载SD卡系统函数

if(Disk_Mount() < 0){Error_Handler();}
  • 1

在这里插入图片描述

补充:

disk_driver文件更新:添加读写测试文件
disk_driver.h

#ifndef _disk_driver_H_
#define _disk_driver_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "fatfs.h"

typedef enum
{
  eDisk_SD = 0,
  eDisk_Num
}Disk_List_EnumDef;//磁盘资源列表

int32_t Disk_Mount(void);
State_EnumDef Disk_Status_Get(Disk_List_EnumDef disk);

#ifdef __cplusplus
}
#endif
#endif


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

disk_driver.c

/**********************************************************************
*file:磁盘文件
*author:残梦
*versions:V1.0
*date:2023.10.10
*note:
typedef enum
{
    eState_Invalid = 0,
    eState_Valid = 1
}State_EnumDef;
**********************************************************************/
#include "disk_driver.h"
#include "sdmmc.h"

static int32_t Disk_Mount_SD(void);
static int Disk_File_Load_SystemParameterA(State_EnumDef mode);

static State_EnumDef disk_state[eDisk_Num] = {eState_Invalid};//磁盘状态

/****************************************
@function:磁盘挂载
@param:void
@return:-1--失败,0--正常
@note:
****************************************/
int32_t Disk_Mount(void)
{
  if(Disk_Mount_SD() < 0)
  {
    disk_state[eDisk_SD] = eState_Invalid;
    return -1;
  }else{disk_state[eDisk_SD] = eState_Valid;}

  Disk_File_Load_SystemParameterA(eState_Valid);
  Disk_File_Load_SystemParameterA(eState_Invalid);
  return 0;
}

/****************************************
@function:挂载磁盘-SD卡
@param:void
@return:-1--失败,0--正常
@note:
****************************************/
static int32_t Disk_Mount_SD(void)
{
  BYTE work[_MAX_SS];
  HAL_SD_CardInfoTypeDef SdCard;

  retSD = f_mount(&SDFatFS,SDPath,1);//挂载盘符A
  if(retSD == FR_NO_FILESYSTEM)//没有文件系统就格式化创建创建文件系统
  {
      retSD = f_mkfs(SDPath,0,0,work,sizeof(work));
      if(retSD == FR_OK)
      {
          retSD = f_mount(NULL,SDPath,1);//格式化后,先取消挂载
          retSD = f_mount(&SDFatFS,SDPath,1);//挂载
      }
      else//格式化失败
      {
        printf("Description Failed to format the SD card...%d\n",retSD);
        goto SD_FAIL;
      }
  }
  else if(retSD != FR_OK)//挂载失败
  {
    printf("Mount failure=%d\n",retSD);
    goto SD_FAIL;
  }

  retSD = f_mount(&SDFatFS,SDPath,1);
  if(retSD != FR_OK){printf("f_mount():retSD=%d\n",retSD);goto SD_FAIL;}

  if(HAL_SD_GetCardInfo(&hsd1,&SdCard) != HAL_OK){printf("HAL_SD_GetCardInfo()\n");goto SD_FAIL;}
  printf("SD卡容量:%.2fGB\n",(float)((uint64_t)SdCard.BlockNbr * (uint64_t)SdCard.BlockSize / 1024.0f / 1024.0f / 1024.0f));

  return 0;
  SD_FAIL:
  {
    printf("Error[Disk_Mount_SD()]:The disk fails to be mounted...\n");
    return -1;
  }
}

/****************************************
@function:获取磁盘状态
@param:void
@return:见State_EnumDef
@note:
****************************************/
State_EnumDef Disk_Status_Get(Disk_List_EnumDef disk)
{
    return disk_state[disk];
}

/****************************************
@function:参数文件加载
@param:mode:读取或者写入文件,eState_Invalid=读取,1--写入
@return:-2--文件不存在,-1--失败,0--成功
@note:
****************************************/
static int Disk_File_Load_SystemParameterA(State_EnumDef mode)
{
    FRESULT res_sd;
    UINT fnum;
    char string[200],FileName[50];
    int32_t ByteNum = 0,value = 0;
    uint32_t line = 0;

    if(!Disk_Status_Get(eDisk_SD))return -1;
    memset(FileName,0,sizeof(FileName));
    sprintf(FileName,"%sSystemParameterA.txt",SDPath);
    printf("%s%s\n",FileName,(mode?"Write":"Read"));
    res_sd = f_open(&SDFile, FileName, (mode?(FA_CREATE_ALWAYS | FA_WRITE):(FA_OPEN_EXISTING | FA_READ)));
    if(res_sd == FR_NO_FILE)
    {
        printf("%s:file does not exist\n",FileName);
        return -2;
    }
    else if(res_sd != FR_OK)
    {
        printf("%s:File opening failure...res_sd[%d]\n",FileName,res_sd);
        return -1;
    }

    line = 0;
    if(mode)
    {
        while(line++ < 10)
        {
            memset(string,0,sizeof(string));
            sprintf(string,"---->>>Test_Line%d\n",line);
            ByteNum = strlen(string);
            res_sd=f_write(&SDFile,string,ByteNum,&fnum);
        }
    }
    else
    {
        while(!(f_eof(&SDFile)))
        {
            memset(string,0,sizeof(string));f_gets(string,sizeof(string),&SDFile);if(strlen(string) == 0){break;}
            printf("%s",string);
            switch(line++)
            {
                case 0:
                {
                    //sscanf(string,"RemoteControlID[%d]:{set range:0xFA-0xFD}\n",&value);
                }break;
                default:break;
            }
        }
    }

    if(&SDFile != NULL){res_sd = f_close(&SDFile);}
    return 0;
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/463999
推荐阅读
  

闽ICP备14008679号