1、固件地址
2、需要修改部分:
diskio.h\diskio.c (必须,底层驱动,与SD卡等相关)
ffconf.h(必须,可选功能配置)
integer.h(数据类型修改,或无)
ffunicode.c(修改字库,若使用中文FF_CODE_PAGE=936,C文件里的数组过大,中小容量单片机容量不足,采用外部FLASH存字库的办法)
ffsystem.c (FF_USE_LFN =3时,采用堆处理长文件名,修改对应的内存管理函数)
3、ffconf.h配置
4、diskio.c中的关键函数
//定义设备号//两个设备//ke加到10个卷
#define SD_CARD 0 //SD卡,卷标为0
#define EX_FLASH 1 //外部flash,卷标为1
#define FLASH_SECTOR_SIZE 512 //512字节一个扇区
u16 FLASH_SECTOR_COUNT= 1024; //W25Q16q32共4M,前0.5用于fafts,后3.5用于存放字库(不用放字库的话最大为8192)
//此变量用于定义FLASH用作fatfs的范围
#define FLASH_BLOCK_SIZE 8 //每个BLOCK有16个扇区
/* Get Drive Status */
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
//未写
return 0;
}
//初始化设备
DSTATUS disk_initialize
(
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
int result;
switch (pdrv)
{
case SD_CARD :
result = SD_Initialize(); //初始化成功则返回0
if(result)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常
{
SD_SPI_SpeedLow();
SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
SD_SPI_SpeedHigh();
}
break;
case EX_FLASH :
result = SPI_Flash_Init();
break;
}
if(result)
{ return STA_NOINIT; } //初始化失败
else
{ return 0; }
}
//读扇区
//pdrv:卷标 buff:读缓冲首地址 sector:开始扇区地址 count:扇区数
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 */
)
{
u8 res;
if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误
switch (pdrv)
{
case SD_CARD : res=SD_ReadDisk(buff,sector,count);
if(res)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常
{
SD_SPI_SpeedLow();
SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
SD_SPI_SpeedHigh();
return RES_NOTRDY; //未准备
}
return RES_OK;
case EX_FLASH :
for(;count>0;count--) //
{
SPI_Flash_Read(buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
sector++;
buff+=FLASH_SECTOR_SIZE;
}
return RES_OK;
}
return RES_PARERR; //无效参数
}
//写一个扇区
#if FF_FS_READONLY == 0 //ffconf.h中开启
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;
int result;
if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误
switch (pdrv)
{
case SD_CARD: res=SD_WriteDisk((u8*)buff,sector,count); //写入成功返回0
if(res){ break;}
return RES_OK;
case EX_FLASH:
for(;count>0;count--)
{
SPI_Flash_Write((u8*)buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
sector++;
buff+=FLASH_SECTOR_SIZE;
}
res=0;
return RES_OK;
}
return RES_PARERR;
}
#endif
//其他磁盘控制
DRESULT disk_ioctl
(
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
int result;
switch (pdrv)
{
case SD_CARD :
switch(cmd)
{
case CTRL_SYNC:
SD_CS=0;
if(SD_WaitReady()==0)res = RES_OK;
else res = RES_ERROR;
SD_CS=1;
break;
case GET_SECTOR_SIZE:
*(WORD*)buff = 512;
res = RES_OK;
break;
case GET_BLOCK_SIZE:
*(WORD*)buff = 8;
res = RES_OK;
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff = SD_GetSectorCount();
res = RES_OK;
break;
default:
res = RES_PARERR;
break;
}
return res;
case EX_FLASH :
switch(cmd)
{
case CTRL_SYNC:
res = RES_OK;
break;
case GET_SECTOR_SIZE:
*(WORD*)buff = FLASH_SECTOR_SIZE;
res = RES_OK;
break;
case GET_BLOCK_SIZE:
*(WORD*)buff = FLASH_BLOCK_SIZE;
res = RES_OK;
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff = FLASH_SECTOR_COUNT;
res = RES_OK;
break;
default:
res = RES_PARERR;
break;
}
return res;
}
return RES_PARERR;
}
5、ffsystem.c修改
#if FF_USE_LFN == 3 /* Use dynamic memory allocation */
/*------------------------------------------------------------------------*/
/* Allocate/Free a Memory Block */
/*------------------------------------------------------------------------*/
#include <stdlib.h> /* with POSIX API */
#include "malloc.h" //内存管理函数
void *ff_memalloc
( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */
)
{
return (UINT*)mymalloc(sizeof(UINT)); /* Allocate a new memory block *///调用mymalloc();
}
void ff_memfree
(
void* mblock /* Pointer to the memory block to free (no effect if null) */
)
{
myfree(mblock); /* Free the memory block *///调用myfree();
}
#endif
6、ffunicode.c修改
修改ffuincode.c以通过SPI使用FLASH中的字库,避免占用stm32内部flash。
首先ffconf.h中修改:
#define FF_CODE_PAGE 936 //中文 支持中文
//是否支持长文件名
#define FF_USE_LFN 3 //在HEAP中,要修改ffsystem.c中的内存申请与释放函数
#define FF_MAX_LFN 20 //长度
在ffuincode.c中修改:先注释掉相应的FF_CODE_PAGE=936的数据
/*------------------------------------------------------------------------*/
/* OEM <==> Unicode Conversions for Static Code Page Configuration with */
/* DBCS Fixed Code Page */
/*------------------------------------------------------------------------*/
#if FF_CODE_PAGE >= 900
//返回特定编码
WCHAR ff_uni2oem
( /* Returns OEM code character, zero on error */
DWORD uni, /* UTF-16 encoded character to be converted */ //要被转换的//u32
WORD cp /* Code page for the conversion */ //转换目标
)
{
WCHAR t[2];
WCHAR c;
u32 i, li, hi;
u16 n;
u32 gbk2uni_offset=0;
if (uni < 0x80) //ASCII,直接不用转换.
{c =(WCHAR)uni;}
else //UNICODE 2 GBK
{
if (uni < 0x10000 && cp == FF_CODE_PAGE) /* Is it in BMP and valid code page? */
{
gbk2uni_offset=0;
/* Unicode to OEMCP */
hi=ftinfo.ugbksize/2;//对半开.
hi =hi / 4 - 1;
li = 0;
for (n = 16; n; n--)
{
i = li + (hi - li) / 2;
SPI_Flash_Read((u8*)&t,ftinfo.ugbkaddr+i*4+gbk2uni_offset,4);//读出4个字节
if (uni == t[0]) break;
if (uni > t[0]) li = i;
else hi = i;
}
c = n ? t[1] : 0;
}
}
return c;
}
WCHAR ff_oem2uni
( /* Returns Unicode character in UTF-16, zero on error */
WCHAR oem, /* OEM code to be converted */
WORD cp /* Code page for the conversion */
)
{
WCHAR t[2];
WCHAR c;
u32 i, li, hi;
u16 n;
u32 gbk2uni_offset=0;
if (oem < 0x80) //ASCII,直接不用转换.
{c = oem;}
else
{
if (cp == FF_CODE_PAGE) /* Is it valid code page? */
{
gbk2uni_offset=ftinfo.ugbksize/2; //GBK 2 UNICODE
/* Unicode to OEMCP */
hi=ftinfo.ugbksize/2;//对半开.
hi =hi / 4 - 1;
li = 0;
for (n = 16; n; n--)
{
i = li + (hi - li) / 2;
SPI_Flash_Read((u8*)&t,ftinfo.ugbkaddr+i*4+gbk2uni_offset,4);//读出4个字节
if (oem == t[0]) break;
if (oem > t[0]) li = i;
else hi = i;
}
c = n ? t[1] : 0;
}
}
return c;
}
#endif