打印

振南的znFAT-单片机上的FAT32文件系统 研发手记

[复制链接]
14037|45
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
znmcu|  楼主 | 2009-12-5 22:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 znmcu 于 2009-12-19 15:54 编辑

#1楼主:znFAT--单片机上的FAT32文件系统 之研发手记**发表于:2009-12-05 22:04
  

znFAT--单片机上的FAT32文件系统  之研发手记

两年前,我开始学习DIY MP3,刚开始我只是直接把MP3文件的数据放在单片机的FLASH中,读取播放。但这样受限于单片机FLASH的容量,使得根本装不下整首的MP3数据,顶多能播放7、8秒钟。这就需要一种大容量的存储器,你可能会说:“用大容量的FLASH ROM芯片就可以了”。不错,用诸如K9F、45DB系列的FLASHROM芯片容量是够大了,但此时也许你也跟我一样碰到了一个问题,MP3文件怎么放入到FLASH芯片中?你可能会说“用烧录器就可以了!”。我要问的话,你见过商场里哪款MP3播放器是需要烧录器的?基本都是通过USB直接拷的,或者是可以扩展存储卡,如SD卡、CF卡,甚至U盘。要用USB把FLASH芯片作成U盘,可以用PDIUSBD12来实现(如果您对这个感兴趣可以看看computer00的USB),对USB有一定了解的,都会知道想把U盘作出来,还是非常复杂的。所以最简单的方法就是使用存储卡,一方面可以使用读卡器,直接在操作系统中把MP3拷入其中,另一方面单片机驱动SD卡的相关资料也比较全,便于研究。
    文件系统的引出就由此而生!!问题是这样的,将MP3文件拷入到SD卡中以后,下面我们要作的就是用单片机来读取SD卡上的数据,以便于播放,拷入的MP3文件数据在SD卡的哪里啊?到哪个扇区中去读啊?我们使用U盘或SD卡等存储设备拷贝电影啊,歌曲啊,都是最平常的事情,你想过没有,这些文件的数据存在SD卡上的什么地方吗?它为什么要存在那个地方?
    为了找到SD卡上的MP3数据,我开始研究相关内容,这些就是FAT32文件系统。研究起来以后,发现已经有很多现成的在单片机上或在ARM等芯片上用的FAT文件系统方案,比如FATFS(这个是最为著名的一个,用得也最多)等等,国内也有几个,比如沁恒的文件系统库(不过他不开源,是商业的东西)、ZLG/FS(他提供的还是应用于ARM上的,在单片机应用的少)等。我也曾经向单片机(我刚开始用的是STC89C58,后来开始用STC12C5A60S2,不过这也是今年才开始用)上去移植这些现成的方案,但移植并不顺利。最后我打算不再用任何现有方案,自己研究自己写。
    于是我开始动手写了一个最原始的方案,这个最原始的方案仅仅可以实现读取根目录下的某个文件,还非常不成熟,同时我在网上发了一篇**《FAT32文件系统的存储机制及其在单片机上的实现》(感兴趣的话可以在网上找一下,不过这篇**里讲的非常肤浅)。我将这个文件系统方案的雏形用于MP3播放实验,实现了读SD卡MP3文件播放的功能。与此同时,我录制了《51单片机实现FAT32文件系统》视频教程(长达500分钟),希望通过通俗全面的讲解,让广大电子爱好者对文件系统有一个初频的了解(不过,现在回想起来,录制视频教程的时候对文件系统的研究仍然还不算深刻)。因为我发现很多人虽然每天在用电脑,每天在听MP3,每天在看电子书,但从不知道有文件系统这种东西存在,从来不纳闷存在扇区中的数据在我们面前怎么就成为了一个个的文件。
    我的SD卡MP3的基本功能虽然实现了,但我又在想:“难道国内就不能有一款开源的,好用的FAT32文件系统的方案吗?”。我在前期研究的基础上,又开始进行更深入的研究。也许你可以在1个月内,甚至1个星期,把文件系统的相关技术手册通读N遍,也可能在理论上搞得很明白(当然需要较高的悟性),但这离最终的实现还相差甚远,或者说只是刚刚起步。一些国外的研究文件系统的组织都是很多人一起倾注很大精力在作的,像EFSL(比利时的开源项目)、FATFS(上面已经提到,它是从大量的wince源代码中剥离出的fat文件系统源代码,微软的代码)等。它们会给我们使用,但不会讲给我们他们是怎么实现的,更重要的一点是,它们一般用于AVR、ARM等芯片上,如果想要在51单片机上使用,不能说不能用,但因为硬件资源有限,所以用起来会有麻烦。所以,我才打算在RAM仅有1K字节的STC国产51单片机上真正作一套功能完备,方便移植的,性能较高,完全从0原创的文件系统方案。
    应用说这项工作工作量很大,主要是我不想仅仅去实现基本的功能,还希望能有功能上的创新。要实现的基本功能有:1、文件系统初始化 2、打开文件 3、读取数据 4、文件重命名 5、复制文件 6、创建文件 7、添加数据 8、创建目录 9、关闭文件  10、获取剩余容量 11、获取总容量  独特具有的功能:我称之为“多设备”(所谓的多设备功能,就是可以在运行的过程中动态的切换存储设备的驱动,说明了就是文件系统可以穿梭于多种存储设备之间,你会问这有什么用?我要说,这里所实现的每一项功能都有非常实际的应用,多设备最典型的应用就是可以在多种设备间进行文件的拷贝,如将SD卡上的某一文件拷贝到CF卡、U盘或是另一张SD卡上)
    最大的工作量并不在于写代码,而在于测试代码和改代码。就像读数据的功能,读从文件里读1000个字节,没有问题,读10000字节呢?仍然不会出错吗?又如打开文件这一功能,如果目录里有5个文件,要打开其中某个文件没有问题,那能保证目录里有10000个文件的时候,打开这个文件仍然没有问题吗?能打开根目录下的文件没有问题,打开\A\B\C\D\E\F\G\H\IJ\K\K\K\K\L\A.TXT这样的深层目录下的文件,也会没问题吗?写入文件数据时,写入1个字节没问题,写入10K的数据也照样没有问题吗?............像这种类似的情况有很多。凭我一个人的力量是不够的,我找了很多网友,给他用我的代码,并将问题反馈给我,我再加以修改。还有一个很重要的途径是通过一些公司实际的工程项目,因为他们会有专门测试的环境,比如频繁读数据、长时间的运行等等。很多问题会在此期间暴露出来。在修改代码的过程中,时常还会发现一些以前没有看到的FAT32更深层的东西。到现在为止,我的文件系统方案已经较为完备,在稳定性与正确性上得到了一定的保障。
    要着重说明的是所实现的一切功能,仅仅用了大约900字节的RAM,其中包括512字节的扇区数据缓冲。
    到后期,我的文件系统开始在网上开源,为了让大家能记住它,我给它起名为znFAT(意为振南的FAT32文件系统方案)。仅仅有znFAT代码是远远不够的,大家感兴趣还是使用znFAT来作的一些实验,比如读SD卡上的TXT文本文件,作电子书;读SD卡上的MP3文件作播放器;读SD卡上的BMP文件,作数码相框;在SD卡与CF卡之间进行文件的互拷;甚至我自己用51的串口作了一个Shell命令接口,来通超级终端敲入命令来实现相应的文件操作(这就是我在网上起名为“仿DOS”的实验)。令我欣慰的是,现在已经有人开始在用znFAT来作一些实验了,说明znFAT真正被人们用起来了。虽然还没有像FATFS等方案那样流行,但它仍然是完全MIC(Made In China)的。
    代码公布出来,并不意味着代码就很成熟,反而会暴露出一些问题。其实最典型的一个问题就是:我提供的znFAT的代码是基于51单片机的KEIL工程,但很多网友并不用51,而用像AVR、STM32、DSP、NIOSII等等。反应一些功能异常。这是对可移植性的很大考验,可移植性要求在不同的硬件条件下,在代码修改量不大的情况下,可以在其上运行,并且功能良好。所以我中途又搞了一阵子STM32(它是一种ARM7核的MCU),最终发现是不同CPU的差异而造成的,说得更具体一些是因为不同CPU的大小端问题。最终成功移植到STM32上,并将代码在网上公布出来。与此同时,一个网友用LM的控制器也跑通了znFAT,并应用于项目,运行良好。
    znFAT从开始作,到现在已有1年多,这期间研究不断深化,现在的znFAT与当初的雏形已有极大的发展。原来的视频教程与文档资料现在已经觉得比较肤浅,所以在打算录制新的视频教程,以求更多的人知道文件系统,知道它的重要。我要说,存储设备的扇区读写好实现,而建立在扇区读写基础上的文件系统的实现,才是思想真正的升华,对研发能力最大的考验。
    为了更广泛的普及文件系统的相关知识,也为了满足很多对文件系统的需求和好奇(您难道没有发现国内,乃至国外,还没有一本专门讲在嵌入式中构建和使用文件系统的书吗?),在努力撰写《振南的znFAT--单片机上的FAT32文件系统》一书。不地写书过程漫长而辛苦,努力早日出来。

   振南赠语
