Zynq Fatfs文件系統應用筆
Hello,panda
筆記介紹基於所描寫敘述的Zynq Fatfs基於Xilinx xilffsv3.0和Sdpsv2.4,文件系統採用在Bare-Metal和輕量級操作系統中經常使用的FatFs,版本號為v0.10b。
在開始介紹FatFs文件系統在Zynq實現之前一定要先對FAT32文件系統有一個清晰的了解。
1 FAT32文件系統
應用筆記針對SD上的FAT32文件系統,在對文件系統作具體介紹之前,先回想一下硬盤的結構,如圖1:
圖1 硬盤結構
對一個機械硬盤而言。柱面、磁頭、扇區確定唯一的扇區物理地址。在數據組織上來看,總是依照主引導區→引導扇區→數據→引導扇區…來排列,一塊硬盤上,基本分區的最大數目為4個。大於4個的被自己主動分配為擴展分區。
SD卡的分區結構和普通磁盤類似,沿用了普通機械硬盤的大多數概念術語。
由於它無需啟動,所以MBR區沒有引導信息,圖2是SD卡文件系統的典型結構。
圖2 SD卡文件系統結構
1.1 主引導記錄(MBR)
在一個硬盤中主引導分區位於硬盤的起始扇區,一共512個字節,包括了446字節的MBR和64字節的DPT,並以55 AA作為結束標志。
由於SD卡不用啟動,因此MBR區域不包括引導數據,SD卡的MBR如圖2所看到的,數據均為小端模式,低字節在前。
圖2 SD卡MBR區域
圖2所看到的為SD卡物理地址為0開始的512字節區域,紅藍線標注的數據包括了兩個重要信息:
① 紅線數據:表示下一個分區的扇區地址,這里是0x2000。即下一個分區從第8192個扇區開始。也就是DBR在第8192個物理分區(0邏輯分區)。
② 藍線數據:表示總扇區數為0x01DAAC00,那么能夠計算得到當前SD卡的總容量為:
ρ=0x01DAAC00*512= 14.83GB
1.2 引導扇區DBR
引導扇區DBR共512個字節。以55 AA結束,前11個字節為跳轉指令和文件系統類型、版本信息。結構如圖3所看到的。
圖3 DBR內容
DBR為邏輯分區起始位置,須要關注下面重要信息:
① 偏移地址0x0D標記每簇的扇區數,圖3顯示為64,即每簇為32KB,文件系統中保存數據的最小單位為簇,僅僅要本簇中寫入了當前文件的數據。它就不能夠被其它文件使用。
② 偏移地址0xE~0xF標記了本分區的保留扇區數,圖3中為598個,也就是說下一個分區(FAT表)的起始扇區為邏輯扇區598。
③ 偏移地址0x10~0x11標記了FAT表的個數,圖3顯示為2個。
④ 偏移地址0x24~0x27標記了FAT表的大小。圖3顯示為3797個。
1.3 信息分區FSINFO
信息分區FSINFO的結構很easy,用以記錄文件系統中空暇簇的數量以及下一可用簇的簇號等信息,以供操作系統作為參考,常位於1號邏輯扇區。
如圖4所看到的。
圖4 FSINFO內容
圖4中紅色方框的為FSINFO簽名。固定為0x61417272;藍色方框中內容為文件系統的空簇數,依據使用情況動態變化;黑色方框為下一個空簇的位置,依據使用情況動態變化。
通常情況下,2號扇區也以55 AA結束,6號扇區是DBR的備份,7號扇區是FSINFO的備份。8號扇區是2號扇區的備份。
1.4 FAT表
從FAT表開始便是文件系統的核心內容。文件占用磁盤的最小單位是簇。即使文件僅僅有一個字節。那么它也占用一個簇的磁盤空間,大文件會占用多個簇。同一個文件的數據並非連續的存放在一段磁盤空間內,而是分成若干段,像鏈子一樣存放。稱之為文件的鏈式存儲。為了實現文
件的鏈式存儲。文件系統必須准確地記錄哪些簇已經被文件占用,還必須為每一個已經占用的簇指明存儲后繼的下一個簇的簇號,對於文件的最后一簇。則要指明本簇無后繼簇。這些都是由 FAT 表來保存的,FAT 表相應表項中記錄着它所代表的簇的有關信息:諸如是空,是不是壞簇,是否是已經是某個文件的尾簇等。
對於FAT表而言。它的重要使命是:描寫敘述簇的分配狀態以及標明文件或文件夾的下一簇的簇號。
1.4.1 FAT表分析
FAT表中每簇的地址固定為32bit。按四字節對其進行划分。並由0開始進行編號。
0號和1號簇由系統保留作特殊使用,從2號簇開始相應文件系統的實際數據區的簇號,FAT表中的簇地址編號與數據區的簇號同樣。
在創建文件系統(格式化)時。全部的FAT表均被清空,FAT1和FAT2的0、1號表項寫入特定值,2號表項常為根文件夾,因此2號表被寫入結束標志。
① FAT32文件系統FAT表的0號表項固定為0x0FFFFFF8;
② 1號表項正常情況為0xFFFFFFFF或0x0FFFFFFF。也可能被用於記錄臟標志,以說明文件系統沒有被正常卸載或者磁盤表面存在錯誤。
③ 若簇未被分配使用,則其FAT表項為0;
④ 若該簇被使用,那么FAT表項值就是該文件下一個存儲位置的簇號,如是文件結束簇,則寫結束標志“0x0FFFFFFF”;
⑤ 若該簇存在壞扇區。則用“0xF7FFFFF”標記該簇為壞簇;
⑥ 新建文件夾時。僅僅為其分配一個簇的空間,相應的FAT表現寫入結束標志,當文件夾超過一個簇時則在空暇區再為其追加一個簇並又一次建立FAT表鏈。
1.4.2 FAT表實例
圖5是一個SD的FAT32文件系統FAT表,每四個字節一組表示一個簇的信息。簇號從0開始。
① 0x0FFFFFF8: FAT表起始標志;
② 0xFFFFFFFF:不用,默認值;
③ 0x0FFFFFFF:根文件夾所在簇;
④ 從FAT表項第3項開始記錄存儲文件的信息。FAT表第三項記錄了存儲文件的下一個簇號為4,…直到第七項結束。
圖5 FAT32文件系統FAT表實例
根文件夾所在的簇為3號簇,這個偏移地址能夠通過計算得出。
① 邏輯地址:保留區大小+FAT表大小*2。那么本文中描寫敘述的文件系統根文件夾的位置為 598+3797*2 =8192。
即根文件夾從邏輯扇區第8192扇區開始。
② 物理地址:隱藏區域+邏輯地址。本例中隱藏區域在MBR表中能夠看到是8192。那么根文件夾的物理地址就是從第16384個扇區開始。
本例中每32KB為一個簇,2號簇即存儲根文件夾的實際數據區域。
1.5 根文件夾
根文件夾在文件系統建立時即已被創建。其目的就是存儲文件夾(也稱文件夾)或文件的文件夾項。每一個文件夾項的大小為32個字節。這32個字節能夠是長文件名稱文件夾項、文件文件夾項、子文件夾項等。圖6是本例中根文件夾的內容。
圖6 根文件夾內容
首先重點提醒圖6中顯示‘X’號的文件是已經刪除但沒有格式化的文件數據,仍然能夠恢復讀出,所以“關鍵數據”刪除后一定要記得深度格式化。
1.5.1 短文件名稱文件夾項
文件夾所在的扇區,都是以 32 Bytes 划分為一個單位,每一個單位稱為一個文件夾項(DirectoryEntry ),即每一個文件夾項的長度都是 32 Bytes 。根文件夾由若干個文件夾項組成,一個文件夾項占用 32 個字節,能夠是長文件名稱文件夾項、文件文件夾項、子文件夾項等。
32 字節的詳細定義例如以下表1所看到的。
表1 FAT32短文件名稱文件夾項定義
字節偏移(16進制) |
字節數 |
定義 |
|
0x0~0x7 |
8 |
文件名稱 |
|
0x8~0xA |
3 |
擴展名 |
|
0xB* (不可取值0F,0F表示長文件名稱文件夾段) |
1 |
屬性字節 |
00000000讀寫 |
00000001僅僅讀 |
|||
00000010 隱藏 |
|||
00000100 系統 |
|||
00001000 卷標 |
|||
00010000 子文件夾 |
|||
00100000 歸檔 |
|||
0xC |
1 |
系統保留 |
|
0xD |
1 |
創建時間的10ms位 |
|
0xE~0xF |
2 |
文件創建時間 |
|
0x10~0x11 0x12~0x13 0x14~0x15 0x16~0x17 0x18~0x19 0x1A~0x1B 0x1C~0x1F |
2 2 2 2 2 2 4 |
文件創建日期 文件最后訪問日期 文件起始簇號的高16位 文件近期改動時間 文件近期改動日期 文件起始簇號的低16位 文件的長度(字節),單文件最大4GB |
以下分析圖6中第一個32字節的內容,分析結果寫入表2。
表2 根文件夾第一個32字節內容
字節偏移(16進制) |
字節內容 |
含義 |
0x0~0x7 |
47,49,52,47,52,41,57,20 |
文件名稱”girlraw”的ASIC碼 |
0x8~0xA |
52,41,57 |
擴展名raw |
0xB |
20 |
歸檔 |
0xC |
1 |
系統保留 |
0xD |
AE |
|
0xE~0xF |
8C56 |
Bit[15:11]:小時,17時 Bit[10:5]:分18分 Bit[4:0]:秒,2秒為單位,44秒 |
0x10~0x11 |
4703 |
Bit[15:9]:年,1980相對值,2015 Bit[8:5]:月。8月 Bit[4:0]:日。3日 |
0x12~0x13 |
470A |
|
0x14~0x15 |
0000 |
文件起始簇號的高16位 |
0x16~0x17 |
729D |
|
0x18~0x19 |
46F7 |
|
0x1A~0x1B |
0003 |
文件起始簇號的低16位,文件存儲第一個簇的位置是3號簇 |
0x1C~0x1F |
00028000 |
163840個字節 |
1.5.2 長文件名稱文件夾項
FAT32 文件系統在為文件分配短文件名稱文件夾項的同一時候會為其分配長文件名稱文件夾項。文件系統在為文件創建長文件名稱(Long File Name,LFN)類型的文件夾項時,並沒有舍棄原有的短文件名稱文件夾項。具有LFN的文件同一時候也有一個常規的SFN(Short File Name,短文件名稱)類型文件夾項。
之所以仍然須要SFN。是由於LFN文件夾項僅僅包括文件的名字,而不包括不論什么有關時間、大小及起始簇號等信息,這些信息仍然須要用SFN文件夾項來記錄。
假設一個文件的文件名稱超過了 8 個字符,則會為其名字截短后為其建立短文件名稱。將短文件名稱存儲在短文件名稱文件夾項中,長文件名稱則存放在長文件名稱文件夾項中。
長文件名稱文件夾項具有下面特點:
① LFN 和 SFN 文件夾項結構在同樣位置有一個屬性標志字節,LFN 文件夾項使用一個特定的屬性值,以說明它是一個長文件名稱項。
② 項中的其它字節。使用UTF-16 編碼,存儲 13 個 Unicode字符的文件名稱,每一個字符占用兩個字節;
③ 假設文件名稱長於 13 個字符,則繼續為其分配LFN 項,直到夠用為止;
④ 全部 LFN 都包括一個校驗和,通過這個校驗和將其與對應的SFN 項關聯起來;
⑤ 一個文件的全部 LFN 項按倒序排列在它的 SFN項前面。即文件名稱的第一部分距離 SFN 是近期的。
表3是長文件名稱文件夾項的詳細結構。
表3 長文件文件夾項定義
偏移字節 |
字節數 |
含義 |
0x00 |
1 |
如文件夾項使用中則為序列號。未分配則為0x00。以前使用但已經被刪除則為0xE5。一個文件的第一個長文件名稱文件夾項的序號為0x01,然后依次遞增,若是最后一項則將該文件夾項序號與0x40進行OR運算后寫入。 |
0x01~0x0A |
10 |
文件名稱的1~5字符(Unicode),未使用部分先填充兩個0x00,然后用0xFF填充 |
0xB |
1 |
長文件名稱文件夾項屬性標志0x0F |
0xC |
1 |
保留未使用 |
0xD |
1 |
校驗和,如一個長文件名稱須要幾個長文件名稱文件夾項進行存儲,則他們具有同樣的校驗和 |
0x0E~0x19 |
12 |
文件名稱的6~11個字符,未使用部分先填充兩個0x00,然后用0xFF填充 |
0x1A~0x1B |
1 |
保留未使用 |
0x1C~0x1F |
4 |
文件名稱的12~13個字符,未使用部分先填充兩個0x00,然后用0xFF填充 |
圖7是根文件夾下長文件名稱文件夾項的截圖。
圖7 長文件名稱文件夾項
如圖7所看到的,紅色方框部分文件名稱占用三個文件夾項,最以下的是短文件名稱文件夾項,指定了文件的全部屬性;緊挨短文件名稱文件夾項倒着向上數是第一第二條長文件名稱文件夾項。
① 第一條長文件名稱文件夾項的序列號直接為0x01,這和短文件名稱文件夾項第七個字節的跳轉指示序號同樣;第二條長文件名稱文件夾項未終止項,值為0x02 or 0x40 = 0x42。
② 第一和第二條長文件名稱文件夾項具有同樣校驗和0x69。
1.5.3 子文件夾
在FAT32文件系統中。除根文件夾在創建文件系統時即被建立並分配空間外,其它全部的子文件夾都是在使用過程中按需建立。新建一個子文件夾時,在其父文件夾中建立文件夾項。在空暇空間中為其分配一個簇並對該簇進行清零操作。同一時候將這個簇號記錄在它的文件夾項中。假設在根文件夾下創建一個子文件夾,那么這個子文件夾就是根文件夾的子文件夾,稱根文件夾為這個子文件夾的父文件夾。
創建子文件夾時,在其父文件夾所在簇為子文件夾建立文件夾項,記錄了子文件夾的起始簇號。同一時候,在為子文件夾分配文件夾項的簇中。用前兩個文件夾項描寫敘述它與父文件夾的關系。
圖8 子文件夾項前兩個文件夾的內容
從圖8子文件夾項的前兩個文件夾能夠看到,文件系統創建了.和..兩個文件夾。當中.文件夾項描寫敘述了該子文件夾自身的信息;..文件夾項描寫敘述了其父文件夾的信息(創建該文件夾所在文件夾的第一個簇號,根文件夾為0x00),建立了子文件夾和父文件夾之間的聯系。
從第三條文件夾項開始為下級子文件夾或文件建立的文件夾項。
① “.”文件夾項,該文件夾指向自身,圖8中它的簇號為0x03,就是當前所在簇。
② “..”文件夾項指向它的父文件夾所在簇,圖8中它的父文件夾簇號為0x00,那么指示創建該文件夾的文件夾為根文件夾。
1.6 FAT32文件操作
本節簡要介紹建立、讀取和刪除文件的步驟。
1.6.1 建立文件
目標:在根文件夾下建立一個叫QspiFlash的子文件夾。並向子文件夾中寫入名為“Zynq Qspi 控制器應用筆記.docx”的文件。
簇大小格式化為32KB,待寫入的文件大小為33KB,需占用兩個簇。
第一步:讀取引導扇區DBR,依據引導扇區的信息來定位FAT表、根文件夾和數據區的位置;
第二步:查看根文件夾下的每一個文件夾項。找到名字為“QspiFlash”且具有子文件夾屬性的文件夾項。找到它的起始簇號為0x03;
第三步:讀取3號簇的內容,查找每個文件夾項。直到找到未分配的位置。
第四步:找到后寫入文件名稱“ZynqQspi 控制器應用筆記.docx”及其相關屬性;
第五步:為文件數據分配空間。轉到FAT表。尋找FAT表中未使用的空間。發現4號簇未使用,將4號簇中寫入結束標記;
第六步:將數據寫到4號簇中並將簇號寫到文件文件夾項中。為剩下1KB數據尋找下一個可用簇;
第七步:在FAT表中尋找可用簇。發現5號簇可用,那么將4號FAT表項值該為5並在5號FAT表項值中寫入結束標記;
1.6.2 讀取文件
讀取文件的過程和建立文件的過程相反。
第一步:和建立文件第一步第二步同樣;
第二步:在3號簇中查找每個文件夾項,找到名為“Zynq Qspi 控制器應用筆記.docx”的文件並獲取其相關屬性。
第四步:讀取第一個簇的數據並轉到FAT表。將下一個簇的數據讀出,直到所有讀出。
1.6.3 刪除文件
刪除文件實質就是:
① 將簇所在FAT清零;
② 將文件文件夾項的第一個字節清零;
刪除文件僅刪除FAT表和置文件夾項標記,實際文件數據並未及時刪除,能夠依據文件系統的構成特點所有恢復或部分恢復。
2 SD卡
SD卡系列規范由Panasonic、SanDisk、Toshiba等發起。處理器端的SDHost、SD卡(SD Device)和文件系統都必須遵循下列規范:
《SD Specifications Part1 Physical Layer Specification》
《SD Specifications PartA2 SD Host Controller Standard Specification》
《SD Specifications Part2 File System Specification》
2.1 SD卡物理特性
(1)容量:SD標准協會定義,容量≤2GB的為標准卡。超過2GB的為大容量卡。
(2)電壓:高電壓供2.7~3.6V;雙電壓供電LowVoltage Range 和2.7~3.6V雙電壓;
(3)速度:默認模式0~25MHz時鍾頻率,快速模式0~50MHz時鍾頻率。
2.2 總線訪問
SD卡均能通過4bit/1bitSD模式或模式訪問,這里僅僅對SD模式作簡要說明。
上電SD默覺得1bit SD模式。Host可通過命令動態重配。命令和應答通過CMD線傳輸,數據通過DATA線傳輸。
命令訪問格式如圖9所看到的。
圖9 SD卡命令訪問及應答格式
SD總線數據訪問有兩種格式,各自是常規數據訪問和寬位寬數據訪問。
圖10 常規數據訪問
常規數據訪問如圖10所看到的,總是以MSB的格式輸出,在4bit模式下,CRC每通道單獨校驗。但校驗狀態僅僅通過DATA0輸出,CRC校驗位為16bit。寬位寬數據訪問如圖11所看到的,也是MSB的格式輸出,但它的位寬單位固定是512bit。
圖11 寬位寬數據訪問
SD卡擦除寫入數據的最小單位為Block。一個Block的大小固定為512B。對於標准卡。擦除起始地址和擦除結束地址命令后跟的地址單位都是字節。因此須要文件系統保證512B對齊;對於高容量卡,擦除起始地址和擦除結束地址命令后跟的地址單位都是Block。
2.3 SD卡初始化
SD卡初始化包含SD復位、工作參數握手等工作,初始化流程如圖12所看到的。
圖12 SD卡初始化流程
有關SD物理層更加具體的操作以及具體的命令含義請查找SD協會頒布的標准文檔:《SD Specifications Part 1 Physical Layer Specification》。
2.4 SD讀寫
SD初始化完畢后。對它的讀寫操作實際上訪問其扇區數據。通過發送CMD25實現寫數據、CMD18命令實現讀數據;至於讀寫數據到哪個位置(扇區),數據的內容是什么。SD卡物理層並不關心。都是通過文件系統進行管理。
3 Zynq SD控制器
Zynq SD控制器符合《SDSpecifications Part A2:SD Host Controller Standard Specification》的定義,有SDMA(單操作DMA)、ADMA1(有4K邊界限制)和ADMA2(在32位系統中同意不論什么位置和隨意大小)。
接口兼容eMMC、MMC3.31、SDIO2.0、SD2.0、SPI。支持SDHC、SDHS器件。
以下描寫敘述SD控制器的一些關鍵特點。
3.1 控制器帶寬控制
控制器採用讀和寫通道各自雙緩沖FIFO的機制提高吞吐帶寬。
3.1.1 雙緩沖FIFO
SD控制器讀寫通道採用獨立的512byte深度的雙緩沖FIFO,在寫操作時,處理器向第二個FIFO DMA數據時。可將第一個FIFO的數據寫到SD總線;在讀操作時,SD總線向第一個FIFO寫數據時,處理器可將數據從第二個FIFO的數據讀出。通過雙緩沖機制以保證最大帶寬。
在寫傳輸中,僅僅有當當中一個FIFO中數據准備好且SD總線空暇時HOST才會向SD卡寫數據。因此不會發生FIFOUnderrun的條件。在DMA模式下,僅僅有當FIFO能夠接受一個Block的數據后才釋放DMA讀請求命令;在非DMA模式下,僅僅有buffer write ready中斷產生后才可寫數據到FIFO。
在讀傳輸過程中。當FIFO都寫滿后HOST會停止SD時鍾暫停傳輸,因此不會出現Overrun的情況,在DMA模式下接收到一個Block數據后才釋放DMA寫命令;在非DMA模式。接收到readready interrupt后處理器方將數據寫到內存。
3.1.2 Stream 讀寫
這樣的模式既能夠在DMA模式下使用,也能夠在非DMA模式下使用,寫操作時WRITE_DAT_UNTIL_STOP(CMD20)開始,直到STOP_TRANSMISSION結束;讀操作時READ_DAT_UNTIL_STOP(CMD11)開始。直到STOP_TRANSMISSION結束。
在這樣的模式下由於不知道數據的長度,所以在傳輸數據中建議將Block Size寄存器設置為最大的512Byte,這樣子當讀寫512Byte數據后會切換FIFO。
3.2 編程模型
本節描寫敘述HOST到SD卡傳輸的編程模型。
3.2.1 傳輸數據協議
SD卡傳輸協議包括三種模式:
(1) 單塊傳輸:總塊數HOST已知。但一次僅僅傳輸一個塊;
(2) 多塊傳輸:總塊數HOST已知,一次傳輸一個或多個塊;
(3) 無限制傳輸:總塊數HOST未知。傳輸直到收到中斷傳輸命令運行,傳輸中斷命令在SD Card為CMD12。SDIO為CMD52。
3.2.2 無DMA傳輸
下圖13是無DMA傳輸的流程圖。在無DMA傳輸過程中,處理器須要等待SD控制器中斷或輪詢狀態,數據組織也全然須要通過處理器來完畢。占用CPU資源非常大。下面是對流程圖步驟的分解:
(1)設置BlockSize寄存器,Block_Size_Block_Count.Transfer_Block_Size,對CMD17, CMD18, CMD24, CMD25, CMD53訪問有效,僅在未發生傳輸時能夠改動。
(2)設置BlockCount寄存器,Block_Size_Block_Count.Blocks_Count_for_
Current_Transfer。
僅在多塊傳輸模式下有效。控制器在每傳輸完一塊后自減,僅僅有在空暇時能夠改動。
(3)設置Argument寄存器,該寄存器需寫入SD訪問CMD的bit[39:8];
(4)設置Muti/Single模式。BlockCount使能,Data傳輸方向,AutoCMD12等,配置Transfer_Mode_Command寄存器。
(5)寫Command寄存器。當寫寄存器的最高字節時,SD控制器發出命令。
(6)等待命令完畢中斷。
(7)向中斷狀態寄存器位寫‘1’清除中斷位。
(8)讀命令響應寄存器獲取從SD卡得到的相關信息。
(9)推斷是寫操作還是讀操作;
(11)等待bufferwrite ready中斷,在無DMA寫操作模式下,MCU沖當Master,在收到該中斷后,通過BufferData Port register向FIFO中寫數據,僅僅有當FIFO為空或者能夠接一整幀的數據后釋放該中斷。
圖13 是無DMA傳輸模式流程圖
3.2.3 單DMA傳輸
單DMA傳輸的流程圖如圖14所看到的,在這樣的模式下,數據搬運通過SDMA完畢,無需處理器參與。釋放了CPU資源。
在SDMA模式下,SystemAddress存儲的是傳輸數據的實際地址。
圖14 單DMA模式下操作流程圖
3.2.4 使用ADMA傳輸
使用ADMA傳輸和SDMA傳輸類似。僅僅是ADMA的性能更好。ADMA傳輸的流程圖如圖15所看到的。
使用ADMA傳輸時。ADMASystem Address寄存器里存儲的是地址描寫敘述表(descriptor table)的首地址,當Block Count Enable使能時。通過Block Size和Block Count寄存器確定數據傳輸的大小,但總大小需和descriptor table的描寫敘述同樣,因為Block Count寄存器僅僅有16bit,表示的范圍有限。
當Block Count Enable關閉時。數據傳輸的大小僅僅由descriptor table決定。地址描寫敘述表有32位地址模式和64位地址模式兩種,在32位系統中採用32位地址模式。
圖15 使用ADMA傳輸流程圖
3.2.5 地址描寫敘述表
ADMA1有4K邊界限制,ADMA2沒有,在一般的系統中ADMA2使用更加靈活。兩者的地址描寫敘述表(descriptor table)也不同。
圖16是ADMA descriptor table的結構。
圖16 ADMA descriptortable結構
(1) ADMA1地址描寫敘述表
使用ADMA1的起始地址必須是4K邊界的頂部。但它能夠降低descriptortable的尺寸,。
ADMA1 descriptortable每一條為32bit。圖17是descriptor table的詳細含義。其內容由Host驅動程序組織。請注意ADMA1 descriptor table存儲也必須遵循4KB邊界限制。
圖17 ADMA1 descriptor table位定義
① Nop。表示無操作,ADMA直接跳過這一條。
② Set。表示獲取數據長度,ADMA啟動默覺得4KB,通過該命令改動。
③ Tran,表示獲取首地址並啟動傳輸,地址必須是4KB頂部。
④ Link。表示鏈接到下一個descriptor table的地址。
(2) ADMA2地址描寫敘述表
使用ADMA2僅僅須要保證32位對其就可以,其descriptortable的地址既能夠是32位也能夠是64位,分別用於32位和64位的系統。
圖18是ADMA2 descriptor table位定義。
圖18 ADMA2descriptor table位定義
圖18中所看到的Length域最大為65536字節(Length=0x0000),超過64KB即要利用Link命令新建新的descriptortable。直到能夠將整個文件所有傳輸完成。假設文件傳輸完成須要使能中斷,那么END位和Int位均要置1。
3.2.6 中斷傳輸操作
SD存儲卡採用CMD12。SDIO採用CMD52命令,有兩種情況下的終止傳輸:
(1) 終止無限制傳輸;
(2) 終止多重塊傳輸。
終止方式也有同步終止和異步終止兩種方式:
(1)同步終止:向BlockGap Control寄存器的Block Gap Request寫‘1’停止當前傳輸。等待傳輸完畢后釋放終止命令。最后再進行數據線和命令線的復位。
(2)異步模式:在CommandInhibit不為‘1’的不論什么時刻;
一般來說。僅僅有在事先並不知道傳輸文件長度的情況下才會選擇中斷傳輸操作。
4 FatFs文件系統及實現
Xilinx SDK提供非操作系統下的基於FatFsv0.10b的輕量級文件系統實現。SDK2015.2下的庫版本號是xilffsv3.0。
4.1 FatFS文件系統
FatFS文件系統是開源的輕量級文件系統,作者思路很清晰,代碼短小精悍,有FatFS通用版和FatFs Tiny板兩個版本號。
通用板適合在ARM、PowerPC等RAM較大的處理器上實現,Tiny版適合在C51、AVR等RAM較小的處理器上實現。FATFS具有下面突出特點:
(1) 結構清晰,代碼量少,文件系統和IO底層分開,特別適合剛開始學習的人學習。
(2) 支持最多10個邏輯盤符和兩級文件夾;
(3) 支持FAT12/FAT16和FAT32文件系統;
(4) 支持長文件名稱。默認支持8字節的短文件名稱。
從實現上說,FatFs文件系統僅僅負責文件系統的文件管理,對底層僅僅規定了調用接口函數規范。詳細的驅動需依據不同平台差別設計。
4.1.1 FatFs文件系統的結構
FatFs文件系統最多能夠掛在10個卷,圖19是FatFs文件系統能夠支持的設備層次結構圖。
這樣的,文件系統層與底層獨立的結構能夠讓應用層訪問不同的地層設備。
眼下。FatFs主要是用於SD(MMC)文件系統,用於U盤、NAND Flash還比較少。
圖19 FatFs 支持設備層次結構
4.1.2 FatFs文件系統實現函數具體解釋
能夠通過FatFs官網獲取最新版本號的函數接口技術文檔或搜索keyword“FatFs通用FAT文件系統 0.09a中文手冊”獲得國內技術人員翻譯的中文文檔,這里不再詳述。
4.2 Zynq FatFs實現
Zynq FatFs實現的結構如圖20所看到的,實現是完畢diskio.c中的相關調用函數。
圖20 FatFs實現結構
4.2.1 用戶應用程序
用戶應用程序就是調用文件系統的相關數據進行創建文件夾、格式化、寫入文件、讀出文件等操作。下面是向SD卡寫入文件的樣例。
/***************************************************************************************
* SDWriteAccess()
* Description : This function provides theSD Card interface for the Simplified header
* functionality of Write.
* Argument(s) : SourceAddress is address inDDR data space;
* LengthBytes is the number of bytes to move;
* filename is the name of the Write file inSDcard
* Return(s) : XST_SUCCESS if the controller initializescorrectly
* XST_FAILURE if the controllerfails to initializes correctly.
* Caller(s) : any.
* Note(s) : none.
****************************************************************************************/
FILfil; /* File object */
u32SDWriteAccess(u32 SourceAddress,u32 LengthBytes,constchar *filename)
{
FRESULT rc; /* Result code*/
UINT bw;
strcpy_rom(buffer,filename);
file_name= (char*)buffer;
rc= f_open(&fil, file_name, FA_OPEN_ALWAYS | FA_WRITE);
if (rc) {
xil_printf("SD: Unable to Write File %s\n", file_name);
return XST_FAILURE;
}
rc= f_lseek(&fil, fil.fsize);
if (rc) {
xil_printf("Shift Pointer To the End of File Failed \r\n");
return XST_FAILURE;
}
rc= f_write(&fil,(void*)SourceAddress,LengthBytes,&bw);
if(rc){
xil_printf("Write File To SD Card Failed \r\n");
return XST_FAILURE;
}
rc= f_lseek(&fil, fil.fsize);
if(rc){
return XST_FAILURE;
}
rc= f_close(&fil);
if(rc){
return XST_FAILURE;
}
return XST_SUCCESS;
}
4.2.2 FatFs模塊
FatFs模塊主要是設置其編譯選項,如設置編譯復雜度宏_FS_MINIMIZE。支持長文件名稱宏_MAX_LFN等。依據需求對比ff.h里面的凝視或說明手冊設置就可以。
4.2.3 底層IO接口
底層IO接口,由用戶在diskio.c函數中實現,主要是實現:
① SD卡初始化。通過disk_initialize函數完畢,主要實現圖12所列的SD卡初始化流程。
② 讀數據,通過disk_read實現,從SD卡讀取若干扇區的數據。
③ 寫數據,通過disk_write實現,向SD卡寫入若干扇區的數據。
Xilinxxilffsv3.0文件系統庫眼下採用ADMA2數據傳輸。用輪詢狀態的方式推斷數據傳輸情況,本用於FSBL從SD卡搬運啟動鏡像,在實際使用的過程中可改為中斷的方式釋放CPU資源。
在驅動調試的過程中經常會遇到SD卡一直寫保護的現象,這樣的現象產生的原因通常是:a)TF卡沒有WP引腳,可是在Vivado Block Design中配置ZYNQ時為其配置了該引腳導致誤判;b)Linux驅動默認會一直推斷硬件WP狀態,在操作TF卡時應凝視該功能。
5 總結
應用筆記介紹FAT32文件系統、Zynq SD控制器特點、FatFs文件系統和其在Zynq平台上的實現,希望對有興趣了解文件系統及SD卡底層行為的同行起到拋磚引玉的作用。Xilinx為其SD控制器提供全套的SDK支持包、Uboot驅動和Linux驅動程序,並在Wiki中有具體的驅動使用說明文檔。
如有問題可增加QQ群300148644共同探討。