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

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

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

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

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

在SPI模式下,我們需要用到的4個(gè)腳的信息可以從下表中獲取,多于的一些腳在SPI模式下是用不到,這里所有的腳我都上拉了,其實(shí)有一些腳不上拉也沒關(guān)系,而且MSP430有些型號(hào)內(nèi)部可以設(shè)置上拉的。此外,SD卡一般有9個(gè)引腳,原理圖里有11個(gè)引腳,主要是因?yàn)樵韴D里畫的是卡槽,多出來的幾個(gè)引腳是檢測(cè)是否有卡,以及卡是否寫保護(hù)的。

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