振吓四方博为旨,
南极北斗自来朝。
电挚山河独标新,
子聚吾来弄天狼。
原点出发终有始,
创业何达必亲为。
无尽峰端难攀登,
限在你我掌当中。

相关帖子

沙发
古道热肠| | 2009-12-5 23:06 | 只看该作者
呵呵,我用在MP3播放的文件系统参考了很多沁恒公司的思想,只需512字节的扇区数据缓冲区,我觉得51单片机最好用FAT16文件系统,FAT32用在8位的51上面,速度慢.只需低速读写的应用另当别论.

使用特权

评论回复
板凳
znmcu|  楼主 | 2009-12-5 23:38 | 只看该作者
znFAT的应用绝不仅限于51

使用特权

评论回复
地板
znmcu|  楼主 | 2009-12-5 23:38 | 只看该作者
很多系统的核心是文件系统,文件系统作好,很多东西就可以作了

使用特权

评论回复
5
jimmygaoyang| | 2009-12-17 09:58 | 只看该作者
您好,振南先生,我现在在DSP2812上使用您的znFAT文件系统,效果很好,可是有一个问题,我不能像操作Word一样随意的修改或删除文件中的一部分,我现在是做数据采集,和存储,每次存储2048字节数据,当达到一定容量后再自动删除文件头部分的2048字节,可是2048字节小于一个簇4096字节,为了减少运行时间,我就直接修改的FAT文件表,让首簇变为原来首簇的下一个簇,相当于进行了删簇操作来减少4096字节,可是这样不是长久的解决办法啊,我能不能删除随意大小随意位置的数据呐?

