<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > SD卡和FAT文件系統(tǒng)示例

          SD卡和FAT文件系統(tǒng)示例

          作者: 時(shí)間:2016-11-10 來源:網(wǎng)絡(luò) 收藏
          1. 初始化SD卡。

          我現(xiàn)在用的多是SPI模式,所以在這里只討論SPI模式。在SPI模式中,所有的指令都要求先將CS腳置0。所以這點(diǎn),我在后面就不再強(qiáng)調(diào)了。

          CMD0,使SD卡從SD模式轉(zhuǎn)到SPI模式。判斷返回值R0,如果不是CARD IS NOT READY,說明硬件上有問題。
          CMD8,參數(shù)是0x000001AA,判斷SD卡符合哪個(gè)標(biāo)準(zhǔn)。如果返回ILLEGAL COMMAND,說明是ver1.x的卡,否則就是ver2.0的卡。
          CMD1,如果是ver2.0的卡,參數(shù)是1<<30,否則就是0,讀取SD卡的狀態(tài),反復(fù),直到CARD IS READY或者超時(shí)。這里有一個(gè)問題,Spec上建議使用ACMD1,說是通用性比CMD1好,而且CMD1并不是一開始就可以使用的。但是我在實(shí)際使用中,發(fā)現(xiàn)一些老卡對這個(gè)指令會返回PARAMETER ERROR。搞不懂是為什么,而且實(shí)際使用中CMD1也很好用,并沒有出現(xiàn)SD卡不能初始化的問題,所以我現(xiàn)在都直接用CMD1。

          到這里基本上SD卡就初始化完畢了。接下來就可以讀取數(shù)據(jù)了。

          2. 讀取CID(CMD10),SD卡鑒別信息,這一步不是必須的。

          鑒別信息中包括了生產(chǎn)商ID,應(yīng)用ID,產(chǎn)品名稱,產(chǎn)品版本,產(chǎn)品序列號,生產(chǎn)日期。

          3. 讀取CSD(CMD9),SD卡信息。

          返回的CSD有兩個(gè)版本。

          if (CSD[0] & 0x40 == 0x40) // ver2.0的卡
          容量 = 1024L*(CSD[8]<<8+CSD[9])
          這個(gè)數(shù)字就是這張SD卡里面總共有多少個(gè)扇區(qū)。

          if (CSD[0] & 0x40 != 0x40) // ver1.x的卡
          容量 = (((CSD[6]&0x03)<<10) | (CSD[7]<<2) | ((CSD[8]&0xC0)>>6) + 1) * (1 << ((((CSD[9]&0x03)<<1) | ((CSD[10]&0x80)>>7)) + 2))

          4. 讀取Partition Table。
          讀取SD卡的扇區(qū)0到buf。
          如果buf[0]不是0xEB或者0xE9,說明這是一個(gè)分區(qū)表。
          buf[454]開始的四個(gè)byte是該分區(qū)前的扇區(qū)數(shù)。例如63表示在這個(gè)分區(qū)前有63個(gè)扇區(qū),那么這個(gè)分區(qū)的第一個(gè)扇區(qū)就是扇區(qū)63。
          buf[458]開始的四個(gè)byte是該分區(qū)的扇區(qū)數(shù)。例如7990000,不是這個(gè)分區(qū)有7990000個(gè)扇區(qū)。那么這個(gè)分區(qū)的塊地址就是63~7990063。
          一個(gè)設(shè)備可以最多有四個(gè)分區(qū),其他三個(gè)分區(qū)的相關(guān)數(shù)據(jù)是在buf[470]/buf[474],buf[486]/buf[490],buf[502]/buf[506]。
          注意,讀取buf的時(shí)候檢查最好兩位,應(yīng)該是55AA。

          5. 讀取BPB。
          好,到這里我們已經(jīng)知道第一個(gè)分區(qū)是在什么位置了?,F(xiàn)在需要做的就是讀取這個(gè)分區(qū)的0扇區(qū)。也就是SD卡的第36個(gè)扇區(qū)。
          這個(gè)512個(gè)byte就是這個(gè)分區(qū)的詳細(xì)資料了。

          檢查buf[0],應(yīng)該是0xEB或者0xE9。如果是的話,那就是BPB表了。接下來比較重要的幾個(gè)數(shù)字是:
          buf[13]的Sectors Per Cluster,就是每個(gè)簇的扇區(qū)數(shù),也就是你在讀取文件是需要一次讀取的扇區(qū)數(shù)。例如8。
          buf[14-15]的Reserved Sectors,保留扇區(qū)數(shù),這個(gè)保留扇區(qū)是在分區(qū)第一個(gè)扇區(qū)到FAT表之間的扇區(qū)數(shù)。例如38。
          buf[28-31]的Hidden Sectors,隱藏扇區(qū)數(shù),這個(gè)隱藏扇區(qū)指的是在這個(gè)分區(qū)前面有多少個(gè)扇區(qū),這個(gè)值在分區(qū)表里也有的。就是63。
          buf[19-20]和buf[32-35],前者是FAT16格式中的扇區(qū)數(shù),后者是FAT32格式中的扇區(qū)數(shù)。這個(gè)值在分區(qū)表里也是有的。就是7990000。
          buf[16],F(xiàn)AT表數(shù),一般是2。
          buf[22-23],buf[36-39],F(xiàn)AT表占用的扇區(qū)數(shù),前者是FAT16的,后者是FAT32的。例如7793。

          好了,到這里我們就可以讀取FAT文件系統(tǒng)中的數(shù)據(jù)了。

          6. 讀取FAT表。
          在上面的例子中,F(xiàn)AT表的位置應(yīng)該是分區(qū)的第一個(gè)扇區(qū)再偏移隱藏扇區(qū)數(shù),就是63+38,等于101。所以從SD卡的101扇區(qū)開始,就是分區(qū)一的FAT表,一共有7793個(gè)扇區(qū)。

          7. 讀取根目錄。
          在FAT16中,根目錄是單獨(dú)的。應(yīng)該是可以建立512個(gè)文件,每個(gè)文件占用32byte,所以總共是512*32/512=32個(gè)扇區(qū)。
          根目錄是跟在FAT表后面的,所以第一個(gè)扇區(qū)是在101+7793*2=15687。

          對于FAT32系統(tǒng),這段忽略。

          8. 讀取數(shù)據(jù)區(qū)。
          FAT16中,數(shù)據(jù)區(qū)是在根目錄后面的,所以第一個(gè)扇區(qū)是15687+32=15719。就是在SD卡上的第15719個(gè)扇區(qū)。

          而FAT32中,由于沒有根目錄,所以數(shù)據(jù)區(qū)直接跟在FAT表后面的,所以就是第15687個(gè)扇區(qū)。這個(gè)扇區(qū)就是LBA=2的地方。所以之后如果上層的文件操作函數(shù),要對LBA=1000寫數(shù)據(jù),那就是對1000+15687=16687扇區(qū)進(jìn)行寫操作。

          到此,我們就得到了整個(gè)FAT系統(tǒng)的結(jié)構(gòu)和數(shù)據(jù),接下來就可以開始操作文件了。


          關(guān)鍵詞: SD卡AT文件系

          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();