經過一周左右時間的摸索,終于明白了如何用msp30在SD卡實現FAT32文件系統(tǒng),很開心~在學習的過程中,也發(fā)現一個問題,就是網上系統(tǒng)地講SD卡的資料很少,而講SDHC卡的資料則更少,所以決定寫一篇博客與大家分享,由于SDHC卡大部分內容都與SD卡一樣,所以下文除非是特別介紹SDHC卡,其余都會以SD卡代替SDHC卡。如果發(fā)現文中存在問題,歡迎指正,謝謝。
首先,我們先說明一下本文的主要內容,本文的主要側重點在于利用msp430(其它單片機應該類似)驅動SD卡。驅動方式選用SPI方式,驅動成功之后,將FAT32文件系統(tǒng)移植過來。所以如果想要仔細學習FAT32文件系統(tǒng)的,可以忽略本文了,想要快速地利用單片機在SD卡上實現FAT32文件系統(tǒng)的,可以看一下。大家可以交流一下。
一、開發(fā)之前的準備
1、準備WinHex工具
工欲善其事,必先利其器。在開發(fā)之前,我們必須要先準備好需要的工具,除了相應的單片機開發(fā)平臺,我們還需要一個很重要的工具,WinHex。WinHex可以直接查看磁盤內部的16進制數據。我們把SD卡用卡槽接到電腦上之后,打開WinHex,點擊Tools--Open Disk,然后在Physical Media下選擇自己的SD卡,即可打開自己的SD卡。如下圖所示。這里需要注意的是,一定要在Physical Media下選自己的SD卡,這樣看到才是物理地址,否則看到的是邏輯地址,可能會跟你的實際操作不一致,如你在地址為1024的地方寫了一段數據,用WinHex在這里卻看不到你寫的數據。

2、SD卡和SDHC卡
目前大家口頭上經常說的是SD卡,但實際上,目前所用的大容量的卡其實均是SDHC卡。SD的容量最大只能到2G,而SDHC卡的容量最小2G,最大32G。所以,如果你的“SD卡”的容量超過2G了,那其實那是SDHC卡。SD卡和SDHC卡在用戶使用上,除了容量大了,幾乎體會不到別的區(qū)別,但是在開發(fā)過程中,卻是存在一些區(qū)別的,SD卡是按字節(jié)尋址,SDHC卡是按塊尋址。這一點一定要記住。什么是按字節(jié)尋址,什么是按塊尋址,我們在下文會簡單講解。

3、尋址方式及“塊”和“簇”的簡單介紹
首先,我們介紹一下“塊”的概念,在SD卡或者SDHC卡里,一個塊是由512個字節(jié)組成,每次讀寫的時候,數據都是以塊為單位進行讀寫的。SD卡讀寫是按字節(jié)尋址,這是指其讀寫地址的單位為字節(jié),而我們前面提到,讀寫的時候數據是以塊為單位進行讀寫的,所以讀寫SD卡的時候,其地址應該為512的倍數,即讀寫SD卡時,其地址參數為0,512,1024……而SDHC卡則是以塊為單位尋址的,即讀寫SDHC卡時,地址參數為1時,讀寫的地址實際上用512字節(jié)開始,到1023字節(jié)出結束。從WinHex中,我們也可以看到,在地址為512倍數的上一行,有一條線分割了上下兩行,這其實也就是把塊分割開了,看起來更清楚了。
在這里,我們再簡單介紹一下“簇”。我們在格式化SD卡的時候,可能會忽略一個選項,分配單元大小,如下圖所示,這個其實就是我們常說的“簇”。在文件系統(tǒng)中,存儲文件是以“簇”為單位進行存儲的。就比如說一棟樓,將它劃分為若干個房間,每個房間的大小一樣,同時給每個房間一個房間號.這時,每個房間的大小,就是分配單元. 在建立分區(qū)時,會出現分配單元大小的選項。每個簇只能存放一個文件。文件就是按照這個簇的大小被分成若干塊存儲在磁盤上的。比如一個512字節(jié)大的文件,當分配單元為512字節(jié)時,它占用512字節(jié)的存儲空間;一個513字節(jié)大的文件,當分配單元為512字節(jié)時,它占用1024字節(jié)的存儲空間,但當分配單元為4096時,它就會占用4096字節(jié)的存儲空間。所以,這也就解釋了為什么有時候我們明明看SD卡或者U盤上還有一定容量的存儲空間,卻存不下文件的問題。

二、SD卡命令介紹
SD卡里,用到的所有命令都是6個字節(jié),第一個字節(jié)為命令代號,緊接著的4個字節(jié)為該命令所需的參數,最后一個字節(jié)為校驗。命令里,第一個字節(jié)可以通過命令數+0x40得到。如cmd8的第一個字節(jié)為0x48。
在SPI模式下,我們需要用到底命令如下表所示:

關于這些命令,這里有幾個注意事項:
1)CMD0的最后一個字節(jié)必須為0x95,因為SD卡剛上電還沒有處于SPI模式,還需要這樣一個校驗的字節(jié)來校驗,進入SPI模式之后,則不需要校驗了,最后一個字節(jié)可以隨意;
2)CMD55和CMD41(該命令也常稱為ACMD41)必須一起使用,這里所說的兩個一起使用是指兩個命令必須連續(xù)發(fā)送,而不是先一直發(fā)送CMD55,收到正確的回復之后,再一直發(fā)送CMD41,,這樣做的后果是一直收到0x05,不是收到0x00;此外,發(fā)送完CMD41之后,會先收到一個0x01,然后才是0x00;
3)讀寫SD卡時,SD卡和SDHC卡的地址信息是不同的,一個是以字節(jié)為單位,一個是以塊為單位;讀SD卡時,寫入CDM17之后,要一直讀,直道讀到0xfe,說明后續(xù)的512字節(jié)是數據;寫SD卡時,寫進數據之后,回復為0x05,說明成功寫入。
這些命令對應的回復整理的還不太全面,有些命令的回復是好幾個字節(jié)的,這里沒有詳細寫出。
三、開發(fā)過程
1、硬件方面
由于我們是采用SPI方式驅動SD卡,所以只需要用到4跟線,分別為片選信號線(CS)、數據輸入線(DIN)、數據輸出線(DOUT)和時鐘線(CLK)。這里,我的這四根線都采用外部上拉的方式上拉了。設計的原理圖如下圖所示。這里需要注意的是,SD卡的數據輸入應該接單片機的數據輸出,SD的數據輸出應該接單片機的數據輸入。

在SPI模式下,我們需要用到的4個腳的信息可以從下表中獲取,多于的一些腳在SPI模式下是用不到,這里所有的腳我都上拉了,其實有一些腳不上拉也沒關系,而且MSP430有些型號內部可以設置上拉的。此外,SD卡一般有9個引腳,原理圖里有11個引腳,主要是因為原理圖里畫的是卡槽,多出來的幾個引腳是檢測是否有卡,以及卡是否寫保護的。

2、軟件方面
軟件方面,我們可以分為四個步驟:
- 先編寫出利用SPI接口讀寫一個字節(jié)的函數
- 然后利用這些函數編寫出寫命令函數
- 利用寫命令函數寫出讀寫數據塊以及初始化函數
- 移植FAT32文件系統(tǒng)
(1)讀寫一個字節(jié)的函數
該函數有兩種方式實現,一個是利用單片機自帶的SPI模塊來實現,這種方式的好處是讀寫速度快,但是單片機上的SPI模塊數量有限,這樣不太靈活,另一個是利用普通IO實現,這樣的好處是使用十分靈活,但是速度不夠快,MSP430的IO的極限翻轉速度大概在320K左右。
(2)寫命令函數
寫命令函數其實是調用寫一個字節(jié)的函數,實現發(fā)送6個字節(jié)命令的效果,只是這里有一點需要注意,在寫命令函數里,為了提高兼容性,應該先拉高片選信號,給8個周期的時鐘信號之后,再拉低片選信號,開始發(fā)命令的操作。
(3)讀寫塊函數
讀寫塊函數其實是調用寫命令函數和讀一個字節(jié)的函數,這里需要注意的有兩點,一個就是上文提到的地址信息的問題,另一個就是在讀寫完塊數據之后,需要拉高片選信號,并且再給8個周期的時鐘信號,以提高穩(wěn)定性。
(4)初始化函數
初始化函數其實是整個SD卡驅動里,最為重要的一個環(huán)節(jié),在SD卡的初始化階段里,為了能夠識別出多種類型的SD卡(MMC卡、SD卡、SDHC卡等),需要調用多條命令,并且根據應答數據來判斷是哪種類型的卡。在初始化的時候,需要注意的是要放慢SPI的速度,這樣初始化的成功率會高一些。具體初始化的過程,后面我會再整理一下,做成一張圖上傳的~
(5)移植FAT32文件系統(tǒng)
有了上述的基礎函數之后,就可以把FAT32文件系統(tǒng)移植過來了,只需要把底層的驅動函數改成自己寫的驅動函數就可以了~
四、總結
前段時間,想用MSP430在SD上實現FAT32文件系統(tǒng),由于時間有限,自己只完成了SD卡的底層驅動這一部分。文件系統(tǒng)的實現,則要感謝znFAT的團隊,因為上層的文件系統(tǒng)是移植的他們的znFAT。感覺znFAT的可移植性真的很強,而且很穩(wěn)定,移植起來還是比較順利的~大家如果想對FAT32文件系統(tǒng)有深入的了解的話,可以買znFAT代碼編寫者寫的一本書看下,目前簡單翻了一遍,感覺思路很清晰的~
最后要感謝網上眾多技術達人對于SD卡驅動的總結,之前也遇到不少奇奇怪怪的問題,也是看很多他們的總結,才能順利完成這個任務~