使用特权

评论回复
6
znmcu|  楼主 | 2009-12-17 12:44 | 只看该作者
谢谢对znFAT的支持
你的意思是把文件数据整体向前移动2048字节吗?
据我所知现有的所有文件系统方案都不能完成这一功能
如果你删除了文件某个位置的数据,那个位置就会出现空余,要把后面的数据向前移动,这是比较费时间的。
你所用的方法也比较好,只是你多删了2048字节
你可以用Disk Ginius这个软件把你的SD卡格式化为簇大小为2048,这样你用你的这种方法就可以实现了

你修改了FAT以后,有几点要注意
1、要把原来的首簇设置为0x0000,即空簇
2、在文件的文件项中首簇更新为当前的首簇
3、更改文件项中的文件大小
4、更改FSINFO中的空闲簇数
5、更改FSINFO中的空簇参考值

使用特权

评论回复
7
jimmygaoyang| | 2009-12-17 21:37 | 只看该作者
你好,谢谢振南先生的回答,您的意思是我无法像Word一样操作,那Word里的文件操作,比如说删除一段后点关闭保存时怎样的操作呐?是吧文件内容完全读进内存,修改完后然后再完全重新写进去吗?相当于向文件添加全部数据,文件其实偏移量为0?是吗

使用特权

评论回复
8
jimmygaoyang| | 2009-12-17 21:46 | 只看该作者
有时我还想随意删除文件头部的任意长度的数据,您看有没有好的方法啊,其实我现在是每采集8192点数据进行存储,每个点数是16位整形,这样8192点共占16384字节,就是4个簇的空间,在文件长度达到85M时自动删除文件头部的4个簇。这种方法我也实现了,现在是要在这8192点数据前加上时间信息,也就是说每一次存储的数据正好比16384多一点,我想到文件达到85M是自动删减这堆比16384多点的数据,让每一次能在文件的开头处看到时间信息,这样能实现吗

