重要说明:首先SD可以开启DMA读取或者单纯的SD的中断,但是其中优先级一定要为SD > SD DMA Rx/Tx > USB,不然当SD卡在读写的时候被其他中断打断,会直接导致U盘掉盘,中途卡顿
fatfs 对ROM 占用过多的为 cc936.c,占用170多KB。对于Flash大小只有 128/64KB 的MCU来说肯定是不够用的
该条问题仅参考:在线程中挂载fatfs或文件读写则应将该线程的栈大于1152,否则容易导致HardFault_Handler,或是其他怪异现象,比如某个队列创建成功,但是写入时查询大小剩余为0,或者写入时直接HardFault_Handler,此问题仅在STM32F405RGT6上遇到,较奇怪
问题现象:
通过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,FS_FAT32,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
重要问题提醒:
1、之前网友评论的:retSD = f_mkfs(SDPath,0,0,work,sizeof(work));应改为retSD = f_mkfs(SDPath,FS_FAT32,0,work,sizeof(work));,这是很重要的,不然会导致retSD 为无效参数FR_INVALID_PARAMETER
2、当H7类似系列,开启MPU读写分配后,FATFS配合SDMMC+DMA会导致f_write类似函数出现写入数据和文本数据不一致,也就是数据丢失现象,目前未解决,建议关闭MPU,或者解决数据一致性问题:
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 */
代码编写:
添加已经写好的文件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,FS_FAT32,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,FS_FAT32,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;
}
文件读写函数示例:
/****************************************
@function:读取温度校准文件
@param:mode:读取或者写入文件,eFalse=读取,eTrue--写入
channel--通道值,小于dTemperature_Channel_Number
@return:
0--成功
-1--失败
-2--文件不存在
-3--和文件系统无关的退出
@note:
****************************************/
static int32_t Calibration_File_Load_Temperature(Bool_EnumDef mode,uint8_t channel)
{
FRESULT res_sd;
UINT fnum;
char string[200],FileName[50];
int32_t ByteNum = 0,value = 0;
uint32_t line = 0;
int val_s16 = 0;
LinearFitting_Parameter_StructDef *p = NULL;
float system_temperature = 0.0f,measure_temperature = 0.0f;
double x[2] = {0.0},y[2] = {0.0},a = 0.0,b = 0.0;
if(channel >= dTemperature_Channel_Number)return -3;
if(!Disk_Status_Get(eDisk_SD))return -1;
memset(FileName,0,sizeof(FileName));
sprintf(FileName,"%stemperature%d.xlsx",SDPath,channel);
res_sd = f_open(&SDFile, FileName, (mode?(FA_CREATE_ALWAYS | FA_WRITE):(FA_OPEN_EXISTING | FA_READ)));
if(res_sd == FR_NO_FILE)
{
dLOG("%s:file does not exist\n",FileName);
return -2;
}
else if(res_sd != FR_OK)
{
dLOG("%s:File opening failure...res_sd[%d]\n",FileName,res_sd);
return -1;
}
line = 0;
if(mode)
{//创建空的温度文件
memset(string,0,sizeof(string));
sprintf(string,"lines\t%d\n",0);
ByteNum = strlen(string);
res_sd=f_write(&SDFile,string,ByteNum,&fnum);
sprintf(string,"system_temperature\tmeasure_temperature\n");
ByteNum = strlen(string);
res_sd=f_write(&SDFile,string,ByteNum,&fnum);
}
else
{
p = &lf_temperature[channel];
line = 0;
while(!(f_eof(&SDFile)))
{
memset(string,0,sizeof(string));f_gets(string,sizeof(string),&SDFile);if(strlen(string) == 0){break;}
//dLOG("%s",string);
switch(line++)
{
case 0:
{
sscanf(string,"lines\t%d\n",&val_s16);
if(Common_LinearFitting_Init(p,val_s16) < 0)
{
dLOG("%s Error:The initial temperature calibration resource failed...%d\r\n",__func__,res_sd);
break;
}
dLOG("Number of rows of temperature calibration data[%d]...\r\n",val_s16);
}break;
case 1:break;//标题行
default:
{
sscanf(string,"%f\t%f\n",&system_temperature,&measure_temperature);
//dLOG("%.1f %.1f\n",system_temperature,measure_temperature);
y[1] = y[0];y[0] = measure_temperature;
x[1] = x[0];x[0] = system_temperature;
p->real[p->number] = system_temperature;
if(p->number < 1){p->number++;continue;}
Common_LinearFitCoefficient(&a,&b,x,y,2);
p->a[p->number - 1] = a;
p->b[p->number - 1] = b;
if(p->number++ > p->length)break;
}break;
}
}
if(p->number > 2)
{
p->a[p->number - 1] = p->a[p->number - 2];
p->b[p->number - 1] = p->b[p->number - 2];
}
else if(p->number < 2)//数据过少
{
p->number = 0;
}
}
if(&SDFile != NULL){res_sd = f_close(&SDFile);}
dLOG("%s[%s]\r\n",FileName,(mode?"Write":"Read"));
return 0;
}
版本更新:disk_driver文件
disk_driver.h
#ifndef _disk_driver_H_
#define _disk_driver_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "fatfs.h"
#include "common_driver.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.1
*date:2023.10.10
*note:
**********************************************************************/
#include "disk_driver.h"
#include "sdio.h"
#include "move.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;}
if(Disk_File_Load_SystemParameterA(eState_Invalid) < 0)
{
Disk_File_Load_SystemParameterA(eState_Valid);
}
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)//没有文件系统就格式化创建创建文件系统
{
#if 1
printf("FR_NO_FILESYSTEM\n");
goto SD_FAIL;
#else
retSD = f_mkfs(SDPath,FS_FAT32,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;
}
#endif
}
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(&hsd,&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;
char str2[20] = {0};
int id = 0;
float angle_offset = 0.0f,angle_range = 0.0f;
if(!Disk_Status_Get(eDisk_SD))return -1;
memset(FileName,0,sizeof(FileName));
sprintf(FileName,"%sSystemParameter.xlsx",SDPath);
printf("%s%s\r\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)
{
memset(string,0,sizeof(string));
sprintf(string,"Move Parameter\ttangle_offset\t[-90,90]\tangle_range\t[0,90]\n");
ByteNum = strlen(string);
res_sd=f_write(&SDFile,string,ByteNum,&fnum);
for(line = 0;line < eMove_ID_Num;line++)
{
sprintf(string,"(%d)%s\tangle_offset\t%f\tangle_range\t%f\n",
line,Name_Move_ID[line],0.0f,90.0f);
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:dLOG("%s",string);break;//Move Parameter
case 1:
case 2:
case 3:
case 4:
case 5:
{
sscanf(string,"(%d)%s\tangle_offset\t%f\tangle_range\t%f\n",
&id,str2,&angle_offset,&angle_range);
dLOG("%d %s %f %f\n",id,str2,angle_offset,angle_range);
Move_ParameterDebug_Set((Move_ID_EnumDef )id,angle_offset,angle_range);
}break;
default:break;
}
}
}
if(&SDFile != NULL){res_sd = f_close(&SDFile);}
return 0;
}