摘要:介紹了面向閃存類設(shè)備的嵌入式文件系統(tǒng)。提出了一種不依靠任何操作系統(tǒng),以單片機(jī)和閃存類設(shè)備為硬件基礎(chǔ)的,依照FAT類型文件系統(tǒng)所構(gòu)建的嵌入式主機(jī)文件系統(tǒng)的設(shè)計(jì)思路,詳細(xì)地、分模塊地對(duì)該系統(tǒng)進(jìn)行了分析,并在實(shí)際開(kāi)發(fā)和應(yīng)用中已經(jīng)得到了驗(yàn)證。
關(guān)鍵詞:嵌入式文件系統(tǒng); 單片機(jī); 閃存類設(shè)備; 文件分配表
中圖分類號(hào):U463.211文獻(xiàn)標(biāo)志碼:A
文章編號(hào):1001-3695(2008)03-0814-02
數(shù)據(jù)采集儀作為故障診斷的前端采集器,廣泛地應(yīng)用在工業(yè)生產(chǎn)的各個(gè)領(lǐng)域中。其中,數(shù)據(jù)存儲(chǔ)技術(shù)是數(shù)據(jù)采集儀的關(guān)鍵技術(shù)之一。考慮到數(shù)據(jù)采集儀的現(xiàn)場(chǎng)工作環(huán)境惡劣,對(duì)數(shù)據(jù)存儲(chǔ)介質(zhì)的要求有如下幾個(gè)特點(diǎn):體積小、可靠性高、存取速度快、通用性好。閃存類存儲(chǔ)設(shè)備在單片機(jī)系統(tǒng)中得到了廣泛的應(yīng)用,常見(jiàn)的有USB電子盤、閃存卡等。其中閃存卡包括MMC卡、CF卡、SD卡,還有SONY的Memory Stick。
為了能在數(shù)據(jù)采集儀與PC之間進(jìn)行交互,必須按照一定的標(biāo)準(zhǔn)來(lái)組織數(shù)據(jù)。通常采用的方法就是在其中嵌入文件系統(tǒng)。目前,市場(chǎng)上存在多種商用的嵌入式操作系統(tǒng)可以支持文件系統(tǒng),如XPE等。但與之對(duì)應(yīng)的是,上述的操作系統(tǒng)對(duì)硬件的要求很高,而且價(jià)格昂貴,并且對(duì)存儲(chǔ)空間也有一定的額外要求。但目前數(shù)據(jù)采集儀中有很多采用的是8位或者16位的MCU,較少使用操作系統(tǒng),即使采用操作系統(tǒng)往往也并不支持文件系統(tǒng)。所以,很有必要開(kāi)發(fā)一種面向移動(dòng)存儲(chǔ)介質(zhì),而且不依賴于操作系統(tǒng)的標(biāo)準(zhǔn)文件系統(tǒng)。
1系統(tǒng)概述
本文所討論的文件系統(tǒng)是依照集中索引文件系統(tǒng)所建立的。集中索引文件系統(tǒng)是目前最常用的基于磁盤存儲(chǔ)器的文件系統(tǒng),包括Windows的FAT系列和基于Linux的Ext系列。所謂的集中索引文件系統(tǒng),是將存儲(chǔ)器的使用信息和文件的索引信息集中存放在存儲(chǔ)區(qū)的固定位置。
閃存設(shè)備可以通過(guò)使用閃存轉(zhuǎn)譯層(FTL)驅(qū)動(dòng)而模擬成與磁盤相似的塊設(shè)備,所以該類設(shè)備均可以通過(guò)調(diào)用相應(yīng)的驅(qū)動(dòng)程序,從而按照集中索引文件系統(tǒng)來(lái)管理數(shù)據(jù)。考慮到數(shù)據(jù)轉(zhuǎn)換和使用方便,本文件系統(tǒng)主要實(shí)現(xiàn)的是基于FAT16類文件系統(tǒng)格式化的閃存類設(shè)備的數(shù)據(jù)文件的讀寫。
文件系統(tǒng)是一個(gè)獨(dú)立的整體,并且有明確的模塊劃分,能夠使該文件系統(tǒng)在對(duì)文件系統(tǒng)格式支持收納該具有很好的擴(kuò)展性,對(duì)文件系統(tǒng)的設(shè)備管理上也實(shí)現(xiàn)了設(shè)備無(wú)關(guān)性。
本文件系統(tǒng)模塊如圖1所示。
用戶接口(文件系統(tǒng)API)模塊:對(duì)文件系統(tǒng)進(jìn)行最后的封裝,對(duì)用戶提供文件系統(tǒng)的API接口,用戶可以直接調(diào)用該模塊的函數(shù)進(jìn)行文件級(jí)的操作;文件系統(tǒng)模塊:主要實(shí)現(xiàn)FAT文件系統(tǒng)中間級(jí)函數(shù);
設(shè)備驅(qū)動(dòng)管理模塊:主要實(shí)現(xiàn)對(duì)文件設(shè)備驅(qū)動(dòng)程序的管理,最終實(shí)現(xiàn)文件系統(tǒng)的設(shè)備無(wú)關(guān)性,通過(guò)通用的函數(shù)接口來(lái)實(shí)現(xiàn)對(duì)各種閃存類設(shè)備底層物理意義的讀寫。
2設(shè)備驅(qū)動(dòng)管理模塊
閃存類設(shè)備可以通過(guò)閃存轉(zhuǎn)譯層(FTL)驅(qū)動(dòng)而模擬成塊設(shè)備,所以本文件系統(tǒng)的設(shè)備驅(qū)動(dòng)管理模塊作為整個(gè)文件系統(tǒng)最底層的模塊可以被上兩層的模塊直接調(diào)用。物理上來(lái)看,閃存類設(shè)備均可以由扇區(qū)組成,每扇區(qū)512 Byte,均采用邏輯塊尋址方式LBA(logical block addressing)。
2.1控制器驅(qū)動(dòng)層
塊設(shè)備控制器驅(qū)動(dòng)是設(shè)備驅(qū)動(dòng)層最底層的函數(shù),是MCU與塊設(shè)備的通信接口,通過(guò)數(shù)據(jù)線、讀寫控制線、片選線完成對(duì)塊設(shè)備或塊設(shè)備控制器的I/O讀寫等操作,可為上層驅(qū)動(dòng)提供對(duì)塊設(shè)備的訪問(wèn)接口。不同的閃存類設(shè)備依照自身的硬件特點(diǎn),接口電路也不盡相同。例如MMC卡、CF卡可直接與MCU通信,而USB電子盤則必須通過(guò)接口芯片與MCU進(jìn)行通信。用戶可根據(jù)所選用的閃存設(shè)備以及自身硬件電路的特點(diǎn)來(lái)選擇這部分的驅(qū)動(dòng)程序。
例如在本實(shí)驗(yàn)室自主開(kāi)發(fā)的基于C8051F124的與MMC卡和USB電子盤的存儲(chǔ)模塊中,塊設(shè)備的控制器驅(qū)動(dòng)層如下:
a)C8051F124與MMC卡通過(guò)SPI通信的驅(qū)動(dòng)程序
INT8U MMCdatachange(uchar Bdata)
{
SPIODAT=Bdata;
while(!SPIF);
SPIF=0:
return SPIODAT;
}
b)C8051F124通過(guò)USB主機(jī)接口芯片CH375與USB電子盤通信的驅(qū)動(dòng)程序
CH375命令端口的I/O地址:INT8U volatilexdataCH375_CMD_PORT _at_ 0xBDF1;
CH375數(shù)據(jù)端口的I/O地址:INT8U volatilexdataCH375_DAT_PORT _at_ 0xBCF0;
寫入一個(gè)命令字節(jié):void CH375_WR_CMD_PORT(INT8U cmd);
寫入一個(gè)數(shù)據(jù)字節(jié): void CH375_WR_DAT_PORT(INT8U dat);
讀出一個(gè)命令或數(shù)據(jù)字節(jié): INT8U CH375_RD_DAT_PORT(void)。
2.2塊設(shè)備驅(qū)動(dòng)層
無(wú)論什么樣的閃存類設(shè)備,由于閃存類設(shè)備特有的物理結(jié)構(gòu),對(duì)閃存類設(shè)備進(jìn)行數(shù)據(jù)的讀寫均是以扇區(qū)為單位進(jìn)行的。通過(guò)調(diào)用底層的控制器驅(qū)動(dòng)程序,從而實(shí)現(xiàn)對(duì)物理扇區(qū)的讀寫。直接以物理扇區(qū)為單位讀寫的函數(shù)如下:
a)從塊設(shè)備中讀取多個(gè)扇區(qū)的數(shù)據(jù)塊到緩沖區(qū)
INT8U RBC_Read(INT32U iLbaStart, INT8U iSectorCount, INT8U *mBufferPoint);
b)將緩沖區(qū)中的多個(gè)扇區(qū)的數(shù)據(jù)塊寫入到塊設(shè)備
INT8U RBC_Write( INT32U iLbaStart, INT8U iSectorCount, INT8U *mBufferPoint );
參數(shù)說(shuō)明:
iLbaStart讀取的線性起始扇區(qū)號(hào);
iSectorCount讀取的扇區(qū)數(shù);
*mBufferPoint指向數(shù)據(jù)緩沖區(qū)的指針。
3文件系統(tǒng)應(yīng)用程序模塊
3.1文件系統(tǒng)邏輯結(jié)構(gòu)劃分
主引導(dǎo)區(qū)(MBR)從塊設(shè)備的物理第一個(gè)扇區(qū)開(kāi)始,存放了塊設(shè)備的邏輯結(jié)構(gòu)信息和介質(zhì)標(biāo)志等,系統(tǒng)每次訪問(wèn)該設(shè)備時(shí),都要對(duì)引導(dǎo)區(qū)內(nèi)的信息進(jìn)行識(shí)別。該數(shù)據(jù)結(jié)構(gòu)中包含了對(duì)文件分區(qū)描述的基本信息,非常重要的有每扇區(qū)的字節(jié)數(shù)、每簇的扇區(qū)數(shù)、FAT 表數(shù)目、目錄項(xiàng)數(shù)、文件分區(qū)中的扇區(qū)數(shù)、每個(gè)FAT 表占用的扇區(qū)數(shù)。主引導(dǎo)區(qū)的數(shù)據(jù)結(jié)構(gòu)定義如下:
typedef struct BPB_BLOCK
{
uchar bJmpBoot[3];//ofs:0.典型的如:0xEB、0x3E、0x90
char bOEMName[8]; //ofs:3.典型的如:MSWIN4.1
uint BPB_wBytesPerSec; //ofs:11.每扇區(qū)字節(jié)數(shù)
uchar BPB_bSecPerClus; //ofs:13.每簇扇區(qū)數(shù)
uint BPB_wReservedSec;
//ofs:14.保留扇區(qū)數(shù),從DBR 到FAT 的扇區(qū)數(shù)
uchar BPB_bNumFATs; //ofs:16.FAT 的個(gè)數(shù)
uint BPB_wRootEntry; //ofs:17.根目錄項(xiàng)數(shù)
……
uint EndingFlag; //ofs:510.結(jié)束標(biāo)志:0xAA55
} BPB_BLOCK, * PBPB_BLOCK;
FAT表用于存放文件分區(qū)信息,通常位于主引導(dǎo)區(qū)和保留扇區(qū)之后。存放在塊設(shè)備中的文件并不是占用連續(xù)的空間,而是根據(jù)一定的算法來(lái)決定某一部分文件內(nèi)容存放到哪個(gè)簇中,然后將這些簇連接起來(lái)構(gòu)成一個(gè)完整的文件。文件分配表是一一對(duì)應(yīng)于數(shù)據(jù)區(qū)簇號(hào)的列表,反映了所有簇的使用情況。每個(gè)表項(xiàng)單元的大小決定了FAT的類型,如FAT16的表項(xiàng)單元為16位。為了數(shù)據(jù)安全,F(xiàn)AT表一般都有一個(gè)備份。
文件目錄表(file directory table,F(xiàn)DT)位于 FAT表之后。FDT由32位的目錄項(xiàng)線性構(gòu)成,記錄著根目錄下每個(gè)文件(子目錄)的起始單元、屬性等。FDT大小為32個(gè)扇區(qū),最多可以保存512個(gè)目錄項(xiàng)。其數(shù)據(jù)結(jié)構(gòu)定義如下:
typedef struct _DIR_INFO
{
unsigned char name[8]; //文件名
unsigned char extension[3];//文件擴(kuò)展名
unsigned char attribute; //文件屬性
unsigned char Reserved[10];//保留區(qū)域
unsigned int lastUpdateDate; //文件更新日期
unsigned int lastUpdateTime; //文件更新時(shí)間
unsigned int startCluster; //文件開(kāi)始簇號(hào)
unsigned long length;//文件長(zhǎng)度
} DIR_INFO, * PDIR_INFO;
3.2文件系統(tǒng)實(shí)現(xiàn)流程
圖2為在塊設(shè)備中實(shí)現(xiàn)文件系統(tǒng)操作的流程。
a)首先在目錄區(qū)中搜索與文件名“PDSA”匹配的文件目錄項(xiàng),對(duì)應(yīng)地找到該文件開(kāi)始的首簇的簇號(hào)000a;如果沒(méi)有相匹配的目錄,則需要新建一個(gè)名為“PDSA”的文件,調(diào)用函數(shù)Getfreeclusternum()來(lái)搜索FAT表得到空閑簇,并且寫入到目錄項(xiàng)中。假設(shè)得到的空閑簇為000a。
b)根據(jù)首簇號(hào)OO0a訪問(wèn)FAT表,讀出首簇號(hào)對(duì)應(yīng)的FAT表項(xiàng)內(nèi)容000b,這就是第二個(gè)簇號(hào)。根據(jù)第二個(gè)簇號(hào)再訪問(wèn)FAT表,讀出其對(duì)應(yīng)的FAT表內(nèi)容,就是第三個(gè)簇號(hào)000c。依此下去,直到最后一個(gè)表項(xiàng)內(nèi)容為FFF8H~FFFFH為止(表示最后一簇)。如果是新建文件,則需要根據(jù)其文件長(zhǎng)度來(lái)判斷需要寫入的簇?cái)?shù)。假設(shè)需要寫入的文件長(zhǎng)度為三個(gè)簇,此時(shí),調(diào)用函數(shù)Getnextcluster()來(lái)搜索FAT表,依次得到相應(yīng)的簇號(hào),并將下一簇的簇號(hào)寫入到上一簇所在的FAT表項(xiàng)中,最后一簇的FAT表項(xiàng)中寫入FFFF,表示文件結(jié)束。
c)根據(jù)b)可知“PDSA”這個(gè)文件占用了三個(gè)簇,這三個(gè)簇號(hào)形成一個(gè)簇鏈,000a-000b-000c。根據(jù)這些簇號(hào)所形成的簇鏈訪問(wèn)這三個(gè)簇號(hào)對(duì)應(yīng)的三個(gè)數(shù)據(jù)存儲(chǔ)區(qū)域,文件“PDSA”就分成三個(gè)部分分別存放在這三個(gè)存儲(chǔ)區(qū)域中。
4用戶接口模塊
按照上述文件系統(tǒng)組織格式,系統(tǒng)通過(guò)目錄項(xiàng)和FAT表來(lái)實(shí)現(xiàn)對(duì)整個(gè)塊設(shè)備上的數(shù)據(jù)按照文件形式進(jìn)行建立和管理。
最終實(shí)現(xiàn)了如下面向用戶的文件級(jí)的操作。
FS_FileInital():系統(tǒng)初始化時(shí)調(diào)用該函數(shù),調(diào)入文件系統(tǒng)的相關(guān)數(shù)據(jù)結(jié)構(gòu);
FS_FileFormat():系統(tǒng)初始化時(shí)調(diào)用該函數(shù),初始化設(shè)備,讀取設(shè)備信息到相關(guān)數(shù)據(jù)結(jié)構(gòu);
FS_FileCreate (INT8U filename):建立新文件;
FS_FileOpen (INT8U filename, INT8U Openflag):以讀或者寫的方式打開(kāi)文件;
FS_FileClose():關(guān)閉已打開(kāi)的文件,釋放相關(guān)緩沖區(qū),保證文件操作的安全;
FS_FileRead(filename, INT8U buf,INT32U datalength):讀取文件到相應(yīng)的緩沖區(qū),第三個(gè)參數(shù)是數(shù)據(jù)長(zhǎng)度;
FS_FileWrite(filename, INT8U buf,INT32U datalength):將緩沖區(qū)中的內(nèi)容寫入到文件中,每次寫入的數(shù)據(jù)長(zhǎng)度由第三個(gè)參數(shù)確定;
FS_FileDelete(filename):刪除文件。
5結(jié)束語(yǔ)
本文介紹的面向閃存類設(shè)備的文件系統(tǒng)在筆者開(kāi)發(fā)的基于8位單片機(jī)C8051F124的便攜式數(shù)據(jù)采集中已經(jīng)得到了采用,可以實(shí)現(xiàn)與外部存儲(chǔ)類閃存設(shè)備的文件級(jí)數(shù)據(jù)交換。其穩(wěn)定性和實(shí)用性已經(jīng)得到了驗(yàn)證,并且對(duì)別的儀器開(kāi)發(fā)也有一定借鑒意義。
參考文獻(xiàn):
[1]李慶誠(chéng),孫明達(dá).基于NAND型閃存的嵌入式文件系統(tǒng)設(shè)計(jì)[J].計(jì)算機(jī)應(yīng)用與研究,2006,23(4):231-233,239.
[2]陳智育.嵌入式系統(tǒng)中的flash文件系統(tǒng)[J].單片機(jī)與嵌入式系統(tǒng)應(yīng)用,2002(2):5-8.
[3]Cygnal Integrated Products,Inc.C8051F單片機(jī)應(yīng)用解析[M].潘琢金,孫德龍,夏秀峰,譯.北京:北京航空航天大學(xué)出版社,2002.
[4]宋群生,宋亞瓊.硬盤扇區(qū)讀寫技術(shù)——修復(fù)硬盤與恢復(fù)文件[M].北京:機(jī)械工業(yè)出版社,2004.
[5]鄭宗漢.實(shí)時(shí)系統(tǒng)軟件基礎(chǔ)[M].北京:清華大學(xué)出版社,2002.
“本文中所涉及到的圖表、注解、公式等內(nèi)容請(qǐng)以PDF格式閱讀原文”