使用特权

评论回复
9
znmcu|  楼主 | 2009-12-18 11:29 | 只看该作者
在嵌入式中的文件操作,是不可能像在PC上那样的,你如果要在文件头上添加数据,就会造成后面数据大批的后移,效率极低。
你所说的WORD中,确实是在RAM中进行操作,最后再存入文件的,znFAT可以让你自由向文件追加数据,可以定位到文件的某个位置,直接去修改数据,但你想实现在文件任意位置添加数据,就比较难,而且效率也很低。你可以预先把你要添加的数据预先留出来,以后可以到文件这个位置来改。

使用特权

评论回复
10
znmcu|  楼主 | 2009-12-18 12:48 | 只看该作者
还有,不要叫我振南先生,我本身现在还是学生,叫我振南就好,或者叫ZN

使用特权

评论回复
11
jimmygaoyang| | 2009-12-18 15:45 | 只看该作者
你好,振南,听了你的解说,我清楚了,昨天仔细看了一下你说的这五点,前三项我是做了的,就是第四、五项,我没有找见关于FSINFO的相关代码,还不会做
1、要把原来的首簇设置为0x0000,即空簇
2、在文件的文件项中首簇更新为当前的首簇
3、更改文件项中的文件大小
4、更改FSINFO中的空闲簇数
5、更改FSINFO中的空簇参考值
这是我的程序,按找删除文件的函数改写的,没有涉及到FSINFO啊?
void DeletData(struct FileInfoStruct *pfi)
{long Cluster1,Cluster2,Cluster3,Cluster_New_Start;
struct direntry *prec;
FAT32_ReadSector(pfi->Rec_Sec,FAT32_Buffer);//获取头四个簇,然后将其清空
prec=(struct direntry *)(FAT32_Buffer+pfi->nRec);
Cluster1=FAT32_GetNextCluster(pfi->FileStartCluster);
Cluster2=FAT32_GetNextCluster(Cluster1);
Cluster3=FAT32_GetNextCluster(Cluster2);
Cluster_New_Start=FAT32_GetNextCluster(Cluster3);//找寻到新的首簇 Cluster_New_Start
FAT32_Modify_FAT(pfi->FileStartCluster,0x00000000);
FAT32_Modify_FAT(Cluster1,0x00000000);
FAT32_Modify_FAT(Cluster2,0x00000000);
FAT32_Modify_FAT(Cluster3,0x00000000);

pfi->FileStartCluster=Cluster_New_Start; //更改文件首簇到Cluster_New_Start
pfi->FileSize=pfi->FileCurOffset-16384;//更改改文件大小
pfi->FileCurSector=SOC(pfi->FileCurCluster);
pfi->FileCurOffset=pfi->FileCurOffset-16384;
FAT32_ReadSector(pfi->Rec_Sec,FAT32_Buffer);//修改FAT表首簇号
(prec->deHighClust)[0]=(Cluster_New_Start&0x00ff0000)>>16;
(prec->deHighClust)[1]=(Cluster_New_Start&0xff000000)>>24;
(prec->deLowCluster)[0]=(Cluster_New_Start&0x000000ff);
(prec->deLowCluster)[1]=(Cluster_New_Start&0x0000ff00)>>8;
   FAT32_WriteSector(pfi->Rec_Sec,FAT32_Buffer);

  FAT32_ReadSector(pfi->Rec_Sec,FAT32_Buffer);//修改文件大小
  (((struct direntry *)(FAT32_Buffer+pfi->nRec))->deFileSize)[0]=((pfi->FileCurOffset)&0x000000ff);
  (((struct direntry *)(FAT32_Buffer+pfi->nRec))->deFileSize)[1]=((pfi->FileCurOffset)&0x0000ff00)>>8;
  (((struct direntry *)(FAT32_Buffer+pfi->nRec))->deFileSize)[2]=((pfi->FileCurOffset)&0x00ff0000)>>16;
  (((struct direntry *)(FAT32_Buffer+pfi->nRec))->deFileSize)[3]=((pfi->FileCurOffset)&0xff000000)>>24;
  FAT32_WriteSector(pfi->Rec_Sec,FAT32_Buffer);
}

