将FatFS移植到NorFlash
将FatFS文件系统移植到NorFlash
1. 下载源码
源码链接:FatFs - 通用FAT文件系统模块 (elm-chan.org)

2. 在Keil工程中创建FatFs文件夹
2.1 将下载的源码复制到FatFs文件夹

2.2 在Keil中添加FatFs
- 添加目录
- 点击Add files添加文件

- 添加头文件目录(即FatFs)

3. 修改diskio.c
- 原始文件如下
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */
/*-----------------------------------------------------------------------*/
#include "ff.h" /* Obtains integer types */
#include "diskio.h" /* Declarations of disk functions */
#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 */
DSTATUS disk_status(BYTE pdrv) {
DSTATUS stat;
int result;
switch (pdrv) {
case DEV_RAM:
result = RAM_disk_status();
return stat;
case DEV_MMC:
result = MMC_disk_status();
return stat;
case DEV_USB:
result = USB_disk_status();
return stat;
}
return STA_NOINIT;
}
DSTATUS disk_initialize(BYTE pdrv) {
DSTATUS stat;
int result;
switch (pdrv) {
case DEV_RAM:
result = RAM_disk_initialize();
return stat;
case DEV_MMC:
result = MMC_disk_initialize();
return stat;
case DEV_USB:
result = USB_disk_initialize();
return stat;
}
return STA_NOINIT;
}
DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) {
DRESULT res;
int result;
switch (pdrv) {
case DEV_RAM:
result = RAM_disk_read(buff, sector, count);
return res;
case DEV_MMC:
result = MMC_disk_read(buff, sector, count);
return res;
case DEV_USB:
result = USB_disk_read(buff, sector, count);
return res;
}
return RES_PARERR;
}
#if FF_FS_READONLY == 0
DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count) {
DRESULT res;
int result;
switch (pdrv) {
case DEV_RAM:
result = RAM_disk_write(buff, sector, count);
return res;
case DEV_MMC:
result = MMC_disk_write(buff, sector, count);
return res;
case DEV_USB:
result = USB_disk_write(buff, sector, count);
return res;
}
return RES_PARERR;
}
#endif
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) {
DRESULT res;
int result;
switch (pdrv) {
case DEV_RAM:
return res;
case DEV_MMC:
return res;
case DEV_USB:
return res;
}
return RES_PARERR;
}
- 修改程序
- 增加头文件
#include <stdint.h> - 修改磁盘:
DEV_RAM改为DEV_NORFLASH - 修改状态:
disk_status - 修改读:
disk_read - 修改写:
disk_write - 修改磁盘信息:
disk_ioctl - 修改获取时间:
get_fattime
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */
/*-----------------------------------------------------------------------*/
#include <stdint.h>
#include "ff.h" /* Obtains integer types */
#include "diskio.h" /* Declarations of disk functions */
#include "norflash_drv.h"
#include "rtc_drv.h"
#define DEV_NORFLASH 0 /* Example: Map NorFlash 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 */
DSTATUS disk_status(BYTE pdrv) {
return RES_OK;
}
DSTATUS disk_initialize(BYTE pdrv) {
uint8_t mid = 0;
uint16_t did = 0;
switch (pdrv) {
case DEV_NORFLASH:
NorflashDrvInit();
ReadNorflashID(&mid, &did);
if (((uint32_t)mid << 16 | did) == NORFLASH_ID) {
return RES_OK;
}
}
return RES_NOTRDY;
}
DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) {
switch (pdrv) {
case DEV_NORFLASH:
ReadNorflashData(sector * NORFLASH_SECTOR_SIZE, buff, count * NORFLASH_SECTOR_SIZE);
return RES_OK;
}
return RES_PARERR;
}
#if FF_FS_READONLY == 0
DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count) {
switch (pdrv) {
case DEV_NORFLASH:
EraseNorflashForWrite(sector * NORFLASH_SECTOR_SIZE, count * NORFLASH_SECTOR_SIZE);
WriteNorflashData(sector * NORFLASH_SECTOR_SIZE, (uint8_t *)buff, count * NORFLASH_SECTOR_SIZE);
return RES_OK;
}
return RES_PARERR;
}
#endif
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) {
switch (pdrv) {
case DEV_NORFLASH:
switch (cmd) {
case GET_SECTOR_COUNT:
*(DWORD *)buff = NORFLASH_SECTOR_COUNT;
break;
case GET_SECTOR_SIZE:
*(WORD *)buff = NORFLASH_SECTOR_SIZE;
break;
}
return RES_OK;
}
return RES_PARERR;
}
DWORD get_fattime(void) {
RtcTime_t rtcTime;
GetRtcTime(&rtcTime);
return ((DWORD)(rtcTime.year - 1980) << 25)
| ((DWORD)(rtcTime.month) << 21)
| ((DWORD)(rtcTime.day) << 16)
| ((DWORD)(rtcTime.hour) << 11)
| ((DWORD)(rtcTime.minute) << 5)
| ((DWORD)(rtcTime.second) >> 1);
}
4. 修改ffconfig.h头文件
- 源码
/*---------------------------------------------------------------------------/
/ Configurations of FatFs Module
/---------------------------------------------------------------------------*/
#define FFCONF_DEF 80286 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_READONLY 0
#define FF_FS_MINIMIZE 0
#define FF_USE_FIND 0
#define FF_USE_MKFS 0
#define FF_USE_FASTSEEK 0
#define FF_USE_EXPAND 0
#define FF_USE_CHMOD 0
#define FF_USE_LABEL 0
#define FF_USE_FORWARD 0
#define FF_USE_STRFUNC 0
#define FF_PRINT_LLI 1
#define FF_PRINT_FLOAT 1
#define FF_STRF_ENCODE 3
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define FF_CODE_PAGE 932
#define FF_USE_LFN 0
#define FF_MAX_LFN 255
#define FF_LFN_UNICODE 0
#define FF_LFN_BUF 255
#define FF_SFN_BUF 12
#define FF_FS_RPATH 0
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/
#define FF_VOLUMES 1
#define FF_STR_VOLUME_ID 0
#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
#define FF_MULTI_PARTITION 0
#define FF_MIN_SS 512
#define FF_MAX_SS 512
#define FF_LBA64 0
#define FF_MIN_GPT 0x10000000
#define FF_USE_TRIM 0
/*---------------------------------------------------------------------------/
/ System Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_TINY 0
#define FF_FS_EXFAT 0
#define FF_FS_NORTC 0
#define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2022
#define FF_FS_NOFSINFO 0
#define FF_FS_LOCK 0
#define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000
-
修改后
-
系统配置如下
-
设置宏:
#define FF_FS_TINY 0,1开销小,0开销大,主要看单片机的性能。 -
设置宏:
#define FF_FS_EXFAT 0。 -
功能函数配置如下:
-
设置宏:
#define FF_USE_MKFS 1// modify -
设置宏:
#define FF_USE_FASTSEEK 1// modify -
设置宏:
#define FF_USE_LABEL 1// modify -
设置宏:
#define FF_USE_STRFUNC 1// modify (支持字符串) -
设置宏:
#define FF_CODE_PAGE 437// modify(无特殊转化写成437就行) -
设置宏:
#define FF_USE_LFN 1// modify(长文件名) -
设置宏:
#define FF_FS_NORTC 0 -
设置宏:
#define FF_VOLUMES 3// modify -
设置宏:
#define FF_MAX_SS 4096//modify(这个越大读写越快)
/*---------------------------------------------------------------------------/
/ Configurations of FatFs Module
/---------------------------------------------------------------------------*/
#define FFCONF_DEF 80286 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_READONLY 0
#define FF_FS_MINIMIZE 0
#define FF_USE_FIND 0
#define FF_USE_MKFS 1 // modify
#define FF_USE_FASTSEEK 1 // modify
#define FF_USE_EXPAND 0
#define FF_USE_CHMOD 0
#define FF_USE_LABEL 1 // modify
#define FF_USE_FORWARD 0
#define FF_USE_STRFUNC 1 // modify
#define FF_PRINT_LLI 1
#define FF_PRINT_FLOAT 1
#define FF_STRF_ENCODE 3
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define FF_CODE_PAGE 437 // modify
#define FF_USE_LFN 1 // modify
#define FF_MAX_LFN 255
#define FF_LFN_UNICODE 0
#define FF_LFN_BUF 255
#define FF_SFN_BUF 12
#define FF_FS_RPATH 0
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/
#define FF_VOLUMES 3 // modify
#define FF_STR_VOLUME_ID 0
#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
#define FF_MULTI_PARTITION 0
#define FF_MIN_SS 512
#define FF_MAX_SS 4096 //modify
#define FF_LBA64 0
#define FF_MIN_GPT 0x10000000
#define FF_USE_TRIM 0
/*---------------------------------------------------------------------------/
/ System Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_TINY 1
#define FF_FS_EXFAT 0
#define FF_FS_NORTC 0
#define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2022
#define FF_FS_NOFSINFO 0
#define FF_FS_LOCK 0
#define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000
5. 封装接口
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "sensor_drv.h"
#include "ff.h"
#include "rtc_drv.h"
#define DEV_PATH_STR "0:"
#define SENSOR_FILE_PATH_STR "0:温度传感器记录.txt" //根目录
static FATFS g_fs; // 文件系统
static FIL g_sensorFile; // 文件句柄
static bool g_fsInitStat; // 是否初始化成功
void FatfsInit(void) {
FRESULT res;
uint8_t workBuffer[FF_MAX_SS];
res = f_mount(&g_fs, DEV_PATH_STR, 1); // 挂载文件系统
if (res == FR_NO_FILESYSTEM) { // 没有部署文件系统
res = f_mkfs(DEV_PATH_STR, 0, workBuffer, FF_MAX_SS); // 创建文件系统
if (res == FR_OK) {
f_mount(NULL, DEV_PATH_STR, 1); // 取消挂载
res = f_mount(&g_fs, DEV_PATH_STR, 1); // 重新挂载
}
}
if (res != FR_OK) {
printf("文件系统初始化失败,错误码:%d.\n", res);
g_fsInitStat = false;
return;
}
g_fsInitStat = true;
}
void FatfsTask(void) {
if (!g_fsInitStat) {
return;
}
FRESULT res;
res = f_open(&g_sensorFile, SENSOR_FILE_PATH_STR, FA_OPEN_APPEND | FA_WRITE);
if (res != FR_OK) {
printf("打开%s失败,错误码:%d.\n", SENSOR_FILE_PATH_STR, res);
return;
}
RtcTime_t rtcTime;
GetRtcTime(&rtcTime);
SensorData_t sensorData;
GetSensorData(&sensorData);
if (f_printf(&g_sensorFile, "%d-%02d-%02d %02d:%02d:%02d, temp is %.1f, humi is %d\n",
rtcTime.year, rtcTime.month, rtcTime.day, rtcTime.hour, rtcTime.minute, rtcTime.second,
sensorData.temp, sensorData.humi) < 0) {
printf("写数据失败.\n");
}
f_close(&g_sensorFile); // 文件关闭
}
void PrintSensorFile(void) {
if (!g_fsInitStat) {
return;
}
FRESULT res;
res = f_open(&g_sensorFile, SENSOR_FILE_PATH_STR, FA_OPEN_EXISTING | FA_READ);
if (res != FR_OK) {
printf("打开%s失败,错误码:%d.\n", SENSOR_FILE_PATH_STR, res);
return;
}
uint8_t readBuf[50];
memset(readBuf, 0, sizeof(readBuf));
while (NULL != f_gets((TCHAR *)readBuf, sizeof(readBuf), &g_sensorFile)) {
printf("%s", readBuf);
memset(readBuf, 0, sizeof(readBuf));
}
f_unlink(SENSOR_FILE_PATH_STR); // 删除文档
}
7. 调用关系

8. NorFlash驱动
/*!
\file gd25qxx.c
\brief SPI flash gd25qxx driver
*/
#include "gd25qxx.h"
#include "gd32f403.h"
#include <string.h>
#define WRITE 0x02 /* write to memory instruction */
#define WRSR 0x01 /* write status register instruction */
#define WREN 0x06 /* write enable instruction */
#define READ 0x03 /* read from memory instruction */
#define RDSR 0x05 /* read status register instruction */
#define RDID 0x9F /* read identification */
#define SE 0x20 /* sector erase instruction */
#define BE 0xC7 /* bulk erase instruction */
#define WIP_FLAG 0x01 /* write in progress(wip)flag */
#define DUMMY_BYTE 0xA5
void spi_flash_init(void) {
spi_parameter_struct spi_init_struct;
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOE);
rcu_periph_clock_enable(RCU_SPI0);
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
gpio_init(GPIOE, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
SPI_FLASH_CS_HIGH();
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_MASTER;;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_8 ;
spi_init_struct.endian = SPI_ENDIAN_MSB;;
spi_init(SPI0, &spi_init_struct);
spi_enable(SPI0);
}
void spi_flash_sector_erase(uint32_t sector_addr) {
spi_flash_write_enable();
SPI_FLASH_CS_LOW();
spi_flash_send_byte(SE);
spi_flash_send_byte((sector_addr & 0xFF0000) >> 16);
spi_flash_send_byte((sector_addr & 0xFF00) >> 8);
spi_flash_send_byte(sector_addr & 0xFF);
SPI_FLASH_CS_HIGH();
spi_flash_wait_for_write_end();
}
void spi_flash_bulk_erase(void) {
spi_flash_write_enable();
SPI_FLASH_CS_LOW();
spi_flash_send_byte(BE);
SPI_FLASH_CS_HIGH();
spi_flash_wait_for_write_end();
}
void spi_flash_page_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write) {
spi_flash_write_enable();
SPI_FLASH_CS_LOW();
spi_flash_send_byte(WRITE);
spi_flash_send_byte((write_addr & 0xFF0000) >> 16);
spi_flash_send_byte((write_addr & 0xFF00) >> 8);
spi_flash_send_byte(write_addr & 0xFF);
while(num_byte_to_write--) {
spi_flash_send_byte(*pbuffer);
pbuffer++;
}
SPI_FLASH_CS_HIGH();
spi_flash_wait_for_write_end();
}
void spi_flash_buffer_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write) {
uint8_t num_of_page = 0, num_of_single = 0, addr = 0, count = 0, temp = 0;
addr = write_addr % SPI_FLASH_PAGE_SIZE;
count = SPI_FLASH_PAGE_SIZE - addr;
num_of_page = num_byte_to_write / SPI_FLASH_PAGE_SIZE;
num_of_single = num_byte_to_write % SPI_FLASH_PAGE_SIZE;
if(0 == addr) {
if(0 == num_of_page)
spi_flash_page_write(pbuffer, write_addr, num_byte_to_write);
else {
while(num_of_page--) {
spi_flash_page_write(pbuffer, write_addr, SPI_FLASH_PAGE_SIZE);
write_addr += SPI_FLASH_PAGE_SIZE;
pbuffer += SPI_FLASH_PAGE_SIZE;
}
spi_flash_page_write(pbuffer, write_addr, num_of_single);
}
} else {
if(0 == num_of_page) {
if(num_of_single > count) {
temp = num_of_single - count;
spi_flash_page_write(pbuffer, write_addr, count);
write_addr += count;
pbuffer += count;
spi_flash_page_write(pbuffer, write_addr, temp);
} else
spi_flash_page_write(pbuffer, write_addr, num_byte_to_write);
} else {
num_byte_to_write -= count;
num_of_page = num_byte_to_write / SPI_FLASH_PAGE_SIZE;
num_of_single = num_byte_to_write % SPI_FLASH_PAGE_SIZE;
spi_flash_page_write(pbuffer, write_addr, count);
write_addr += count;
pbuffer += count;
while(num_of_page--) {
spi_flash_page_write(pbuffer, write_addr, SPI_FLASH_PAGE_SIZE);
write_addr += SPI_FLASH_PAGE_SIZE;
pbuffer += SPI_FLASH_PAGE_SIZE;
}
if(0 != num_of_single)
spi_flash_page_write(pbuffer, write_addr, num_of_single);
}
}
}
void spi_flash_buffer_read(uint8_t* pbuffer, uint32_t read_addr, uint16_t num_byte_to_read) {
SPI_FLASH_CS_LOW();
spi_flash_send_byte(READ);
spi_flash_send_byte((read_addr & 0xFF0000) >> 16);
spi_flash_send_byte((read_addr & 0xFF00) >> 8);
spi_flash_send_byte(read_addr & 0xFF);
while(num_byte_to_read--) {
*pbuffer = spi_flash_send_byte(DUMMY_BYTE);
pbuffer++;
}
SPI_FLASH_CS_HIGH();
}
uint32_t spi_flash_read_id(void) {
uint32_t temp = 0, temp0 = 0, temp1 = 0, temp2 = 0;
SPI_FLASH_CS_LOW();
spi_flash_send_byte(0x9F);
temp0 = spi_flash_send_byte(DUMMY_BYTE);
temp1 = spi_flash_send_byte(DUMMY_BYTE);
temp2 = spi_flash_send_byte(DUMMY_BYTE);
SPI_FLASH_CS_HIGH();
temp = (temp0 << 16) | (temp1 << 8) | temp2;
return temp;
}
void spi_flash_start_read_sequence(uint32_t read_addr) {
SPI_FLASH_CS_LOW();
spi_flash_send_byte(READ);
spi_flash_send_byte((read_addr & 0xFF0000) >> 16);
spi_flash_send_byte((read_addr & 0xFF00) >> 8);
spi_flash_send_byte(read_addr & 0xFF);
}
uint8_t spi_flash_read_byte(void) {
return(spi_flash_send_byte(DUMMY_BYTE));
}
uint8_t spi_flash_send_byte(uint8_t byte) {
while (RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE));
spi_i2s_data_transmit(SPI0, byte);
while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE));
return(spi_i2s_data_receive(SPI0));
}
uint16_t spi_flash_send_halfword(uint16_t half_word) {
while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE));
spi_i2s_data_transmit(SPI0, half_word);
while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE));
return spi_i2s_data_receive(SPI0);
}
void spi_flash_write_enable(void) {
SPI_FLASH_CS_LOW();
spi_flash_send_byte(WREN);
SPI_FLASH_CS_HIGH();
}
void spi_flash_wait_for_write_end(void) {
uint8_t flash_status = 0;
SPI_FLASH_CS_LOW();
spi_flash_send_byte(RDSR);
do {
flash_status = spi_flash_send_byte(DUMMY_BYTE);
} while((flash_status & WIP_FLAG) == SET);
SPI_FLASH_CS_HIGH();
}
/*!
\file gd25qxx.h
\brief the header file of SPI flash gd25qxx driver
*/
#ifndef GD25QXX_H
#define GD25QXX_H
#include "gd32f403.h"
#define SPI_FLASH_PAGE_SIZE 0x100
#define SPI_FLASH_CS_LOW() gpio_bit_reset(GPIOE, GPIO_PIN_3)
#define SPI_FLASH_CS_HIGH() gpio_bit_set(GPIOE, GPIO_PIN_3)
void spi_flash_init(void);
void spi_flash_sector_erase(uint32_t sector_addr);
void spi_flash_bulk_erase(void);
void spi_flash_page_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write);
void spi_flash_buffer_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write);
void spi_flash_buffer_read(uint8_t* pbuffer, uint32_t read_addr, uint16_t num_byte_to_read);
uint32_t spi_flash_read_id(void);
void spi_flash_start_read_sequence(uint32_t read_addr);
uint8_t spi_flash_read_byte(void);
uint8_t spi_flash_send_byte(uint8_t byte);
uint16_t spi_flash_send_halfword(uint16_t half_word);
void spi_flash_write_enable(void);
void spi_flash_wait_for_write_end(void);
#endif /* GD25QXX_H */