准备再单片机CH579上移植FATFS1.3方便数据管理,下面简单介绍一下移植注意事项和误区。
需要准备的材料有:
(1)FATFS文件系统源码FATFS1.3(点此下载最新FATFS源码)。
(2)单片机平台一个(CH579)。
(3)SPI_FLASH芯片一个(如:W25Q16)。
FATFS是一个通用的嵌入式文件系统,对不同的平台支持很好,大到硬盘、U盘、存储卡,小到spi_flash芯片甚至单片机内部FLASH都可以使用FATFS。今天我们就在一个2M大小的SPI_FLASH( W25Q16)上建立一个文件系统,主控制器是CH579单片机。在做文件系统移植前,你需要把操作SPI_FLASH的驱动调通,能读写SPI_FLASH就可以了。
第一步、 解压缩新下载的FATFS源码,看看里面都是些什么文件。如下图所示,红色框是移植FATFS所必须的文件,蓝色框内的文件是可选的移植文件。
diskio.c个diskio.h是和存储器读写控制相关的驱动接口,比如SPI_FLASH的读写函数接口,都要映射到这里面。必须的文件
ff.h和ff.h是FATFS的核心文件,必须的文件
ffconf.h是FATFS的配置文件,用来裁剪FATFS,必须的文件
integer.h是FATFS所用到的数据类型定义,用以兼容不同字长CPU,必须的文件
ffsystem.c是一些关于在带操作系统平台中,使用的示例,可选文件
ffunicode.c是万国码编码文件,文件里主要是大数组定义,假如你需要让文件名支持中文就需要这个文件,这个文件会使代码空间急剧变大,可选文件
第二步、 本次FATFS移植未使用操作系统,文件系统支持中文路径和名称,所以需要ff.c、ff.h、ffconf.h、diskio.c、diskio.h、ffunicode.c和integer.h这六个文件添加到工程中即可。如下图:
第三步 修改ffconf.h文件,来裁剪我们的FATFS,通过宏开关来去掉不用的功能,来精简文件系统。想知道每个宏的功能?(点击这里)
需要注意的是:由于我们此次移植支持了中文路径和名称,所以这个要设置这个宏 #define FF_CODE_PAGE936 /*936代表 简体中文*/
特别注意:下图的修改,FF_MAX_SS的值必须和FLASH的块的值一直,我在这里走了歪路,搞了半天,它默认的是512,网上其它文档没有提示这里的修改。
第四步 修改diskio.c 来映射我们的存储器读写控制接口,如下:
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */
/*-----------------------------------------------------------------------*/
/* 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 "SPIFlash.H"
/* Definitions of physical drive number for each drive */
#define SPI_FLASH 0 /* Example: Map Ramdisk to physical drive 0 */
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
if(pdrv == SPI_FLASH)
{
PRINT("!!!disk_status OK\r\n");
return RES_OK; //Ö±½Ó·µ»ØOK¼´¿É
}
else
{
PRINT("!!!disk_status ERR\r\n");
return RES_PARERR;
}
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
if(pdrv == SPI_FLASH)
{
SPIFlash_Init();//³õʼ»¯spi flash
PRINT("!!!disk_initialize OK\r\n");
return RES_OK;
}
else
{
PRINT("!!!disk_initialize ERR\r\n");
return RES_PARERR;
}
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
DRESULT res;
PRINT("disk_read---sector:%d,count:%d\r\n",sector,count);
if(pdrv == SPI_FLASH)
{
for(;count>0;count--)
{
ReadExternalFlash_SPI_DAN(sector*4096,4096,buff);//spi flashµÄ¶Áº¯Êý£¬×¢Òâ²ÎÊýÀàÐÍÒ»ÖÂ
sector++;
buff+=4096;
}
res = RES_OK; //ĬÈÏдÈëÕý³££¬¿ÉÒÔ¼Ó
return res;
}
else
{
return RES_PARERR;
}
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
DRESULT res;
PRINT("disk_write---sector:%d,count:%d\r\n",sector,count);
if(pdrv == SPI_FLASH)
{
for(;count>0;count--)
{
EraseExternal4KFlash_SPI(sector*4096);
BlukWriteExternalFlash_SPI(sector*4096,4096,(uint8_t *)buff);//spi flashµÄдº¯Êý£¬×¢Òâ²ÎÊýÀàÐÍÒ»ÖÂ
sector++;
buff+=4096;
}
res=RES_OK;
return res;
}
else
{
PRINT("!!!disk_write ERR\r\n");
return RES_PARERR;
}
}
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
if (pdrv == SPI_FLASH)
{
switch (cmd)
{
case CTRL_SYNC:
return RES_OK;
/* ÉÈÇøÊýÁ¿ 1024*1024*1024 =4 (MB) */
case GET_SECTOR_COUNT:
*(DWORD * )buff = 512;spi flashµÄ¿é´óСÊÇ4K Bytes
// *(DWORD * )buff = 8*1024;//W25Q16 ÓÐ512´óСΪ4k bytesµÄÉÈÇø
return RES_OK;
/* ÉÈÇø´óС*/
case GET_SECTOR_SIZE :
*(WORD * )buff = 4096;//spi flashµÄ¿é´óСÊÇ4K Bytes
// *(WORD * )buff = 512;//spi flashµÄ¿é´óСÊÇ4K Bytes
return RES_OK;
/*¿é */
case GET_BLOCK_SIZE :
*(DWORD * )buff =1;
return RES_OK;
default:
return RES_PARERR;
}
}
else
{
PRINT("!!!disk_ioctl ERR\r\n");
return RES_PARERR;
}
}
DWORD get_fattime(void) {
// DWORD time;
return 0;
}
这里面一定注意,FLASH读写函数驱动的调用。很关键,决定是否能移植成功。