学习笔记1:STM32实现SPI FLASH + FATFS
1.FATFS移植操作
1.1 fatfs下载
打开官网:FatFs – Generic FAT Filesystem Module
1.2 源码结构
具体源码在source文件夹中:
source
├── 00history.txt //历史版本信息
├── 00readme.txt //FATFS简介
├── diskio.c //磁盘IO适配文件
├── diskio.h //磁盘IO适配头文件
├── ff.c //FATFS主要实现文件
├── ff.h //FATFS主要实现头文件
├── ffconf.h //FATFS配置头文件
├── ffsystem.c //系统调用适配文件
└── ffunicode.c //Unicode适配文件
移植过程中,需要配置diskio.c 和 ffconf.h文件。
1.3 代码移植+修改
可以参考别的作者的教程:STM32FATFS文件系统移植_stm32移植fatfs-CSDN博客
1.3.1 修改 diskio.c 文件
// 需要修改的函数
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
我根据自己的W25Q128修改代码如下:
/*-----------------------------------------------------------------------*/
/* 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 "drv_spiflash.h"
/* Definitions of physical drive number for each drive */
#define DEV_SPI_FLASH 0
#define PAGE_SIZE 256
#define SECTOR_SIZE 4096 //每个·扇区4K
#define SECTOR_COUNT 4096 //W25Q128 256block,每个block 16扇区
#define BLOCK_SIZE 16 //16*4096
#define FLASH_PAGES_PER_SECTOR SECTOR_SIZE/PAGE_SIZE
//#define FLASH_ADDR_OFFSET 1536 //偏移1536扇区 1536*4k = 6M,fats管理W25Q128 10M内存
#define FLASH_REMAIN_SECTOR_COUNT 4096
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS Stat;
Stat = STA_NOINIT;
if(DrvSpiflashReadID() != 0)
Stat &= ~STA_NOINIT; //Stat=0x00
return Stat;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS Stat;
Stat = STA_NOINIT;
Stat = disk_status(pdrv);
return Stat;
}
/*-----------------------------------------------------------------------*/
/* 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 */
)
{
UINT i;
for(i = 0;i < count;i++)
{
DrvSpiflashRead(buff + i * SECTOR_SIZE,sector * SECTOR_SIZE + i * SECTOR_SIZE,4096 );
}
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* 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 */
)
{
UINT i;
for(i = 0;i < count;i++)
{
DrvSpiflashWrite((void *)(buff + i * SECTOR_SIZE),sector * SECTOR_SIZE + i * SECTOR_SIZE,4096 );
}
return RES_OK;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res = RES_OK;
switch(cmd)
{
case CTRL_SYNC :
break;
case CTRL_TRIM:
break;
case GET_BLOCK_SIZE:
*(DWORD*)buff = BLOCK_SIZE;
break;
case GET_SECTOR_SIZE:
*(DWORD*)buff = SECTOR_SIZE;
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff = FLASH_REMAIN_SECTOR_COUNT;
break;
default:
res = RES_PARERR;
break;
}
return res;
}
修改为上面的函数后,再增加一个时间函数,不然会报错
__weak DWORD get_fattime(void) // 获取时间
{
return ((DWORD)(2024-1980)<<25) // 设置年份为2024
| ((DWORD)1<<21) // 设置月份为1
| ((DWORD)1<<16) // 设置日期为1
| ((DWORD)1<<11) // 设置小时为1
| ((DWORD)1<<5) // 设置分钟为1
| ((DWORD)1<<1); // 设置秒数为1
}
1.3.2 修改 ffconf.h 文件
FF_USE_MKFS置1,打开f_mkfs()函数,可用来磁盘初始化
FF_CODE_PAGE置936,兼容简体中文
设置FF_MIN_SS、FF_MAX_SS,最小最大擦除块,根据自己的存储设备修改
2 测试
在main函数中初始化SPI FLASH,然后调用下面的测试函数,查看结果
FATFS USERFatFS; /* FatFs文件系统对象 */
FIL fnew; /* 文件对象 */
uint8_t ret = 0;
void Ftafs_Test()
{
FRESULT res_flash; /* 文件操作结果 */
UINT fnum; /* 文件成功读写数量 */
char ReadBuffer[128] = {0}; /* 读缓冲区 */
char WriteBuffer[] ={"Test App!!!/r/n"}; /* 写缓冲区 */
BYTE work[FF_MAX_SS];
ret = f_mount(&USERFatFS,"0:",1); //挂载盘符0
if(ret == FR_NO_FILESYSTEM) //没有文件系统就格式化创建创建文件系统
{
ret = f_mkfs("0:",NULL,work,sizeof(work));
if(ret == FR_OK)
{
printf("fatfs mkfs\r\n");
ret = f_mount(NULL, "0:", 1); //格式化后,先取消挂载
ret = f_mount(&USERFatFS, "0:", 1); //重新挂载
}
else//格式化失败
{
printf("Description Failed to format the SD card...%d\r\n",ret);
return;
}
}
else if(ret != FR_OK)//挂载失败
{
printf("Mount failure=%d\r\n",ret);
return;
}
else
{
printf("Mount success\r\n");
}
//打开文件操作
res_flash = f_open(&fnew, "0:/log.txt", FA_OPEN_ALWAYS|FA_WRITE|FA_READ );
if ( res_flash == FR_OK )
{
printf("File open OK\r\n");
}
else
{
printf("File open False : %d\r\n", res_flash);
return;
}
//向文件系统写操作
res_flash=f_write(&fnew,WriteBuffer,sizeof(WriteBuffer),&fnum);
if ( res_flash == FR_OK )
{
printf("Write open OK\r\n");
}
else
{
printf("Write open False\r\n");
}
//读文件系统数据操作
res_flash = f_lseek(&fnew,0);
res_flash=f_read(&fnew,ReadBuffer,sizeof(ReadBuffer),&fnum);
if ( res_flash == FR_OK )
{
printf("Read OK\r\n");
printf("ReadBuffer = %s\r\n", ReadBuffer);
}
else
{
printf("Read False\r\n");
}
//关闭文件系统
f_close(&fnew);
}
作者:AIshixian