引言
需要微控制器的應(yīng)用通常也需要一些機(jī)制,,即使在掉電的情況下也可以保存設(shè)置,。例如,,一臺(tái)收音機(jī),假如在更換電池的時(shí)候會(huì)丟失之前的電臺(tái)設(shè)置,,肯定不會(huì)在當(dāng)今的市場(chǎng)上獲得成功,。客戶期望喜歡的頻道,、溫度預(yù)設(shè)值,、參數(shù)首選項(xiàng)和其他持久性的信息能夠一直被保存。
為滿足客戶對(duì)非易失數(shù)據(jù)存儲(chǔ)的要求,,設(shè)計(jì)師通常會(huì)使用一個(gè)串行EEPROM,。這些EEPROM器件體積很小、價(jià)格便宜,、而且在市場(chǎng)上已經(jīng)被長(zhǎng)期使用,,設(shè)計(jì)工程師使用這些器件非常便利。但是在當(dāng)今對(duì)成本非常敏感的市場(chǎng)領(lǐng)域,,增加一個(gè)并不昂貴的EEPROM可能會(huì)使設(shè)計(jì)超出預(yù)算,。
很多處理器使用閃存存儲(chǔ)程序代碼,使用靜態(tài)RAM存儲(chǔ)數(shù)據(jù)信息,。盡管充分利用閃存未使用的部分作為非易失數(shù)據(jù)存儲(chǔ)很有吸引力,,但是傳統(tǒng)的哈佛架構(gòu)制約了這種應(yīng)用。MAXQ架構(gòu)屬于哈佛架構(gòu),,具有獨(dú)立的代碼和數(shù)據(jù)總線,。但MAXQ器件包含的硬件部分可以實(shí)現(xiàn)偽馮諾依曼架構(gòu),,如同訪問(wèn)數(shù)據(jù)空間一樣訪問(wèn)代碼空間。這種額外的多功能性,,結(jié)合MAXQ的效用函數(shù),,可實(shí)現(xiàn)存儲(chǔ)器的擦寫服務(wù),為完整的可讀寫非易失存儲(chǔ)子系統(tǒng)提供了解決方案,。
關(guān)于閃存的基本考慮
閃存是一種電子可擦除存儲(chǔ),。通常也被認(rèn)為是“主讀”。簡(jiǎn)言之,,盡管閃存是可寫的,,但數(shù)據(jù)更新并不會(huì)很頻繁,多數(shù)的操作都是讀操作,。多數(shù)閃存器件從字面意思來(lái)講都是可寫的,,但每次只能整塊擦除。這使得那些存儲(chǔ)器件通常都不適合用于易變存儲(chǔ),,只適合用作從不改變內(nèi)容的固定數(shù)據(jù)存儲(chǔ),。
有兩種類型的閃存:NAND閃存和NOR閃存。NAND閃存用在存儲(chǔ)卡和U盤中,。通常,,由于數(shù)據(jù)按時(shí)鐘串行傳輸,從NAND器件中讀數(shù)據(jù)需要數(shù)個(gè)周期,。這種有序的操作使NAND閃存不適合用作程序代碼存儲(chǔ),,因?yàn)樽x取時(shí)間會(huì)太長(zhǎng),。相反,NOR閃存類似傳統(tǒng)字節(jié)寬度或字寬度存儲(chǔ)。讀取NOR閃存就像讀取ROM器件:先發(fā)器件選擇和地址命令,,在等待足夠的存取時(shí)間之后,,從總線上讀取數(shù)據(jù),。NOR閃存用于MAXQ處理器中,。
MAXQ處理器的閃存
MAXQ處理器中使用的閃存單元被擦除時(shí)會(huì)變成“1”狀態(tài)。因此,,在擦除后,,存儲(chǔ)單元中的每個(gè)位置都將包含0xFFFF。對(duì)某一存儲(chǔ)位置進(jìn)行編程會(huì)把某些位從“1”變成“0”狀態(tài),。為了使被編程過(guò)的位重新變回“1”狀態(tài),,整個(gè)單元必須被擦除。
任何電擦除的存儲(chǔ)器件必須面臨的問(wèn)題是持久性,。根據(jù)特定的技術(shù),,一個(gè)閃存單元在完全失效之前,,可以忍耐的擦除次數(shù)少達(dá)1,000次,,多達(dá)1,000,000次。因此,使用閃存做數(shù)據(jù)存儲(chǔ)的任何應(yīng)用都必須保證寫操作循環(huán)在整個(gè)陣列中均勻分布,,不允許某一個(gè)位置的擦除編程次數(shù)比其他位置多很多,。
多數(shù)閃存器件都允許把之前已經(jīng)編程過(guò)的位置中的沒(méi)有編程過(guò)的位從“1”變成“0”狀態(tài)。例如,,對(duì)于多數(shù)器件,,允許對(duì)某個(gè)位置編程,把數(shù)據(jù)從0xFFFE變?yōu)?x7FFE,,在這個(gè)編程過(guò)程中,,沒(méi)有任一個(gè)位從“0”變成“1”。然而,,MAXQ系列器件中使用的閃存,,不允許對(duì)已經(jīng)編程過(guò)的位置再編程,即使沒(méi)有發(fā)生從“0”到“1”的變化,。這樣的寫操作會(huì)失敗,,保持?jǐn)?shù)據(jù)在0xFFFE狀態(tài)。
MAXQ器件編程受限制的理由如下,。正在被編程的存儲(chǔ)單元起初是作為代碼空間的,,所以必須很謹(jǐn)慎,禁止對(duì)已寫過(guò)的位置的任何寫操作,。0xFFFF指令指一條無(wú)效的源代碼,,它不太可能出現(xiàn)在有效的代碼單元內(nèi)。因此,,阻止對(duì)已編程過(guò)的位置的寫操作能夠幫助保持代碼單元的完整性,。
使用MAXQ2000的設(shè)計(jì)方案
在這篇文章中,我們主要討論一個(gè)MAXQ器件:MAXQ2000,。這個(gè)微處理器具有64kB的程序存儲(chǔ)空間,,具體劃分為128個(gè)單元,每個(gè)單元具有256個(gè)16位的字,。下面介紹兩種設(shè)計(jì)方案,。第一種方案適用于信息寫一次后在產(chǎn)品的生命周期內(nèi)不會(huì)再頻繁改動(dòng),例如校準(zhǔn)數(shù)據(jù),、版本信息和特征參數(shù)等等,。第二種方案針對(duì)更普通的裝置,這種設(shè)計(jì)要允許數(shù)據(jù)頻繁改動(dòng),,例如使用信息或者詳細(xì)記錄等,。
方案1
問(wèn)題:校準(zhǔn)數(shù)據(jù)需要存儲(chǔ)在產(chǎn)品中。產(chǎn)品會(huì)一直需要重新校準(zhǔn),,所以校準(zhǔn)數(shù)據(jù)必須保存在一個(gè)可改寫的存儲(chǔ)空間中,。
解決方案:這實(shí)際上是可以想象的到的最簡(jiǎn)單的情況,。MAXQ2000程序存儲(chǔ)空間中預(yù)留了兩個(gè)單元用于存儲(chǔ)校準(zhǔn)數(shù)據(jù),一個(gè)是字地址0x7E00,,另一個(gè)是0x7F00,。當(dāng)MAXQ2000第一次收到保存校準(zhǔn)數(shù)據(jù)的命令,它就會(huì)檢查這兩個(gè)單元并確保它們是空的,。校準(zhǔn)數(shù)據(jù)被保存到第一個(gè)單元,。
當(dāng)MAXQ2000第二次收到保存校準(zhǔn)數(shù)據(jù)的命令,它會(huì)再次檢查這兩個(gè)單元,。當(dāng)發(fā)現(xiàn)0單元已被使用,,它會(huì)把校準(zhǔn)數(shù)據(jù)復(fù)制到1單元,接著擦除0單元,。
當(dāng)MAXQ2000收到讀校準(zhǔn)數(shù)據(jù)的請(qǐng)求(例如在上電時(shí)),,它會(huì)讀這兩個(gè)單元,看哪個(gè)正在被使用,。沒(méi)有被擦除的單元用來(lái)配置器件到校準(zhǔn)狀態(tài),。
這種方案的最主要優(yōu)點(diǎn)是簡(jiǎn)易性。當(dāng)某些應(yīng)用需要在上電時(shí)作配置時(shí)(或者其它恢復(fù)配置的情況),,這種方法很適用,。讀程序會(huì)接收到一個(gè)字指針,并返回這個(gè)地址的內(nèi)容,;寫程序會(huì)接收一個(gè)字指針,,并嘗試對(duì)這個(gè)地址寫操作。擦除程序會(huì)擦除這兩個(gè)單元,。
這種方案的缺點(diǎn)是:子程序極其不智能,。無(wú)法判斷寫操作是否成功。假如寫操作失敗了,,不會(huì)有任何動(dòng)作來(lái)解決問(wèn)題,。為什么這種方案只適用于對(duì)已知的空單元寫操作,以上這種限制就是其原因,。
方案2
問(wèn)題:非易失存儲(chǔ)用來(lái)跟蹤用電量和其它會(huì)經(jīng)常改變的數(shù)據(jù),。更新的頻率從一周數(shù)次到一天數(shù)次。電表是一個(gè)很好的應(yīng)用舉例,。
解決方案:在這種情況下即時(shí)傳統(tǒng)的EEPROM也需要另求幫助,。問(wèn)題在于:頻繁的更新、和可擦除存儲(chǔ)技術(shù)固有的有限電擦除壽命,,排除了使用單個(gè)EEPROM頻繁寫擦除操作的可能性,。假如這種應(yīng)用需要每小時(shí)更新一次。具有10,000次寫擦除次數(shù)限制的EEPROM只能工作一年,,遠(yuǎn)遠(yuǎn)低于電表應(yīng)用所需的10年壽命設(shè)計(jì)目標(biāo),。
這個(gè)問(wèn)題的解決方案是實(shí)現(xiàn)“損耗平衡”,。也就是指不對(duì)單一位置重復(fù)寫操作。相反,,在整個(gè)存儲(chǔ)陣列中執(zhí)行均勻分布的寫操作,。
正是基于此目的,,損耗平衡技術(shù)被接受,,并在閃存存儲(chǔ)設(shè)備中使用。它的算法非常復(fù)雜難以理解,。但對(duì)于我們,,介紹簡(jiǎn)單的機(jī)理就足夠了。
在這種設(shè)計(jì)中,,存儲(chǔ)陣列中的數(shù)據(jù)條目并不是以地址作參考,,而是以數(shù)據(jù)元編號(hào)為參考。數(shù)據(jù)元編號(hào)是一個(gè)和數(shù)據(jù)元素一一對(duì)應(yīng)的任意8位數(shù)值,。所以在這個(gè)方案中最大可以有255個(gè)數(shù)據(jù)元(數(shù)據(jù)元0預(yù)留),。每個(gè)數(shù)據(jù)元包含:包括數(shù)據(jù)元編號(hào)和數(shù)據(jù)元長(zhǎng)度的雙字節(jié)報(bào)頭(圖1);指示1,、2,、3或者4個(gè)16位字的兩位碼,以保留足夠的剩余空間進(jìn)行錯(cuò)誤管理,。
圖1. 數(shù)據(jù)單元報(bào)頭結(jié)構(gòu)
寫數(shù)據(jù)單元時(shí),,寫子程序必須知道要寫的數(shù)據(jù)、數(shù)據(jù)單元的長(zhǎng)度和數(shù)據(jù)要寫的位置,。很容易可以知道數(shù)據(jù)寫在哪個(gè)地址,;無(wú)論是新數(shù)據(jù)單元還是更新已有的數(shù)據(jù)單元,都會(huì)寫在存儲(chǔ)陣列的末尾,。寫命令會(huì)搜索陣列的末尾,,緊接著在最后一個(gè)記錄后寫入新的數(shù)據(jù)單元。假如在當(dāng)前的存儲(chǔ)頁(yè)面沒(méi)有足夠的空間保存特定長(zhǎng)度的數(shù)據(jù)元,,就會(huì)出現(xiàn)頁(yè)面結(jié)束標(biāo)志并打開(kāi)一個(gè)新頁(yè)面,。圖2是這種典型的數(shù)據(jù)頁(yè)面的結(jié)構(gòu)。
在這個(gè)數(shù)據(jù)頁(yè)面中,,先寫數(shù)據(jù)單元1,,并更新。接著寫數(shù)據(jù)單元4,,但從不更新,。隨后是數(shù)據(jù)單元3,共更新7次,。最后寫入數(shù)據(jù)單元2,,從不更新,。
頁(yè)面結(jié)束標(biāo)志的出現(xiàn)表明曾執(zhí)行寫操作,但數(shù)據(jù)單元太長(zhǎng)不能填入當(dāng)前頁(yè)面,。會(huì)打開(kāi)一個(gè)新頁(yè)面以填寫數(shù)據(jù)單元,。在整個(gè)數(shù)據(jù)結(jié)構(gòu)的末尾會(huì)分配一個(gè)空單元,這里本該是一個(gè)數(shù)據(jù)單元的報(bào)頭,。
圖2. 典型的數(shù)據(jù)頁(yè)面
要注意這種方案并沒(méi)有涉及重復(fù)記錄的問(wèn)題,。因?yàn)橹貜?fù)記錄不會(huì)有問(wèn)題。事實(shí)上,,讀和寫程序都會(huì)完全忽略重復(fù)記錄,。寫操作時(shí),不管同樣編號(hào)的記錄是否存在,,新記錄都會(huì)寫在陣列的末尾,。當(dāng)讀操作時(shí),只有符合請(qǐng)求記錄編號(hào)的最后一個(gè)(所以是最近的)記錄可以讀到,。
從陣列中讀取數(shù)據(jù)元會(huì)比寫操作更復(fù)雜,。讀功能會(huì)收到數(shù)據(jù)元編號(hào)和數(shù)據(jù)元應(yīng)該寫入的地址。當(dāng)執(zhí)行此命令時(shí),,讀操作會(huì)從陣列的最開(kāi)始進(jìn)行搜索,。當(dāng)它找到一個(gè)記錄符合被請(qǐng)求的數(shù)據(jù)元,它會(huì)保存這個(gè)地址并繼續(xù)搜索,。當(dāng)它找到另外一個(gè)匹配的記錄時(shí),,讀命令會(huì)用新地址替代已保存的地址。當(dāng)搜索到陣列的末尾時(shí),,保存的地址就會(huì)是符合請(qǐng)求記錄的最近寫入的記錄,。當(dāng)執(zhí)行讀操作時(shí),就會(huì)把這個(gè)數(shù)據(jù)復(fù)制到緩存中,。
盡管所介紹的用來(lái)從存儲(chǔ)陣列中保存和讀取記錄的主讀機(jī)制是可行的,,還會(huì)存在一個(gè)問(wèn)題:沒(méi)有機(jī)制可以重新使用被過(guò)時(shí)的記錄占用的空間(也沒(méi)有機(jī)制可以刪除記錄。但由于這種方案是針對(duì)嵌入式應(yīng)用開(kāi)發(fā)的,,所以可能不會(huì)是個(gè)很嚴(yán)重的問(wèn)題,。)。如果不重新恢復(fù)一些空間,,這些之前被分配的空間會(huì)很快用盡,。由于閃存只能每次擦除一整個(gè)頁(yè)面,恢復(fù)空間意味著擦除整個(gè)頁(yè)面,。另外一個(gè)更嚴(yán)重的問(wèn)題是閃存頁(yè)面不能被隨便擦除,,會(huì)存在刪除有用信息的風(fēng)險(xiǎn)。唯一的可選方案是在刪除整個(gè)舊頁(yè)面之前,把有用信息復(fù)制到一個(gè)新頁(yè)面,。
從廢舊的記錄中恢復(fù)空間有三個(gè)步驟,。第一,打開(kāi)新頁(yè)面,,把每個(gè)數(shù)據(jù)元的最近版本復(fù)制到新頁(yè)面中,。第二,擦除舊頁(yè)面,。第三,,對(duì)新頁(yè)面做頁(yè)面標(biāo)示,是讀命令可以找到新頁(yè)面,。
第一個(gè)步驟比較復(fù)雜,,需要更詳細(xì)的檢查,。完成這個(gè)步驟最簡(jiǎn)單的方法可以分成兩個(gè)子步驟:第一,,使用一個(gè)RAM保存記錄編號(hào)和陣列中最近記錄的地址;第二,,從RAM陣列逐一復(fù)制最近記錄到新閃存頁(yè)面,。這個(gè)過(guò)程最快,并且相對(duì)簡(jiǎn)單,。
使用這兩個(gè)子步驟存在的問(wèn)題是MAXQ2000只有1k字的RAM空間,。上述方案限制了可以保存到RAM中作緩存的數(shù)據(jù)量。這明顯是不能接受的,。
這種難題的解決方案非常耗時(shí),,但不管存儲(chǔ)陣列變得多大(合理范圍內(nèi))都是可行的。為源陣列中的每一項(xiàng)條目單獨(dú)操作,,而不是在RAM中建立指針,。因此,算法可以簡(jiǎn)化為:
- 從源陣列讀取一個(gè)數(shù)據(jù)元,。
- 在目標(biāo)陣列中搜索這個(gè)數(shù)據(jù)單元,。假如找到了,就說(shuō)明這個(gè)數(shù)據(jù)單元已經(jīng)寫入,。源指針增加并返回步驟1,。
- 在源陣列中搜索這個(gè)數(shù)據(jù)單元最近記錄。
- 把這個(gè)數(shù)據(jù)單元的最近記錄寫入目標(biāo)陣列中,。
- 源指針增加并返回步驟1,。
最后,在目標(biāo)陣列中,,每個(gè)數(shù)據(jù)元都有精確的條目對(duì)應(yīng),。填寫后的頁(yè)面如圖3示意。這樣,,就可以安全擦除源頁(yè)面,,并把頁(yè)面報(bào)頭寫入目標(biāo)陣列,。
圖3. 空間恢復(fù)后,圖2中的數(shù)據(jù)頁(yè)面會(huì)如此表現(xiàn),。
這個(gè)過(guò)程對(duì)于數(shù)據(jù)存儲(chǔ)會(huì)非常安全,。然而,當(dāng)使用閃存器件時(shí)還要面對(duì)另一個(gè)風(fēng)險(xiǎn):在寫或者擦除操作中掉電,。假如發(fā)生掉電,,有可能會(huì)破壞一個(gè)或者多個(gè)頁(yè)面(例如寫操作)或者不能完全擦除頁(yè)面(例如擦除操作)。而我們這種緊湊的操作從本質(zhì)上講是安全的,??梢钥紤]以下的情況:
- 假如在填寫操作時(shí)掉電,源頁(yè)面仍然保持完整,。當(dāng)重新上電后,,很容易辨別新寫的頁(yè)面(他們沒(méi)有頁(yè)面報(bào)頭)并把它擦除,再重新啟動(dòng)填寫操作,。
- 假如在正擦除舊頁(yè)面時(shí)掉電,,可能會(huì)包含無(wú)效的報(bào)頭??梢圆脸@些頁(yè)面并把報(bào)頭添加到新頁(yè)面,。
- 假如在正把頁(yè)面報(bào)頭寫入到新頁(yè)面時(shí)掉電,數(shù)據(jù)仍然是完整的,。頁(yè)面報(bào)頭更新操作可以再次重新啟動(dòng),。
- 簡(jiǎn)言之,這些預(yù)料之外的突發(fā)事件不會(huì)導(dǎo)致陣列數(shù)據(jù)被破壞并不可恢復(fù),。
方案2的改進(jìn)
這里介紹的存儲(chǔ)子系統(tǒng)沒(méi)有錯(cuò)誤檢測(cè)的機(jī)制,。在數(shù)據(jù)元標(biāo)識(shí)符中有一些位(這里的是6位)沒(méi)有被使用??梢允褂?a class="innerlink" href="http://forexkbc.com/tags/CRC" title="CRC" target="_blank">CRC6算法(x6 + x + 1)根據(jù)數(shù)據(jù)元計(jì)算出CRC以確保沒(méi)有發(fā)生讀寫錯(cuò)誤,。這雖然不是特別強(qiáng)大的算法(它會(huì)錯(cuò)過(guò)多位錯(cuò)誤中的1/64),它可以檢測(cè)到多數(shù)可能發(fā)生的錯(cuò)誤,。
這個(gè)方法對(duì)系統(tǒng)的另一個(gè)限制是讀取時(shí)間很長(zhǎng),。每次讀操作都需要讀取陣列中的所有記錄,以找到最近的記錄,。有3個(gè)方法可以用來(lái)縮短讀取時(shí)間:
在數(shù)據(jù)單元中為正向指針留一個(gè)空字節(jié),。當(dāng)數(shù)據(jù)更新時(shí),為正向指針?lè)峙湟粋€(gè)新的入口地址,。按照這種方式,,數(shù)據(jù)表格可以按鏈表的方式移動(dòng)。
向后移動(dòng)表格。這樣就可以在被請(qǐng)求信號(hào)第一次出現(xiàn)時(shí)停止搜索,。
假如單元數(shù)量很少,,可以在啟動(dòng)時(shí)建立一個(gè)RAM陣列,包含單元ID和指針,。后面的讀取會(huì)很快,。只需讀RAM陣列以決定從哪兒獲取數(shù)據(jù)單元。
結(jié)論
非易失數(shù)據(jù)存儲(chǔ)是每位設(shè)計(jì)工程師遲早都必須面對(duì)的問(wèn)題,。使用MAXQ處理器靈活的閃存,,就不用再借助于串行存儲(chǔ)保存配置數(shù)據(jù)了。