fatfs移植
- 上官网fatfs,最下面下载原码,之后解压。这里版本很重要,版本不同可能兼容就不一样。本人试了下ff14版本还不错,如果一个版本不行,可以再换个版本。多两个版本自然也就熟悉了。
- 将解压后的‘diskio.c’,‘ff.c’,‘ffsystem.c’,'ffunicode.c’加入项目。ff.h所在目录加入到项目搜索目录
- 更改diskio.c中的底层驱动
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include "ff.h" /* Obtains integer types */
#include "diskio.h" /* Declarations of disk functions */
#include "stm32f10x_conf.h"
// 这里的头文件不要忘记加入了
// 这里sdio会使用DEV_MMC这个逻辑卷号,如果还想加入spi_flash、USB。可以在这里加入
/* Definitions of physical drive number for each drive */
#define DEV_RAM 0 /* Example: Map Ramdisk to physical drive 0 */
#define DEV_MMC 1 /* Example: Map MMC/SD card to physical drive 1 */
#define DEV_USB 2 /* Example: Map USB MSD to physical drive 2 */
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat = STA_NOINIT;
/*int result;*/
SDTransferState card_state = SD_TRANSFER_OK;
switch (pdrv) {
case DEV_RAM :
// translate the reslut code here
return stat;
case DEV_MMC :
// 这里是SDIO状态
card_state = SD_GetStatus();
if(card_state == SD_TRANSFER_ERROR)
stat = RES_ERROR;
else if(card_state == SD_TRANSFER_BUSY)
stat = RES_NOTRDY;
else
stat = RES_OK;
return stat;
case DEV_USB :
// translate the reslut code here
return stat;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat = STA_NOINIT;
switch (pdrv) {
case DEV_RAM :
// translate the reslut code here
return stat;
case DEV_MMC :
// SDIO 初始化
if(SD_OK == SD_Init())
stat = RES_OK;
return stat;
case DEV_USB :
// translate the reslut code here
return stat;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
DRESULT res = RES_PARERR;
switch (pdrv) {
case DEV_RAM :
// translate the reslut code here
return res;
case DEV_MMC :
// 数据读取
if(count > 1){
SD_ReadMultiBlocks(buff, sector * BLOCK_SIZE, BLOCK_SIZE, count);
SD_WaitReadOperation();
while(SD_GetState() != SD_TRANSFER_OK);
}
else{
SD_ReadBlock(buff, sector * BLOCK_SIZE, BLOCK_SIZE);
SD_WaitReadOperation();
while(SD_GetState() != SD_TRANSFER_OK);
}
res = RES_OK;
return res;
case DEV_USB :
// translate the reslut code here
return res;
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if FF_FS_READONLY == 0
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
DRESULT res = RES_PARERR;
switch (pdrv) {
case DEV_RAM :
// translate the reslut code here
return res;
case DEV_MMC :
// 数据写入
if(count > 1){
SD_WriteMultiBlocks((uint8_t)buff, sector * BLOCK_SIZE, BLOCK_SIZE, count);
SD_WaitWriteOperation();
while(SD_GetState() != SD_TRANSFER_OK);
}
else{
SD_WriteBlock((uint8_t)buff, sector * BLOCK_SIZE, BLOCK_SIZE);
SD_WaitWriteOperation();
while(SD_GetState() != SD_TRANSFER_OK);
}
res = RES_OK;
return res;
case DEV_USB :
// translate the reslut code here
return res;
}
return RES_PARERR;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
// 这个有的版本设置后不会用到,但在FF_MIN_SS不是512时会用到
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res = RES_PARERR;
switch (pdrv) {
case DEV_RAM :
// Process of the command for the RAM drive
return res;
case DEV_MMC :
// Process of the command for the MMC/SD card
switch(cmd){
case GET_SECTOR_COUNT:
*(DWORD *)buff = 1;
return RES_OK;
case GET_SECTOR_SIZE:
*(DWORD *)buff = 512;
return RES_OK;
case GET_BLOCK_SIZE:
*(DWORD *)buff = 1;
return RES_OK;
case CTRL_SYNC:
return RES_OK;
}
return res;
case DEV_USB :
// Process of the command the USB drive
return res;
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Get Current time */
/*-----------------------------------------------------------------------*/
// 时间全返回0
DWORD get_fattime(void){
return 0;
}
- 设置ffconf.h,使之支持中文
// 格式化打开
#define FF_USE_MKFS 1
// seek也打开
#define FF_USE_FASTSEEK 1
// 简体中文
#define FF_CODE_PAGE 936
// 这里可以先设置为0,然后试下2
#define FF_USE_LFN 2
// 最多打开10个卷标,这里不设置,如果想用1的卷标就会报错,只能使用0做为唯一的卷标
#define FF_VOLUMES 10
// 下面这两个要检查下,如果不是512很可能就会调用disk_ioctl。如果没有实现disk_ioctl就有可能会报错
#define FF_MIN_SS 512
#define FF_MAX_SS 512
- main.c中加入测试代码
// 因为本人使用的freeRTOS,因此将测试代码放在一个任务里面。如果你没有用实时系统,可以直接放在一个测试函数里面
void fatfs_test_task(void *pvParameter)
{
int res;
int a;
FIL fdst;
FATFS fs;
UINT br, bw;
BYTE buffer[512];
BYTE textFileBuffer[] = "think you for use fatfs~ ^ _ ^ \r\n";
// 这里的挂载函数不同版本不一样,这个格式是较新的版本
res = f_mount(&fs, "1:", 1);
// 旧些的版本使用以下形式
// res = f_mount(1, &fs);
res = f_open(&fdst, "1:/Demo.TXT", FA_WRITE | FA_CREATE_ALWAYS);
// 下面是写入测试
if(res == FR_OK){
res = f_write(&fdst, textFileBuffer, sizeof(textFileBuffer), &bw);
f_close(&fdst);
printf("\r\n file create success");
printf("\r\n write date %d", bw);
}
else if( res == FR_EXIST){
printf("\r\n file exists\r\n");
}
// 下面是读取测试
res = f_open(&fdst, "1:/Demo.TXT", FA_OPEN_EXISTING | FA_READ);
br = 1;
a = 0;
for(;;){
for(a = 0; a < 512; a++)
buffer[a] = 0;
res = f_read(&fdst, buffer, sizeof(buffer), &br);
printf("\r\n %s ",buffer);
if(res || br == 0) break;
}
f_close(&fdst);
while(1);
}
- 编译一下,确认没有错误
- 将SD卡连上电脑,格式化为fat32。因为之前打开了格式化选择,也可以使用开发板格式化
f_mkfs
。读者有兴趣可以自己试下 - 可以先用调试模式看下。在
f_mount
打个断点,单步运行。每次返回0表示正确。如果不是返回0,可以看下FRESULT定义的枚举类型,表示什么错误。FR_DISK_ERR
,FR_INT_ERR
,FR_NO_FILESYSTEM
几个错误是最常见的。DISK_ERR
表示硬件错误,FR_INT_ERR
是SD卡初始化错误,可以在diskio.c的初始化代码中打个断点,确认是否成功初始化,FR_NO_FILESYSTEM
表示当前sd卡文件格式不是fat32或不能识别,请重新格式化。
搞定后,用串口助手连接电脑和开发板,如果显示以下信息,表示fatfs移植成功。此时将sd卡插入电脑,可以看到卡里面会有一个Demo.TXT的文件,里面有一行文字think you for use fatfs~ ^ _ ^
file create success
write date 34
think you for use fatfs~ ^ _ ^
That is all