低功耗、低噪聲的MAXQ2000微控制器適合于多種應(yīng)用。MAXQ2000在閃存中存儲(chǔ)非易失性數(shù)據(jù),并和用戶代碼空間共享32k字(64kB)的閃存容量。但如果你的應(yīng)用需要更多的非易失性存儲(chǔ)器怎么辦呢?這篇文章說明了如何使用安全數(shù)碼(SD?)存儲(chǔ)介質(zhì)來擴(kuò)展MAXQ2000的非易失性數(shù)據(jù)存儲(chǔ)器。
外部存儲(chǔ)器的設(shè)計(jì)考慮
對于你的應(yīng)用設(shè)計(jì)來說,首要應(yīng)該考慮電源電壓和電流的要求。在典型的MAXQ2000應(yīng)用中,可采用一個(gè)雙路線性穩(wěn)壓器,從而在所選的時(shí)鐘頻率下使處理器工作于盡可能低的核心電壓(VDD)下。MAXQ2000的VDD電壓可低至1.8V。VDDIO為MAXQ2000的I/O引腳供電,允許的電壓范圍最低至VDD,最高可達(dá)3.6V。可接受的外部存儲(chǔ)器電流消耗受限于電源的額定電流,對于電池供電設(shè)備,則電流消耗受限于電池系統(tǒng)的容量。其次,在保證能為目標(biāo)應(yīng)用提供足夠帶寬的前提下,應(yīng)將連接外部存儲(chǔ)器的MAXQ2000 I/O數(shù)限制到最少。例如,Atmel的AT29LV512閃存芯片與一個(gè)主機(jī)微控制器連接時(shí),需要15條地址線、8條數(shù)據(jù)線和3條控制線。由于MAXQ2000沒有外部地址/數(shù)據(jù)總線,在上述例子中,就需要由軟件來控制總線事務(wù)。對于某些應(yīng)用來說,這種方法不能很有效地利用MAXQ2000的I/O引腳。
然而,基于SPI?和I2C的外部閃存器件只需要3到4個(gè)接口引腳。MAXQ2000具有一個(gè)硬件SPI模塊,而I2C在MAXQ2000上必須由用戶通過軟件實(shí)現(xiàn)(即"位模擬")。這種集成功能使得SPI接口成為訪問外部非易失性存儲(chǔ)器的主要途徑。
SD存儲(chǔ)卡
SD存儲(chǔ)介質(zhì)是一種非易失性外部存儲(chǔ)器,可滿足許多應(yīng)用的上述要求。SD格式是"多媒體卡" (MMC)格式的繼任產(chǎn)品。SD卡存儲(chǔ)器一般工作于3.3V電壓,具有適度的電流要求。SD卡的容量從幾兆字節(jié)到最高4GB不等。容量范圍如此之寬,可為眾多應(yīng)用提供充足的外部存儲(chǔ)空間。由于SD卡采用專有的共享總線,乍一看,似乎很難與MAXQ2000接口。然而,SD繼承了MMC的第二總線格式-SPI。由于MAXQ2000提供SPI硬件支持,連接非常容易。
圖1. MAXQ2000與SD存儲(chǔ)卡的接口非常簡單。
圖1的電路圖給出了一個(gè)典型應(yīng)用電路。SD卡要求全雙工、8位SPI操作。數(shù)據(jù)從MAXQ2000的MOSI引腳同步輸入SD卡的DI引腳,并由SD卡的DO線同步輸入MAXQ2000的MISO引腳。數(shù)據(jù)在CLK信號(hào)的上升沿同步輸入和輸出。在每次數(shù)據(jù)傳輸?shù)哪┪策€必須提供8個(gè)額外的時(shí)鐘,以允許SD完成任何未完結(jié)的操作。對應(yīng)這些額外時(shí)鐘的輸入數(shù)據(jù)必須全為1。識(shí)別階段的時(shí)鐘頻率必須限定在400kHz以內(nèi),但SD卡一經(jīng)識(shí)別后,時(shí)鐘頻率便可提高到25MHz。
MAXQ2000的SPI模塊
MAXQ2000包含一個(gè)硬件SPI模塊,可以方便地針對SD卡接口進(jìn)行配置。為了配置時(shí)鐘極性和數(shù)據(jù)長度,需將SPICF寄存器置為全零。這種SPI模塊配置在時(shí)鐘的上升沿鎖存數(shù)據(jù),并將數(shù)據(jù)長度設(shè)置為8位。對于本應(yīng)用,MAXQ2000的系統(tǒng)時(shí)鐘頻率為16MHz。在這種情況下,需要將SPICK寄存器置為0x28,從而使SPI時(shí)鐘頻率接近380kHz。必須將SPICN寄存器的低2位置位,以使能SPI主機(jī)模式。SD SPI數(shù)據(jù)格式
SD卡的SPI協(xié)議與SD總線協(xié)議相似。如果一片SD卡沒有數(shù)據(jù)要發(fā)送,則將DO引腳保持在全1的空閑狀態(tài),因此不是在每個(gè)時(shí)鐘沿都從SD卡的DO引腳接收有效數(shù)據(jù)。當(dāng)SD卡有數(shù)據(jù)要回送給主機(jī)時(shí),要在數(shù)據(jù)之前先發(fā)送一些以0為起始位的特定令牌。當(dāng)這些令牌發(fā)送完畢之后,SD卡要發(fā)送的所有定長數(shù)據(jù)立即被發(fā)送出去。由于接收器事先已經(jīng)知道要接收的字節(jié)數(shù),因而響應(yīng)中不包含表征長度的字節(jié)。此外,由于在起始令牌和數(shù)據(jù)都發(fā)送完畢后才會(huì)進(jìn)入空閑狀態(tài),所以全部數(shù)據(jù)字節(jié)都以不帶前綴的原始形式發(fā)送。和總線上其它所有通信過程一樣,令牌大小也要和SPI傳輸?shù)?位邊界對齊。主機(jī)發(fā)送給SD卡的指令和數(shù)據(jù)都遵循類似的格式,以全1指示總線空閑。除了狀態(tài)令牌以外,所有傳輸都由附加在數(shù)據(jù)末尾的循環(huán)冗余校驗(yàn)(CRC)碼進(jìn)行保護(hù)。系統(tǒng)提供兩種CRC算法:CRC-7用于小數(shù)據(jù)塊,CRC-16則用于大數(shù)據(jù)塊。CRC是SD SPI接口的可選部分,但除非應(yīng)用系統(tǒng)限制它的使用,否則應(yīng)該使用CRC來確保數(shù)據(jù)的完整性。循環(huán)冗余校驗(yàn)
CRC算法通常用于檢測由不可靠的通信通道引起的誤差。特定CRC類型的選擇根據(jù)需要保護(hù)的數(shù)據(jù)長度來決定。對于基于SD存儲(chǔ)介質(zhì)的數(shù)據(jù),采用CRC-7和CRC-16編碼方式。CRC算法將被保護(hù)的數(shù)據(jù)用選中的除數(shù)進(jìn)行除法運(yùn)算,產(chǎn)生一個(gè)余數(shù)。因?yàn)樵撍惴ㄖ杏玫玫氖嵌囗?xiàng)式,所以該除法運(yùn)算不含進(jìn)位邏輯。無需考慮進(jìn)位時(shí),除法運(yùn)算可通過邏輯XOR操作來實(shí)現(xiàn)。所選中的除數(shù)通常用CRC的多項(xiàng)式來表示。接著,計(jì)算出的余數(shù)和數(shù)據(jù)一起傳輸,接收器用此余數(shù)來檢查確認(rèn)數(shù)據(jù)在傳輸過程中是否正常。
對于CRC-7,余數(shù)可通過一個(gè)7位移位寄存器在軟件中計(jì)算。計(jì)算開始時(shí),將該移位寄存器初始化置為全零。當(dāng)受保護(hù)數(shù)據(jù)的每一位(MSB在先)被移入移位寄存器的LSB時(shí),移出移位寄存器的MSB,并進(jìn)行檢查。如果移出的位為1,則用CRC-7多項(xiàng)式系數(shù)0x09進(jìn)行異或運(yùn)算,以此來修正移位寄存器的內(nèi)容。如果從移位寄存器中移出的位為0,則無需XOR操作。受保護(hù)數(shù)據(jù)的最后一位被移入移位寄存器且完成了條件XOR操作后,必須按此類似方式移入7個(gè)或更多0。這一過程稱作擴(kuò)張并完成多項(xiàng)式除法運(yùn)算。此時(shí),CRC-7值可從移位寄存器直接讀出。
圖2. 通過移位寄存器架構(gòu)計(jì)算CRC-7。
當(dāng)接收器收到所有受保護(hù)的數(shù)據(jù)后,接收器可計(jì)算基于受保護(hù)數(shù)據(jù)的CRC-7值并將改值與接收到的CRC-7值進(jìn)行比較。如果這兩個(gè)值不同,接收器就能判斷出受保護(hù)數(shù)據(jù)在傳輸過程中出現(xiàn)錯(cuò)誤。如果這兩個(gè)值相同,則接收器可完全判定通信通道上的數(shù)據(jù)是完整的。
CRC-16算法可用同樣的方式來構(gòu)建。在這種情況下,移位寄存器長度為16位而不是7位;多項(xiàng)式系數(shù)改為0x1021,且輸入數(shù)據(jù)通過16個(gè)0位來擴(kuò)張。
SD命令格式
發(fā)送給SD卡的命令采用6字節(jié)的格式(圖3)。命令的第1個(gè)字節(jié)可通過將6位命令碼與16進(jìn)制碼0x40進(jìn)行或運(yùn)算得到。如果命令需要,則在接下來的4個(gè)字節(jié)中提供一個(gè)32位的參數(shù);最后1個(gè)字節(jié)包含了從第1個(gè)字節(jié)到第5個(gè)字節(jié)的CRC-7校驗(yàn)和。表1列出了一些重要的SD命令。圖3. 發(fā)送給存儲(chǔ)卡的SPI模式SD命令采用6字節(jié)格式。
表1. 部分SD存儲(chǔ)卡命令
Command | Mnemonic | Argument | Reply | Description |
0 (0x00) | GO_IDLE_STATE | none | R1 | Resets the SD card. |
9 (0x09) | SEND_CSD | none | R1 | Sends card-specific data. |
10 (0x0a) | SEND_CID | none | R1 | Sends card identification. |
17 (0x11) | READ_SINGLE_BLOCK | address | R1 | Reads a block at byte address. |
24 (0x18) | WRITE_BLOCK | address | R1 | Writes a block at byte address. |
55 (0x37) | APP_CMD | none | R1 | Prefix for application command. |
59 (0x3b) | CRC_ON_OFF | Only Bit 0 | R1 | Argument sets CRC on (1) or off (0). |
41 (0x29) | SEND_OP_COND | none | R1 | Starts card initialization. |
將SD卡初始化為SPI模式
剛上電時(shí),SD卡缺省使用專有的SD總線協(xié)議。為了將SD卡切換到SPI模式,主機(jī)應(yīng)發(fā)出命令0 (GO_IDLE_STATE)。SD卡會(huì)檢測到SPI模式選擇信息,因?yàn)榭ㄟx擇(CS)引腳在該命令和其它所有SPI命令傳送過程中都保持為低電平。SD卡以R1響應(yīng)(圖4)作為回應(yīng)??臻e狀態(tài)位被置為高電平,表明SD卡已進(jìn)入空閑狀態(tài)。為了保持與MMC卡的兼容性,此階段的SPI時(shí)鐘頻率一定不能超過400kHz。圖4. R1響應(yīng)指示發(fā)出的命令是否成功執(zhí)行。
SD卡進(jìn)入SPI模式后,SD規(guī)范要求主機(jī)在進(jìn)行其它任何請求之前先發(fā)送一條初始化命令。為了能區(qū)分MMC卡和SD卡,SD卡采用了一種不同的初始化命令,MMC卡對該命令是不響應(yīng)的。先向卡發(fā)送命令55 (APP_CMD),緊接著再發(fā)送應(yīng)用命令41 (SEND_OP_COND),這樣即完成了這個(gè)重要的步驟。MMC卡對命令55不做回應(yīng),通過這一點(diǎn)可鑒別出MMC卡,并將其視作無效介質(zhì)而拒絕訪問。這個(gè)命令序列要一直重復(fù)執(zhí)行,直到來自存儲(chǔ)卡的R1響應(yīng)中所有位均為0 (也就是說,IDLE位變?yōu)榈?才停止。
清單1. 代碼必須用SEND_OP_COND來識(shí)別SD和MMC卡。
SD卡包含了一些重要的寄存器,用來提供SD卡的相關(guān)信息。最重要的寄存器是存儲(chǔ)卡特定數(shù)據(jù)寄存器(CSD)。對于我們的應(yīng)用示例而言,我們感興趣的是存儲(chǔ)器的數(shù)據(jù)塊大小和總?cè)萘俊N覀冞€必須對存儲(chǔ)卡標(biāo)識(shí)數(shù)據(jù)寄存器(CID)加以注意,因?yàn)樗舜鎯?chǔ)卡的制造商詳細(xì)信息和序列號(hào)。圖5顯示了CSD寄存器和CID寄存器的配置結(jié)構(gòu)。
圖5. CSD寄存器和CID寄存器提供SD卡的相關(guān)信息。
檢查SD卡的響應(yīng)
要讀取存儲(chǔ)卡的寄存器或數(shù)據(jù)塊,我們首先必須理解存儲(chǔ)卡如何響應(yīng)我們的請求。在SPI模式下,SD卡以R1應(yīng)答SEND_CSD (9)、SEND_CID (10)和READ_SINGLE_BLOCK (17)命令。接著則是一個(gè)起始令牌,然后是所請求的數(shù)據(jù),最后是數(shù)據(jù)的CRC-16校驗(yàn)和。我們不能想當(dāng)然地認(rèn)為數(shù)據(jù)起始令牌是緊接著R1響應(yīng)即刻發(fā)出的,因?yàn)榭偩€在這兩個(gè)事件之間會(huì)進(jìn)入空閑狀態(tài)一段時(shí)間。圖6顯示了數(shù)據(jù)響應(yīng)的細(xì)節(jié)。圖6. 從SD卡到主機(jī)的數(shù)據(jù)傳輸要加入一個(gè)起始令牌作為前綴。
讀取CSD寄存器和CID寄存器的元數(shù)據(jù)
使用SEND_CSD和SEND_CID命令可返回寄存器的內(nèi)容,以便確定SD卡的參數(shù)。這些命令分別返回與CSD或CID寄存器容量大小一致的固定數(shù)量的字節(jié)。SEND命令字節(jié)中包含的參數(shù)被SD卡忽略。從SD卡中讀取一個(gè)數(shù)據(jù)塊
從SD卡中讀取一個(gè)數(shù)據(jù)塊是相當(dāng)簡單的。主機(jī)發(fā)出READ_SINGLE_BLOCK命令,并將起始字節(jié)地址作為參數(shù)。這個(gè)地址必須和介質(zhì)上一個(gè)塊的起始位置對齊。然后SD卡會(huì)驗(yàn)證這個(gè)字節(jié)地址,并以一個(gè)R1命令作為響應(yīng)。如果命令中的地址越界,則會(huì)在命令響應(yīng)中指示這種情況。如果完成了SD介質(zhì)的讀取操作并且沒有錯(cuò)誤發(fā)生,則先發(fā)送一個(gè)起始數(shù)據(jù)令牌,接著是固定數(shù)量的數(shù)據(jù),最后是兩個(gè)字節(jié)的CRC-16校驗(yàn)和。如果SD卡碰到硬件故障或介質(zhì)讀取錯(cuò)誤,則不會(huì)發(fā)送起始數(shù)據(jù)令牌。而是發(fā)送一個(gè)錯(cuò)誤令牌,數(shù)據(jù)傳輸隨之中止。
向SD卡中寫入一個(gè)數(shù)據(jù)塊
寫入一個(gè)數(shù)據(jù)塊和讀取數(shù)據(jù)塊類似,即主機(jī)必須提供一個(gè)與SD卡數(shù)據(jù)塊邊界對齊的字節(jié)地址。寫入數(shù)據(jù)塊的大小必須與READ_BL_LEN相同,一般為512字節(jié)。通過發(fā)出WRITE_BLOCK (24)命令啟動(dòng)寫操作過程,SD卡將以R1命令響應(yīng)格式進(jìn)行應(yīng)答。如果命令響應(yīng)表明寫操作可以進(jìn)行,則主機(jī)發(fā)送數(shù)據(jù)起始令牌,接著是固定數(shù)量的數(shù)據(jù)字節(jié),最后以發(fā)送數(shù)據(jù)的CRC-16校驗(yàn)和結(jié)束。SD卡返回一個(gè)數(shù)據(jù)響應(yīng)令牌以指示待寫入的數(shù)據(jù)是否被接受。如果數(shù)據(jù)被接受,SD卡會(huì)在存儲(chǔ)卡忙時(shí)始終將DO線保持為低電平。存儲(chǔ)卡忙期間,主機(jī)不必始終將卡選擇線保持為低電平,如果解除CS選擇狀態(tài),SD卡將釋放DO線。當(dāng)多于一個(gè)的設(shè)備與SPI總線連接時(shí),上述處理方式非常有用。主機(jī)可以一直等待SD卡釋放忙指示標(biāo)志,也可以定期觸發(fā)片選信號(hào)以檢查存儲(chǔ)卡的工作狀態(tài)。如果卡仍然處于忙狀態(tài),它會(huì)將DO線拉低以指示該狀態(tài)。否則,存儲(chǔ)卡會(huì)使DO線返回至空閑狀態(tài)(見圖7)。
圖7. 從主機(jī)到SD卡的數(shù)據(jù)傳輸使用一套更為復(fù)雜的握手機(jī)制。
SPI命令與數(shù)據(jù)錯(cuò)誤檢測
可利用CRC-7和CRC-16校驗(yàn)來檢測主機(jī)與SD卡間的通信錯(cuò)誤。如果因物理因素而導(dǎo)致錯(cuò)誤發(fā)生,如在插入、移除時(shí)的觸點(diǎn)抖動(dòng),或是可拆卸介質(zhì)固有的接觸不良狀況,錯(cuò)誤檢測機(jī)制可實(shí)現(xiàn)堅(jiān)固的錯(cuò)誤恢復(fù)功能。我們強(qiáng)烈建議使用校驗(yàn)和機(jī)制,這可以通過發(fā)出CRC_ON_OFF (59)命令并將參數(shù)的最低位置為高來啟動(dòng)該功能。清單2. 強(qiáng)烈推薦使能CRC校驗(yàn)和。
評(píng)論
查看更多