(测试环境:IAR540 + STM32F103VBT6 + SDC(SPI方式) + ucOS-II + TFT(ILI9325) )
FATFS官网:http://elm-chan.org/fsw/ff/00index_e.html
下载最新版本FatFs R0.09 (November 14,2011)
解压缩后有两个文件夹doc和src,把src拷贝到工程中,其中包括diskio.h、ff.c、ff.h、integer.h、ffconf.h。
diskio.h、ff.c、ff.h、integer.h四个文件都不需要修改,移植需要做的:(1)配置ffconf.h。(2)创建底层驱动diskio.c文件。
一、根据系统类型配置ffconf.h
_FFCONF是代表了版本号,不做处理。
- 函数和缓冲区配置
- _FS_TINY设置缓冲区的位置,假如设置为0,也就是每个文件(FIL结构体)中带一个buf,否则的话,整个文件系统公用一个buf。内存还是够的,所以选择为0。
- _FS_READONLY设置是否文件只读,系统需要可读写的,设置为0。
- _FS_MINIMIZE设置为0,因为以下的那些函数要用到,不简化。
- _USE_STRFUNC设置是否使用字符串函数,主要有f_gets, f_putc, f_puts, f_printf四个函数,暂时不用,因为我们的数据都是自定义结构体的存储方式,为了节省空间这个设置为0。
- _USE_MKFS设置是否实现f_mkfs函数。我们需要在设备初始化时完全格式化Flash,所以此函数需要。
- _USE_FORWORD设置
- _USE_FASTSEEK设置是否支持文件快速定位,它主要采用缓冲区来存储簇链映射图,以空间换时间,对于我们系统不合算,还是采用普通定位方式好。
- 本地化和命名空间配置
- _CODE_PAGE设置目标系统的本地化设置,本系统有ASCII支持就足够了,支持本地化的情况下,模块的大小将大幅增加,反而不符合我们选择FatFs的初衷,所以选择1。
- _USE_LFN设置长文件名,我们系统不支持,设为0。
- _MAX_LFN不用设置,因为不支持长文件名。
- _LFN_UNICODE设置长文件名是否支持Unicode,我们选择不支持,因为不支持长文件名。
- _FS_RPATH设置相对路径支持。相对路径在编程的时候特别方便,但是为了先移植成功,暂不支持。
- 物理驱动器配置
- _VOLUMES设置逻辑驱动器的个数,默认为1。
- _MULTI_PARTITION设置是否多个分区。不分区,设为0。
- _USE_ERASE设置擦除扇区。在f_mkfs和remove_chain两个函数中添加擦除的代码,设置为0。
- 系统配置
- _WORD_ACCESS设置是否支持字访问。不支持。
- _FS_REENTRANT设置是否重入。因为我们的系统文件访问不是很频繁,而且都是在一个任务中访问,所以不支持重入。
- _FS_TIMEOUT超时设置。
- _SYNC_t访问重入时的同步句柄。
- _FS_SHARE设置文件共享,能同时被几个文件同时打开。设置为0。
二、配置完成后,编译一下程序。此时编译是不会成功的,从错误提示中可见,缺少六个函数disk_initialize,disk_write,disk_read,get_fattime,disk_ioctl,disk_status。这几个函数在diskio.h中有声明,是底层驱动的接口,需要创建diskio.c并自己编写这几个函数。
三、创建diskio.c。
该次测试的SDCARD用的是SPI方式,关于SDCARD的读写和SPI的应用在该博客其它文章中有详细说明,这里就不多讲了,只对FATFS相关文件作说明。
(1)get_fattime——得到系统时间。可以从RTC中获取时间,作为测试,此处只是随便返回一个数。
DWORD get_fattime (void)
{
return ((DWORD)(2010 - 1980) << 25) /* Fixed to Jan. 1, 2010 */
| ((DWORD)1 << 21)
| ((DWORD)1 << 16)
| ((DWORD)0 << 11)
| ((DWORD)0 << 5)
| ((DWORD)0 >> 1);
}(2)disk_initialize——磁盘初始化。这里只用了一个卡,驱动器号为0即可。
DSTATUS disk_initialize (BYTE drv)
{
while(SD_Init()!=0); // SD_Init为SD卡初始化
return 0;
}(3)disk_status——获取磁盘状态。这里直接返回0,表示状态OK,以后再写
DSTATUS disk_status (
BYTE drv /* Drive number (always 0) */
)
{
return 0;
}(4)disk_ioctl——实现控制I/O的特性设置。这里直接返回0表示OK,以后再写
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
return RES_OK;
}(5)disk_read——磁盘读
DRESULT disk_read (
BYTE drv, /* Physical drive nmuber (0) */
BYTE *buff, /* Pointer to the data buffer to store read data */
DWORD sector, /* Start sector number (LBA) */
BYTE count /* Sector count (1..128) */
)
{
if(count>1)
SD_ReadMultiBlock(sector, buff, count);
else
SD_ReadSingleBlock(sector, buff);
return RES_OK;
}(6)disk_write——磁盘写
DRESULT disk_write (
BYTE drv, /* Physical drive nmuber (0) */
const BYTE *buff, /* Pointer to the data to be written */
DWORD sector, /* Start sector number (LBA) */
BYTE count /* Sector count (1..128) */
)
{
if(count>1)
SD_WriteMultiBlock(sector, buff, count);
else
SD_WriteSingleBlock(sector, buff);
return RES_OK;
}四、编译程序成功。开始FATFS的API。
FRESULT res; /* Result code */
FATFS fatfs; /* File system object */
FIL fil; /* File object */
DIR dirs; /* Directory object */
FILINFO finfo; /* File information object */
UINT br;
BYTE buff[128];
char diskname[20] = {"newdir"};disk_initialize(0);
f_mount(0, &fatfs);
res = f_mkdir(diskname); // 新建文件夹,名为newdir
res = f_open(&fil, "123.txt", FA_OPEN_EXISTING | FA_READ); // 打开123.txt 文件
if(res==FR_OK)
{
res = f_read(&fil,buff,sizeof(buff),&br); // 读文件
for(i=0;i<br;i++)
send_data(buff[i]); // 通过串口把读到的数据送到PC,校验正确性
f_close(&fil); // 关闭文件
}
f_mount(0, NULL);