使用特权

评论回复
12
znmcu|  楼主 | 2009-12-18 16:07 | 只看该作者
FAT32与FAT16不同点之一就是FAT32有FSINFO,其中就可以直接读出来磁盘剩余容量和下一个可以用的空闲簇,当然FSINFO也需要程序来进行维护。

也许你有这种经历,使用CH375配套的沁恒文件系统库时,在获取U盘的剩余容量时,FAT32可以马上得到结果,而FAT16就要等一段时间才能得到结果。就是因为FAT16没有FSINFO,所以程序要由FAT表来统计容量,这时间就长了。

FSINFO是我研发文件系统后期才发现的一个区域。它的位置在DBR的后一个扇区

使用特权

评论回复
13
znmcu|  楼主 | 2009-12-18 16:18 | 只看该作者
谢谢

使用特权

评论回复
14
kk2614755| | 2009-12-19 11:39 | 只看该作者
呵呵,等你的书出了在看看先,  我看过你那个文件系统,   一团乱码,   或许是我功力不够吧,

使用特权

评论回复
15
znmcu|  楼主 | 2009-12-19 13:39 | 只看该作者
由于文件系统本身的复杂性,如果没有基础,看起来确实就是一团乱码
正是由于文件系统代码有些庞杂,所以才有了出书的念头,让带读者一起来剖析
我尽力让代码条理清晰一些,方便大家的学习和使用
谢谢

使用特权

评论回复
16
luck851| | 2009-12-19 22:36 | 只看该作者
标记一下有时间好好研究一下

使用特权

评论回复
17
headwolf_83| | 2009-12-20 00:11 | 只看该作者
如果要做商业应用,可能更多人会选择大公司开发的,比如ZLG,MICROCHIP,这是我了解到的。

使用特权

评论回复
18
headwolf_83| | 2009-12-20 00:19 | 只看该作者
如果你不打算把这个FAT做到中国知名以及于知名度匹配的完善,以便有更多的人能用于商业应用,把这个时间抽出来做其它,你可以得到更全面的提高。
技术员都有玩技术的倾向,但是做产品开发,却最怕技术员玩技术。而技术员如果太喜欢玩技术,而不是更多考虑产品和自己的发展,也是不大好。不过趁着还是学生,多玩一下技术是好的,毕业了,就没那么多时间了。加油。

使用特权

评论回复
19
znmcu|  楼主 | 2009-12-20 01:52 | 只看该作者
znFAT刚开始源于兴趣,已经作了1年多,中间经历无数次测试,包括多次在工程上的应用。也暴露出无数的问题,都在发现后得到我改进和修复。从而保证其正确性与稳定性。
znFAT的研发初衷在于解决实际的问题,满足实现的需求。是希望它能被更多人知道,更多人用起来,我把代码全部开源的原因也就在于此。
不光用起来,还让有兴趣的人可以有机会来研究学习。这就是要出教程与书的原因了。

学生确实是喜欢玩技术,把技术当成是玩具来找乐趣。本身我现在是研三的学生,现在的时间确实不多了。
尽力把自己研究的东西作到完善。
当然希望有更多的人来用我的znFAT,来感觉它到底怎么样。
在EDNCHINA那边有小组我已经发了10个应用实例,大家可以过去看看。
http://group.znmcu.cn/

使用特权

评论回复
20
znmcu|  楼主 | 2009-12-20 01:54 | 只看该作者
FATFS ZLGFS UCFS固然好,但它不会配上教程,配上书,告诉你它是怎么实现的,内部技术有哪些,细节是怎样的,如果要自己写文件系统方案,应该怎么作。这是我研究文件系统的初衷。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:振南的znFAT -- 单片机上上的FAT32文件系统 www.znmcu.cn

4474

主题

5195

帖子

33

粉丝