学习笔记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

物联沃分享整理
物联沃-IOTWORD物联网 » 学习笔记1:STM32实现SPI FLASH + FATFS

发表回复