在pc机上移植fatfs文件系统(windows/linux) (一)
开始我的技术生涯~
哈哈,老大给我分配了一个以前都没接触到的任务。在PC机上移植fatfs文件系统。以前我认为的移植是调用底层提供的API接口,在PC机上模拟,测试通过后再移植到目标板上。这次的移植竟然是移植到PC机上。
我的开始考虑到的硬件基础:文件系统要在硬件存储介质上运行,例如u盘啊、SD卡啊。那这次没有硬件设备,怎么模拟呢。diskio.c是和底层硬件相关的文件。解决方案是用创建一个具有一定大小的文件来作为存储载体。
开始有了一点思路。我就开始了人生的第一次移植。
fatfs下载地址:http://elm-chan.org/fsw/ff/00index_e.html 工作后,搜索引擎就从百度转到了谷歌。嵌入式的很多重要资料都是外文文献。难堪啊,还好有谷歌浏览器,可以翻译网页~~ 强大 哈哈。
我用的是fatfs 0.08b 最新版。 0.08b版本多了几个API接口。并且前辈们反映移植遇到的问题 解决了。
下到了源代码

有2个文件夹。doc 里面我没仔细看。 src里面就是源代码 了。

diskio.c是自己写的。是一些贴近底层硬件的函数。
我看了CSDN里面一些前辈关于移植fatfs的资料。首先第一步就是配置ffconf.h
fatfs有2个版本。一个是tiny版本。这个版本适合比较小的RAM,eg:单片机。我用的是正常版。#define_FS_TINY0/* 0:Normal or 1:Tiny */
因为 移植后要测试读与写是否匹配,所以设置为读写功能。#define _FS_READONLY 0/* 0:Read/Write or 1:Read only */
#define _FS_MINIMIZE3/* 0 to 3 */ 我用了全部功能,因为没要求要裁剪。这个具体实现以后再慢慢琢磨。
#define_USE_MKFS1/* 0:Disable or 1:Enable */ 如果是在PC机上模拟,这个必须设置成1.因为这个参数,我搞了1天。下面再详述。
#define _CODE_PAGE936 简体中文
#define_MAX_SS512/* 512, 1024, 2048 or 4096 */ 一个扇区512字节
#define_USE_ERASE1/* 0:Disable or 1:Enable */ 具备擦除功能,这个功能 我目前还没测试过。
#define _WORD_ACCESS0/* 0 or 1 */
配置好ffconf.h,就可以开始写diskio.c了。
DSTATUS disk_initialize(BYTE drv)
{
return 0;
}
这个函数是用来初始化disk的。 因为这里没有硬件,所以直接return 0.
DSTATUS disk_status(BYTE drv)
这个函数嘛,是用来获取硬件状态的。我用文件模拟,就随便写了,可以正常打开就返回Ok,否则就返回错误代码
DRESULT disk_read(BYTE drv, BYTE *buff, DWORD sector, BYTE count)
{
FILE *fp = NULL;
DWORD ulSeek = 0;
unsigned long nRead = 0;
int nSeekRes = 0;
DRESULT res = RES_OK;
if (drv || !count)
{
//Only support a single disk operation
//count is not equal to 0, otherwise parameter error
printf("param err!\n");
return RES_PARERR;
}
if((fp=fopen(DISKNAME, "r+")) == NULL)
{
printf("disk no ready!\n");
return RES_NOTRDY;
}
ulSeek = sector*512;
if(((nSeekRes = fseek(fp, ulSeek, SEEK_SET)) == 0) && ((nRead = fread((void *)buff, _MAX_SS, count, fp)) != 0))
{
printf("read disk OK!\n");
}
else
{
printf("Out of range Or ...\n");
res = RES_ERROR;
}
fclose(fp);
return res;
}
disk_read 是用来读取扇区数据的。可以偏移访问。开始的时候忘记单位了,ulSeek = sector,后来经过永都提醒,才注意到这个错误。不然调用格式化函数的时候一直不能正常返回。读取都是数量级扇区读取的。
disk_write和disk_read函数大同小异,这里不多描述了。
disk_ioctl,开始的时候我直接return 0。到后来需要调用格式化函数,那就必须实现disk_ioctl功能了。0.08b版本目前支持以下5种命令。
#define CTRL_SYNC0/* Flush disk cache (for write functions) */
#define GET_SECTOR_COUNT1/* Get media size (for only f_mkfs()) */
#define GET_SECTOR_SIZE2/* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */
#define GET_BLOCK_SIZE3/* Get erase block size (for only f_mkfs()) */
#define CTRL_ERASE_SECTOR4/* Force erased a block of sectors (for only _USE_ERASE) */
*(DWORD*)buff = (128-1)*32;
GET_SECTOR_COUNT 用来读取扇区个数的。我创建存储载体的思想是这样的sector=512字节。
今天就先写到这。明天继续。~
赶早继续~
每个扇区512字节,我创建一个2M的文件。开始的时候我不知道一个簇几个扇区,后来调试程序的时候才看到内部数组,一个簇2个扇区。我是模拟NAND FLASH。一个page512字节,每个块有32个page,2M的文件有了128个块。文件的第一块用来作为系统块。所以扇区大小要扣除系统块。
写完diskio.c,就开始写测试代码。
首先必须创建一个文件,并赋予一定大小。我是通过读写来测试的。
1、调用f_mount函数。 一般挂载不会出现什么问题。
2、开始的时候我没调用f_mkfs(0,0,0),直接打开文件。打开文件会一直失败。
3、深入研究下fopen。fatfs文件系统有对象的概念。chk_mounted用来检查文件系统对象是否有效。调试遇到的问题就卡在fmt = check_fs(fs, bsect = 0);/* Check sector 0 if it is a VBR */。 该函数是用来加载引导记录并且检测是否为FAT映射表(应该是这个意思)。
static
BYTE check_fs (/* 0:The FAT BR, 1:Valid BR but not an FAT, 2:Not a BR, 3:Disk error */
FATFS *fs, /* File system object */
DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
)
{
if (disk_read(fs->drv, fs->win, sect, 1) != RES_OK)/* Load boot record */
return 3;
if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55)/* Check record signature (always placed at offset 510 even if the sector size is >512) */
return 2;
if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146)/* Check "FAT" string */
return 0;
if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
return 0;
return 1;
}
先来说说return 3的2种场景吧:
1)、创建一个空文件,没有赋予大小,没有格式化
2)、后来听老大说,可以创建一个img文件。就自己去网上找了相关资料。成功的创建了一个FAT12/16 的2M大小img文件。经测试,执行fopen成功。但是fwrite和fread是失败的。我自己考虑了下,应该是文件操作不能直接对img文件进行读写。
如果是return 2,那么就是你没有格式化文件。

上图为测试结果。
测试结果我直接用UE工具打开载体文件。

在0x00010000H处有数据进入。
fat文件系统分区解读,查看链接:http://199818.blog.51cto.com/189818/32679

浙公网安备 33010602011771号