赞
踩
重要说明:首先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 */
机器翻译:
ENABLE_SD_DMA_CACHE_MAINTENANCE :当使用可缓存内存区域时,可能需要维护缓存有效性。启用下面的定义来激活每个缓存的维护读写操作。注意:这只适用于基于cortex M7的平台。
ENABLE_SCRATCH_BUFFER:一些DMA需要4字节对齐的地址缓冲区来正确读写数据。在fatf中,一些访问不是这样,因此我们需要一个4字节对齐的刮擦缓冲区来正确传输数据
此时就可以解决了
参考:https://blog.csdn.net/kavieen/article/details/124025353
/**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卡插拔,按需添加
选择外部晶振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
添加个串口
生成工程
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 */
添加已经写好的文件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; }
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
补充:
typedef enum
{
eStatus_Invalid = 0,
eStatus_Valid = 1
}status_EnumDef;
主函数main.c添加头文件并调用挂载SD卡系统函数
if(Disk_Mount() < 0){Error_Handler();}
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
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; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。