首页资源分类嵌入式系统 > 一篇比较详细介绍FatFs文件系统移植的文章

一篇比较详细介绍FatFs文件系统移植的文章

已有 445117个资源

下载专区

上传者其他资源

    文档信息举报收藏

    标    签:FATFS

    分    享:

    文档简介

    一篇比较详细介绍FatFs文件系统移植的文章

    文档预览

    博客广告 标签: 文件系统 FATFS 转一篇比较详细介绍 FatFs 文件系统移植的文章 FatFs 文件系统的移植 因为需要,又不想自己写,所以就移植了一个文件系统。 说下我的硬件和开发工具:接成 TRUE IDE 模式下的 CF 卡(也就是相当 于一块硬盘了),三星 S3C2440的 ARM9,开发工具是很老很老的 D 版的 ADS1.2。 我在网上看到的嵌入式系统上面常用的文件系统有 UCOSII 公司的 UC/FS, 支持 CF 卡,硬盘,SD/MMC 卡,还有 NAND FLASH 等等,比较多,不过是商 用的,需要银子的,有周立功的用于教学用(为什么说是用于教学用的,呵呵, 等下就说)的 ZLG/FS,还找到了开源、免费的两个,其中一个叫做 efsl ,另 一个叫做 FatFs 。 现在先不考虑版权的问题,选择一个比较合适的文件系统。第一个 UC/FS 文件系统没得什么说的,UCOSII 那个公司开发的,稳定性,兼容性应该都不会 差。第二个是 ZLG/FS。周立功的很多的开发板上面都送了这个文件系统的源代 码的,在网上找到一个现成的读写硬盘的,只是是基于 LPC2200系列的处理器 的。第三个是 efsl,是一个开源的项目,免费,只需要提供读扇区和写扇区2个函 数。第四个是 FatFs,跟 efsl 一样,也是一个开源的项目,移植的时候比 efsl 多几 个简单的函数。 这里补充一下 CF 卡和硬盘的简单的资料,CF 卡有三种模式,其中有一个叫 TRUE IDE,接成这个模式以后,就跟他的模式名字一样,他就是一个硬盘,对他 进行读写,也就相当于对一个硬盘进行读写。当引脚 OE(好像是叫 OE,具体参考 CF 卡文档)在上电的时候检测到拉低,那么 CF 卡就进入 TRUE IDE 模式。读写 硬盘的时候,在只写一次 LBA,只发送一个命令(读或者写)的情况下,最多可以 读或者写256个扇区(当然也可以读一个扇区,读或者写多少个扇区在扇区计数器 count 里面),其中,发一个读或者写命令,读或者写256个扇区所需要的时间,比 分256次去读写这些扇区所需要的时间要短得多,效率要高得多,我现在需要的是 一个读写的速度比较快,效率比较高的文件系统,因此,底层的读写扇区必须要每 写一个命令就可以读写多个扇区,读写扇区的函数必须要有扇区计数器(前面的 count)这个参数,才可能满足要求。 UC/FS 也是在网上搜了个代码,看了下,很标准的几个层,什么硬件层,文件 系统层,API 层,等等(具体参见 UC/FS 的文档),跟 UCOSII 一个公司的,稳定 性应该不错,需要提供的函数也是读扇区,写扇区等等几个。但是底层的读写扇区 的函数不需要提供扇区计数器 count 这个参数,也就是说,这个文件系统不能在只 写一个读或者写命令的情况下,读或者写多个扇区,本来效感觉不错的一个文件系 统,效率就大大的降低了。 然后看了下 efls 这个文件系统,开源的项目,免费的项目,好东西,移植也 很简单,同样移植的时候也是提供读写扇区等几个函数,但是面临的跟 UC/FS 同样的问题,每次读写的时候也只能读写一个扇区。 绝望之余看到了周立功的文件系统,大概看了下(没有仔细阅读源代码), 硬件驱动上面能够在发一次读命令的情况下,读写多个扇区,而且感觉上比较简 单,同样,层次也很清楚,移植需要做的事情也是修改后面的读写扇区等等几个 函数。于是就开干了。功夫不负苦心人,过了几天,CF 卡能够读写了,拿到电 脑上面看写的数据,没问题。从 CF 卡里面读文件出来,打印到超级终端,也没 有问题,以为就万事 OK 了,想了下,我们需要的,最关心的,第一是速度,然 后就开始测试速度,不测不知道,一测吓一跳!太“快”了,TMD,才5,6个 K Bytes 每秒!!!!!(我的驱动已经测试了,上 M 字节每秒的) 于是跟踪到写里 面去,发现一个很,十分,非常严重的问题:ZLG/FS 提供了读一个字节的函数, 忘了叫做啥,这里暂时叫 ReadOneByte(***),然后读多个字节,或者说读大 块字节的函数用的是啥,呵呵, for(i=0;i < N ; i++) ReadOneByte(***),这种机制,不慢才怪事!!!于 是伤心的抛弃了 ZLG/FS,这东东,学习还是可以的,商用的话,差太远了!!! 我那点东西,文件系统可以不上,但是必须有个文件存储协议,或者说叫做 自己的文件系统,自己写个简单的存储协议,试过,很麻烦。但是如果上文件系 统,自己写的话,写要累死人的,写出来的不一定效率就高,速度就快,所以, 还是在网上漫无目的的找,觉得应该有效率很高的文件系统的。 还是那句话,功夫不负苦心人,终于让我找到了,也就是现在所用的,FatFs, 开源,免费,高效!(说一下这里几个文件系统都有的一个缺点,由于微软的 FAT 版权的问题,FatFs,ZLG/FS,efsl 都只支持 DOS 8.3 文件名,即8个字 节的文件名,一个”.“,然后3个字节的扩展名,我找到的那个 UC/FS 也不支持, 不知道在更新的版本里面支持不,看哪天有空了,把那个 FatFs 改下,让他支持, 呵呵)。FatFs 的底层可以写一次命令,读写多个扇区。FatFs 的设计的 读写的思想就很好,小块的数据,我就经过 Buffer 来存储,大块的数据, 我就直接进行存取,那样速度,效率高了很多,看图: FatFs 文件系统的结构也很清晰,也是看图: 补充一点,FatFs 的作者写了两个,一个是正宗的 FatFs,比较适合大的 RAM 的设备,另一个是 FatFs/Tiny,比较适合小 RAM 的系统,比如单片机,FatFs/Tiny 占用较小的 RAM,代价是更慢的读写速度和更少的 API 函数。不过两个都支持 FAT12,FAT16,FAT32文件系统。 下载下来的 FatFs 的 FatFs 有两个文件夹,一个是 doc ,FatFs 的说明, 包括特性,系统函数,以及可能的一些问题,另一个就是源代码文件夹 src 了, 总共8个文件,diskio.c 和 diskio.h 是硬件层,ff.c 和 ff.h 是 FatFs 的文件系统层 和文件系统的 API 层,integer.h 是文件系统所用到的数据类型的定义,tff.c 和 tff.h 是 Tiny 的文件系统层和文件系统的 API 层,还有一个00readme.txt 简要的 介绍了 FatFSHE FatFs/Tiny,包括他们所支持的 API,怎么配置等等。 移植的问题,第一个是数据类型,在 integer.h 里面去定义好数据的类型。 第二个,就是配置,打开 ff.h(我用的 FatFs,不是 Tiny),_MCU_ENDIAN, 选择你的 CPU 是大端存储(big endding)还是小端存储(little endding),一 般的都用的小端存储,1是小端,2是大端。这个相当重要,一会儿还要谈到这 里。其他的,按照自己的需要来配置了,说明文档够清楚了,我就不多说啥了。 第三件事情,就是写底层的驱动函数,包括: • disk_initialize- Initialize disk drive • disk_status- Get disk status • disk_read- Read sector(s) • disk_write- Write sector(s) • disk_ioctl- Control device dependent features • get_fattime- Get current time 所有的函数都牵涉到了选择第几个磁盘的问题,如果仅仅用一个,可以不必理会 这个 drv 参数。 disk_initialize,如果不需要的话,直接返回 0 就行 disk_status,这个嘛,先不管了,直接返回 0 就 OK disk_read- Read sector(s) disk_write- Write sector(s) 读写扇区,注意参数哦! disk_ioctl 需要回应 CTRL_SYNC,GET_SECTOR_COUNT, GET_BLOCK_SIZE 三个命令,正确返回 0 即 RES_OK,不正确返回 RES_ERROR。 所有的命令都从 ctrl 里面去读,返回值仅仅返回这次操作是否 有效,而需要传递回去的数据在 buff 里面,以下是我的: CTRL_SYNC 命令,直接返回 0; GET_SECTOR_COUNT,得到所有可用的扇区数目 (逻辑寻址即 LBA 寻址方式) GET_BLOCK_SIZE,得到每个扇区有多少个字节,比 如 *((DWORD*)buff) = 512; 其他的命令,返回 RES_PARERR disk_ioctl 这个函数仅仅在格式化的时候被使用,在调试读写的时候,这个函数 直接让他返回 0 就 OK 了。 get_fattime- 得到系统的时间,格式请见文档。不用的话,返回 0 就行。 这样移植了,也基本上就成功了,但是在我的板子上面死活不行,每次一执行到 几个宏定义比如 LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) 就产生数据终止异 常( DATA ABORT exception),但是网上的一个兄弟的(ouravr 上的一个兄 弟,用的 SD 卡,IAR 编译器,平台是 STM32,已经成功了,还公布了源码的, 这里没有问题啊),没问题。分析下这个几个宏的意思: LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))是在 little endding 里面定义的 LD_WORD(ptr) ,LD 就是 load,WORD 在 integer.h 里面定义的是 16 位的无 符号数,那这个需要完成的就是载入一个 16 位的数,或者说是 2 个字节,后面 的 ptr 是参数。(WORD)(*(WORD*)(BYTE*)(ptr)) ,先将这个 ptr 转换成一个指 向 BYTE 类型数据的指针(BYTE *),在将这个指针转换成一个指向 16 位无 符号数的指针(WORD *),然后用一个 ” * “将这个数据取出来,转换成一个 无符号的 16 位数据,这个仅仅从 C 语言的角度来看,实际上呢,这个完成的就 是从 ptr 指针指向的位置,取出 2 个字节,作为一个 16 位的无符号数取出,而 这 2 个字节是 little endding,即小端模式,低字节是低 8 位,高字节是高 8 位。 既然是这样的,测试了下,定义了一个 BYTE buf[512],定义一个 WORD 类型 zz, 用一个指针 pt,让 pt 指向 buf[0],调用 LD_WORD(ptr),zz=LD_WORD(pt);没问题,将 pt 指向 buf[1], 呵呵,问题马上出来了,数据终止异常,然后测试了指针指向 buf[3],buf[5]等 等奇数个,都是这样的问题,我就郁闷了啊,TMD,编译器的问题!!!!不 过还好,找到问题了,就可以解决问题了,在 ff.h 里面的宏定义里面把这即个 东东给注释掉,然后在 ff.c 里面把这几个宏定义写成函数,这里贴一个出来: WORD LD_WORD(void *pt) BYTE *PT = (BYTE*)pt; { //定义一个指针,将当前的指针指向的地址的 值赋给 PT return (WORD)(PT[0]+PT[1]*256); //计算这个 16 位数,(低 8 位在前面, 高 8 位在后面),并来个强制类型转 //换,并返回 } 需要注意的是,LD_WORD 返回的就必须是 WORD。这样做了,编译器大部分 的也可以编译通过,但是 ADS 就是通不过,有 3 个地方, finfo->fsize = LD_DWORD(&dir[DIR_FileSize]); /* Size */ finfo->fdate = LD_WORD(&dir[DIR_WrtDate]); /* Date */ finfo->ftime = LD_WORD(&dir[DIR_WrtTime]); /* Time */ 其中,dir 的是这样定义的:const BYTE *dir,编译器报错是类型不匹配,因此, 这里的几个 LD_WORD 和 LD_DWORD 重写,定义成一致的类型即可: WORD LD_WORD_1(const BYTE *pt) { BYTE *PT = (BYTE*)pt; return (WORD)(PT[0]+PT[1]*256); } DWORD LD_DWORD_1(const BYTE *pt) { BYTE *PT = (BYTE*)pt; return ((DWORD)PT[0]+(DWORD)(PT[1]*256)+(DWORD)(PT[2]*65536)+(DWORD)( PT[3]*16777216)); } 而后面改成: finfo->fsize = LD_DWORD_1(&dir[DIR_FileSize]); finfo->fdate = LD_WORD_1(&dir[DIR_WrtDate]); finfo->ftime = LD_WORD_1(&dir[DIR_WrtTime]); /* Size */ /* Date */ /* Time */ 编译,一路 OK,然后写一个文件,哇,哈哈哈哈!!!!终于出来了!!!! 写文件没问题,读也没问题!@~~~~~测试了常用的函数,都没有问题,包括格 式化(f_mkfs,前提是你的 disk_ioctl 没问题),测试 了下速度,读 12.5M 的 MP3,大约 3 秒,写这个 12.5M 的 MP3 大约 6.5 秒, 勉强达到要求,再优化下驱动那边就可以更快了!~~~~~~~ 发个 FatFs 的官方网址 http://elm-chan.org/fsw/ff/00index_e.html 总结这次移植,差点失败就在于编译器的指针的转换问题,写出来,希望兄弟姐 妹们在移植的时候不会遇到这种问题。

    Top_arrow
    回到顶部
    EEWORLD下载中心所有资源均来自网友分享,如有侵权,请发送举报邮件到客服邮箱bbs_service@eeworld.com.cn 或通过站内短信息或QQ:273568022联系管理员 高进,我们会尽快处理。