本帖最后由 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 */
- }
|