利用基于閃存的MCU實(shí)現用戶(hù)數據存儲
方案1
本文引用地址:http://dyxdggzs.com/article/84016.htm問(wèn)題:校準信息、MAC地址或制造數據等配置數據必須要存儲在產(chǎn)品中。雖然這些通常是固定不變的信息,但在整個(gè)產(chǎn)品生命周期內配置數據需要多次更新的可能性還是存在的。
解決方案:下面是實(shí)際中最容易想到的例子。有兩個(gè)塊,一個(gè)塊在字地址0x7E00處,另一個(gè)在0x7F00處,都用于數據存儲。在第一次收到保存配置數據的命令時(shí),處理器會(huì )檢查這兩個(gè)塊,在發(fā)現它們都是空塊后,配置數據被就存入第一個(gè)塊。
保存配置數據的第二條命令同樣會(huì )使處理器再一次檢查這兩個(gè)塊。當發(fā)現塊0已經(jīng)有數據后,它就將配置數據拷貝到塊1,然后擦除塊0中的數據。
當收到恢復配置的請求時(shí)(比如在上電時(shí)),處理器會(huì )同時(shí)讀取兩個(gè)塊的數據并確定哪個(gè)塊在用。只要是沒(méi)被擦除的塊就是在用塊。
這種方案的主要優(yōu)點(diǎn)是簡(jiǎn)單:如果設備在上電(或其他配置恢復事件)時(shí)需要塊中的配置數據,這是很好的一種方案。讀數程序會(huì )接受一個(gè)字長(cháng)的指針,返回該地址的數值,寫(xiě)入程序則接受一個(gè)字長(cháng)的指針,然后嘗試向該地址進(jìn)行寫(xiě)入操作。擦除程序只是同時(shí)擦除兩個(gè)塊。
這種方案的主要缺點(diǎn)就是主要優(yōu)點(diǎn)的反面:程序的思路太過(guò)簡(jiǎn)單。沒(méi)有操作去判斷寫(xiě)入數據是否成功—在發(fā)出寫(xiě)入命令后,如果寫(xiě)入失敗,處理器不會(huì )做任何事去解決問(wèn)題。這也是為什么這個(gè)方案只是用來(lái)寫(xiě)入已知是空的閃存塊的原因。
方案2
問(wèn)題:要求用非易失性存儲技術(shù)來(lái)跟蹤用電量和其他經(jīng)常變化的數據。更新經(jīng)常是一周數次或一天數次發(fā)生。
解決方案:這是即使傳統EEPROM也需要尋求幫助的場(chǎng)合。問(wèn)題是:更新的頻率和所有非易失性存儲器有限的寫(xiě)入壽命這樣的事實(shí)不允許反復寫(xiě)入和擦除單個(gè)EEPROM單元??紤]一個(gè)小時(shí)更新一次的情況,具有1萬(wàn)次寫(xiě)入-擦除次數限制的EEPROM只需一年時(shí)間就會(huì )失效,這個(gè)時(shí)間比電表所需的十年設計目標少得太多了。
解決這個(gè)問(wèn)題的方法之一是實(shí)現某種形式的“損耗均衡”。這意味著(zhù)不會(huì )有單個(gè)位置被反復寫(xiě)數據。相反,寫(xiě)入操作將呈類(lèi)似合理指數分布的方式分散到整個(gè)存儲器陣列。
損耗均衡是一種很好理解的技術(shù),在閃存器件中使用就是出于這個(gè)目的。但它的算法非常復雜和難以理解,不過(guò)對我們來(lái)說(shuō),一個(gè)更簡(jiǎn)單的原理介紹就足夠了。
存儲陣列中的數據項是由數據單元(data element)號引用的,而不是地址。
數據單元號是一個(gè)唯一識別數據單元的任意8位數,因此在這種方案中,最多有255個(gè)數據單元(數據單元0是保留單元)。
每個(gè)數據單元有一個(gè)雙字節的頭部(見(jiàn)圖2),包含了數據單元號和數據單元長(cháng)度以及留給差錯管理使用的足夠空間,其中長(cháng)度是一個(gè)兩位代碼,可表示1個(gè)、2個(gè)、3個(gè)或4個(gè)16位的字。
圖2:數據單元的頭部結構
寫(xiě)一個(gè)數據單元需要知道寫(xiě)入數據的地址、寫(xiě)入數據的單元號和長(cháng)度。寫(xiě)函數先尋找陣列結尾,然后緊跟最后一個(gè)記錄之后寫(xiě)入新的數據單元。
如果閃存頁(yè)中沒(méi)有足夠的空間容納指定長(cháng)度的記錄,一個(gè)表示結尾的頁(yè)標記將被寫(xiě)入,并會(huì )打開(kāi)一個(gè)新的頁(yè)。有關(guān)典型數據頁(yè)的結構請見(jiàn)圖3。
圖3:典型的數據頁(yè)
在展開(kāi)的數據頁(yè)中,先寫(xiě)入經(jīng)常要更新的數據單元1,再寫(xiě)入從不更新的數據單元4,然后寫(xiě)入需要多次更新的數據單元3。最后,寫(xiě)入從不更新的數據單元2。
出現頁(yè)的結尾標記表明過(guò)進(jìn)行過(guò)一次數據寫(xiě)入嘗試,但由于數據單元太長(cháng)而無(wú)法將數據單元裝進(jìn)該頁(yè),因此打開(kāi)了一個(gè)新頁(yè)來(lái)容納該數據單元。整個(gè)數據結構的結尾設定為空白單元,這個(gè)位置有望成為單元頭部。
值得注意的是,我還沒(méi)有說(shuō)明重復記錄的問(wèn)題。這是因為在這種方案中重復記錄不是問(wèn)題。事實(shí)上,讀寫(xiě)程序是完全忽略重復記錄的。
在寫(xiě)數據時(shí),新的記錄會(huì )寫(xiě)在陣列的最后,而不管是否有相同號碼的記錄存在。在讀數據時(shí),只有匹配請求記錄號的最后,也就是最近的記錄被讀出來(lái)。
從陣列中讀出一個(gè)數據單元要比寫(xiě)入稍微復雜一些。讀函數首先接受應被寫(xiě)入數據單元內容的單元號碼和地址。當被調用時(shí),讀函數從頭開(kāi)始搜索陣列。
當它找到與請求數據單元相匹配的記錄時(shí),它將對應的地址先存起來(lái),然后繼續搜索。如果它找到另外一條匹配的記錄,它就用新的地址代替剛才存儲的地址。
當到達陣列結尾時(shí),最終存儲的地址將指向最近寫(xiě)入拷貝的請求記錄。讀函數隨即在被調用時(shí)將這個(gè)數據拷貝到緩存。
復用存儲器空間
現在,我們已經(jīng)有了一種以讀取為主的可行機制用于從存儲陣列中存取記錄。剩下只有一個(gè)問(wèn)題:我們還沒(méi)有建立起復用被廢棄的記錄拷貝占用的空間。(我們也還沒(méi)有建立刪除記錄的機制,但由于是用在嵌入式應用中,這可能不是一個(gè)很重要的特性)
如果不恢復空間,分配的空間將很快用完?;謴涂臻g意味著(zhù)擦除整個(gè)頁(yè),因為閃存只能一次擦除一整頁(yè)。但閃存頁(yè)被隨意擦除時(shí)將會(huì )出現刪除有用信息的風(fēng)險。唯一的方法是在擦除舊頁(yè)時(shí)將有效信息拷貝到新的頁(yè)。
從廢棄記錄恢復空間要分三步走:首先,打開(kāi)新的閃存頁(yè),將每個(gè)數據單元的最新版拷貝到新的頁(yè);然后,刪除舊頁(yè);最后,在新頁(yè)上放置頁(yè)標記以便讀程序能找到它們。
評論