何 諧
(江陰職業(yè)技術(shù)學(xué)院,江陰214400)
何諧(講師),研究方向為單片機(jī)與嵌入式應(yīng)用。
FAT類文件系統(tǒng)是Windows操作系統(tǒng)在磁盤文件管理上最常用的一種文件系統(tǒng)。而FAT32文件系統(tǒng)是微軟FAT類文件系統(tǒng)中的最高版本,微軟從Windows95版本開始,后續(xù)的操作系統(tǒng)均支持FAT32文件系統(tǒng),是現(xiàn)今Windows下最常用的硬盤文件系統(tǒng)。當(dāng)人們使用SD卡等存儲裝置從計算機(jī)上拷取文件時,存儲器中的文件管理即符合FAT32文件系統(tǒng)的管理原則,因此,使用嵌入式芯片設(shè)計音樂播放器時,為了能自動識別SD卡上的音樂文件,關(guān)鍵是FAT32文件系統(tǒng)在嵌入式芯片上的實現(xiàn),本文研究了FAT32文件系統(tǒng)在Cortex-M3內(nèi)核的音樂播放器上的應(yīng)用,并設(shè)計了基于FAT32的音樂播放器。
Cortex-M3內(nèi)核是ARM公司推出的基于ARMv7體系架構(gòu)的處理器核,具有高性能、低成本、低功耗的特點,而意法半導(dǎo)體公司的STM32系列芯片STM32F103RB則是在Cortex-M3內(nèi)核的基礎(chǔ)上擴(kuò)展了高性能的外圍設(shè)備。該芯片工作頻率為72MHz,內(nèi)置高速存儲器(128KB的閃存和20KB的SRAM)。由于其豐富的外設(shè)和優(yōu)異的性價比,音樂播放器選擇其作為主控制器芯片,利用其自帶的2組SPI接口讀取SD卡音頻文件以及緩存,并將讀取的音頻數(shù)據(jù)流送至音頻解碼器VS1003進(jìn)行解碼;同時主控制器還負(fù)責(zé)人機(jī)交互,連接TFT屏幕顯示歌曲名稱以及鍵盤用以選擇曲目。
本音樂播放器選擇SD卡作為存儲裝置。SD卡使用前應(yīng)通過讀卡器連接至計算機(jī),格式化為FAT32文件格式,同時將*.mp3、*.wav、*.wma格式的音樂文件復(fù)制到SD卡中。一般來說,SD卡支持兩種工作模式:SD模式和SPI模式。由于STM32F103RB本身具有2個SPI接口,因此SD卡以SPI模式連接STM32F103RB的SPI1口。
VS1003是荷蘭VLSI公司出品的一款單芯片MP3/WMA/MIDI/WAV音頻解碼和ADPCM編碼芯片,通過SPI控制。該系統(tǒng)中,VS1003作為主控芯片的從機(jī)使用,STM32F103RB通過它的SPI2口向VS1003不斷輸出音頻數(shù)據(jù)流,VS1003自動解碼,并連接外部功放和喇叭,就可以聽到所播放的音樂了。
STM32F103RB與SD卡和VS1003的連接圖如圖1所示。
圖1 STM32F103RB與SD卡和VS1003的連接圖
FAT類文件系統(tǒng)對文件的存儲空間是按簇進(jìn)行劃分和管理的,即一個文件總是占用若干個整簇,即文件最后一簇剩余的空間將不再使用。不同的簇采用簇號來區(qū)分,F(xiàn)AT32文件系統(tǒng)使用32位二進(jìn)制來表示簇號,適用于空間大于512MB的磁盤。每簇對應(yīng)的扇區(qū)數(shù)將決定磁盤的容量,扇區(qū)是僅小于簇的存儲單位,一般每扇區(qū)大小為512字節(jié)。為了提高對整個磁盤空間的利用率,“簇”不宜大,也不宜小。對于小容量的磁盤,F(xiàn)AT32系統(tǒng)實際每個簇為4KB,也就是8個扇區(qū);當(dāng)磁盤容量超過8GB時,每個簇為8KB,32GB以上每簇為32KB。
當(dāng)SD卡被格式化為FAT32文件格式時,SD卡中的邏輯盤空間就被劃分為三大部分:保留區(qū)、FAT表區(qū)(文件分配表區(qū))、DATA區(qū)。其中保留區(qū)和FAT表區(qū)又合稱為系統(tǒng)區(qū),文件的真正存儲從DATA區(qū)開始。
保留區(qū)包含了FAT32的重要數(shù)據(jù)結(jié)構(gòu)——MBR(主引導(dǎo)記錄)和DBR(系統(tǒng)引導(dǎo)扇區(qū))。MBR如果存在,則絕對0扇區(qū)就是MBR;如不存在,此扇區(qū)就是DBR。MBR的前面446字節(jié)為引導(dǎo)程序,隨后的64字節(jié)是4條記錄,稱為DPT(磁盤分區(qū)表),每條記錄均包含了分區(qū)的開始磁頭、開始柱面與分區(qū)類型、分區(qū)的結(jié)束頭、結(jié)束柱面與扇區(qū)、分區(qū)的第一個扇區(qū)、總扇區(qū)數(shù)等信息。由于SD卡容量不是很大,通常不作分區(qū),后面三條分區(qū)記錄均為0。
通過DPT可以找到DBR扇區(qū),在DBR中記錄了分區(qū)的很多重要的信息,這些重要信息都保存在BPB(BIOS參數(shù)塊)這個區(qū)域。這些重要信息包含了FAT32的大部分全局參數(shù),例如:每扇區(qū)的字節(jié)數(shù)、每簇扇區(qū)數(shù)、保留扇區(qū)數(shù)、FAT表數(shù)、FAT區(qū)前隱扇區(qū)數(shù)、FAT表所占扇區(qū)數(shù)、第一個目錄的簇號等。
DBR扇區(qū)之后是保留扇區(qū),再接著便是FAT表區(qū)了,F(xiàn)AT32中有兩個FAT表,第二個是第一個的備份,通過對BPB的解析可知FAT表的開始扇區(qū)和大小。FAT表是一個鏈?zhǔn)浇Y(jié)構(gòu),每4個字節(jié)(一個32位二進(jìn)制)為一個FAT表項,每個FAT表項對應(yīng)一個簇,00簇和01簇被系統(tǒng)保留,因此前2個FAT表項為特殊字符。從02簇開始,每個簇都依次對應(yīng)一個FAT表項內(nèi)容。如果該簇未使用或已回收,相應(yīng)FAT表項內(nèi)容寫零,壞簇以0FFFFFF7H標(biāo)識;如果該簇是文件的最后一簇,F(xiàn)AT表項值為0FFFFFFFH;如果該簇不是文件的最后一簇,F(xiàn)AT表項值為該文件占用的下一個簇的簇號,文件占用的各簇構(gòu)成一個簇鏈,保存在FAT表中。因此,只要知道文件的起始簇號,就可以根據(jù)該鏈?zhǔn)浇Y(jié)構(gòu)找到整個文件。當(dāng)新建文件時,如果新建的文件只占用一個簇,為其分配的簇對應(yīng)的FAT表項將會寫入結(jié)束標(biāo)記,如不只占用一個簇,則在FAT表項中記錄下一簇簇號直至結(jié)束;當(dāng)刪除文件時,文件所對應(yīng)的FAT表項將被設(shè)置為0,以表示其對應(yīng)的簇處于未分配狀態(tài)。
DATA區(qū)從02簇開始,該區(qū)根據(jù)存放的內(nèi)容,可分為根目錄區(qū)和文件數(shù)據(jù)區(qū)。根目錄區(qū)存放根目錄文件,通過BPB解析可知02簇的開始扇區(qū),該扇區(qū)也稱根目錄簇開始扇區(qū)。從這個扇區(qū)開始依次存放文件目錄項,每個文件目錄項占用32字節(jié),根目錄文件的大小隨文件目錄項個數(shù)增加而增加。除了第一個32字節(jié)為文件卷標(biāo),其后的每個文件目錄項均描述了和文件相關(guān)的大部分信息,如文件名、文件創(chuàng)建時間、訪問時間、文件大小、文件起始簇號等等。解析出這些文件信息,特別是文件起始簇號,嵌入式芯片就可以根據(jù)FAT表訪問任意文件內(nèi)容了。根目錄項中的內(nèi)容也可以是子目錄文件的信息用同樣方法也可以找出子目錄下的所有文件的信息。
FAT32在Cortex-M3內(nèi)核的嵌入式芯片上的實現(xiàn)依賴于一些必要的結(jié)構(gòu)體,這些結(jié)構(gòu)體包括了FAT32文件系統(tǒng)的重要區(qū)域信息,通過對這些結(jié)構(gòu)體的解析,可以方便計算出目標(biāo)文件的重要信息。因此,F(xiàn)AT32文件系統(tǒng)首先定義這些結(jié)構(gòu)體,包括MBR結(jié)構(gòu)體struct PartSector、DPT結(jié)構(gòu)體struct PartRecord、BPB結(jié)構(gòu)體struct FAT32_BPB、文件目錄項結(jié)構(gòu)體struct direntry和文件信息結(jié)構(gòu)體struct FileInfo。
FAT32文件系統(tǒng)本身就是用來管理和控制對扇區(qū)數(shù)據(jù)的讀和寫,因此,需要構(gòu)建一個FAT32_ReadSector()函數(shù),用來讀取存儲設(shè)備的扇區(qū),與FAT32_WriteSector()一起構(gòu)成其他FAT32函數(shù)的底層函數(shù)。由于系統(tǒng)的存儲設(shè)備是SD卡,SD卡函數(shù)SD_ReadDisk()可從指定物理扇區(qū)號讀取1個扇區(qū)的數(shù)據(jù),放入全局變量數(shù)據(jù)緩沖區(qū)FAT32_Buffer[512]中,因此,使用SD_ReadDisk()來作為這個底層函數(shù)。
初始化FAT32文件系統(tǒng)包括以下幾個函數(shù)。
尋找 DBR函數(shù) FAT32_Find_DBR():此函數(shù)用FAT32_ReadSector()讀入SD卡0扇區(qū)數(shù)據(jù),強(qiáng)制類型轉(zhuǎn)換為MBR結(jié)構(gòu)體struct PartSector,解析出其中的DPT結(jié)構(gòu)體struct PartRecord,返回DBR所在扇區(qū)號。
FAT32_Init()函數(shù):將DBR扇區(qū)數(shù)據(jù)讀入緩沖區(qū),強(qiáng)制類型轉(zhuǎn)化為BPB結(jié)構(gòu)體,解析struct FAT32_BPB,計算出FAT32的重要信息:每扇區(qū)字節(jié)數(shù)、每簇扇區(qū)數(shù)、第一個FAT表扇區(qū)號、FAT表占用的扇區(qū)數(shù)、根目錄簇號、根目錄簇開始扇區(qū)、根目錄占用扇區(qū)、第一個數(shù)據(jù)扇區(qū),作為全局變量參數(shù)。
ClustToSector()函數(shù):輸入?yún)?shù)是任意簇號,返回該簇所對應(yīng)的起始扇區(qū)號。
GetNextCluster()函數(shù):根據(jù)文件當(dāng)前簇號,在FAT表中找到文件下一簇號返回,如沒有后繼簇,則返回0x0ffffff8,表示文件結(jié)束。
Get_File_Info():該函數(shù)輸入?yún)?shù)為根目錄簇號dir_clust、全局參數(shù)文件信息結(jié)構(gòu)體struct FileInfo、音樂文件類型、音樂文件序號count。該函數(shù)首先根據(jù)根目錄簇號找到該簇起始扇區(qū)號,連續(xù)讀取扇區(qū),直到FAT表中簇鏈結(jié)束。對讀取的每個扇區(qū)數(shù)據(jù)以32字節(jié)為單位強(qiáng)制轉(zhuǎn)換為文件目錄項結(jié)構(gòu)體struct direntry,對每個合法的文件目錄項結(jié)構(gòu)體struct direntry進(jìn)行解析。若音樂文件類型符合輸入?yún)?shù),文件索引號自增1;若該文件索引號即為音樂文件序號時,表示找到目標(biāo)音樂文件。將該目標(biāo)文件的struct direntry的32字節(jié)內(nèi)容轉(zhuǎn)化到全局變量文件信息結(jié)構(gòu)體struct FileInfo,提取文件信息詳情。struct FileInfo結(jié)構(gòu)體如下:
音樂播放器可循環(huán)播放SD卡上的音樂格式文件,只要文件格式為*.mp3、*.wav、*.wma,就可順序播放,TFT屏幕顯示正在播放的音樂文件名稱,通過對按鍵的操作可實現(xiàn)歌曲的暫停/播放、選擇上一首和下一首。該音樂播放器軟件系統(tǒng)設(shè)計除FAT32文件系統(tǒng)FAT32.c之外,還包括以下幾大模塊:歌曲播放模塊music_play.c為軟件的最高層應(yīng)用層;SD卡模塊sd.c、VS1003模塊vs1003.c為music_play.c提供設(shè)備驅(qū)動;而SPI模塊spi.c為最底層的物理數(shù)據(jù)交換程序,為sd.c和vs1003.c提供支持。軟件系統(tǒng)結(jié)構(gòu)如圖2所示。
圖2 軟件系統(tǒng)結(jié)構(gòu)
應(yīng)用層程序music_play.c在初始化之后首先計算出根目錄下音樂格式歌曲的數(shù)目,隨后判斷按鍵狀態(tài),當(dāng)選擇前一首、后一首或一首歌播放完畢時,改變播放歌曲的索引號,播放該索引號的歌曲。
播放某歌曲時,首先利用FAT32函數(shù)Get_File_Info(),根據(jù)歌曲索引號和文件類型來構(gòu)造該文件的文件信息結(jié)構(gòu)體struct FileInfo,并獲取這首歌的文件起始簇號、歌曲名稱等信息。根據(jù)文件開始簇號,調(diào)用FAT32函數(shù)FAT32_ReadSector()讀取1扇區(qū)數(shù)據(jù),存入STM32F103RB的512字節(jié)的數(shù)據(jù)緩沖區(qū),緩沖區(qū)數(shù)據(jù)隨后通過SPI函數(shù)SPI2_ReadWriteByte()發(fā)送給 VS1003播放。當(dāng)該簇所有扇區(qū)播放完畢后,一簇結(jié)束,利用FAT32函數(shù)GetNextCluster()在FAT表中繼續(xù)尋找下一簇簇號,循環(huán)上述過程,直到簇鏈結(jié)束,歌曲也播放完畢。
歌曲播放主流程如圖3所示。
系統(tǒng)讀取SD卡時使用STM32F103RB的SPI1口,設(shè)置為高速模式;發(fā)送數(shù)據(jù)到VS1003時使用SPI2口,設(shè)置為低速模式。這樣在歌曲的播放過程中,數(shù)據(jù)的讀取速度永遠(yuǎn)超過數(shù)據(jù)的發(fā)送速度,可以得到比較好的音質(zhì),不會出現(xiàn)聲音的抖動。
本文結(jié)合FAT32文件系統(tǒng)提出嵌入式系統(tǒng)的音樂播放器設(shè)計方案,研究了FAT32文件系統(tǒng)在Cortex-M3內(nèi)核的音樂播放器中的實現(xiàn)方法,對便攜式多媒體播放器的研發(fā)具有一定的指導(dǎo)意義。
圖3 歌曲播放流程圖
[1]何立民.單片機(jī)高級教程[M].北京:北京航空航天大學(xué)出版社,2007.
[2]戴士劍,涂彥輝.數(shù)據(jù)恢復(fù)技術(shù)[M].2版.北京:電子工業(yè)出版社,2007.
[3]劉偉.數(shù)據(jù)恢復(fù)技術(shù)深度揭秘[M].北京:電子工業(yè)出版社,2010.
[4]唐繼賢.51單片機(jī)應(yīng)用系統(tǒng)開發(fā)實例精解[M].上海:科學(xué)技術(shù)出版社,2012.
[5]劉軍.例說STM32[M].北京:北京航空航天大學(xué)出版社,2011.