<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 利用基于閃存的MCU實現(xiàn)用戶數(shù)據(jù)存儲

          利用基于閃存的MCU實現(xiàn)用戶數(shù)據(jù)存儲

          作者: 時間:2008-06-11 來源:Maxim公司 Ben Smith 收藏

            方案1

          本文引用地址:http://www.ex-cimer.com/article/84016.htm

            問題:校準信息、MAC地址或制造數(shù)據(jù)等配置數(shù)據(jù)必須要存儲在產(chǎn)品中。雖然這些通常是固定不變的信息,但在整個產(chǎn)品生命周期內(nèi)配置數(shù)據(jù)需要多次更新的可能性還是存在的。

            解決方案:下面是實際中最容易想到的例子。有兩個塊,一個塊在字地址0x7E00處,另一個在0x7F00處,都用于數(shù)據(jù)存儲。在第一次收到保存配置數(shù)據(jù)的命令時,處理器會檢查這兩個塊,在發(fā)現(xiàn)它們都是空塊后,配置數(shù)據(jù)被就存入第一個塊。

            保存配置數(shù)據(jù)的第二條命令同樣會使處理器再一次檢查這兩個塊。當(dāng)發(fā)現(xiàn)塊0已經(jīng)有數(shù)據(jù)后,它就將配置數(shù)據(jù)拷貝到塊1,然后擦除塊0中的數(shù)據(jù)。

            當(dāng)收到恢復(fù)配置的請求時(比如在上電時),處理器會同時讀取兩個塊的數(shù)據(jù)并確定哪個塊在用。只要是沒被擦除的塊就是在用塊。

            這種方案的主要優(yōu)點是簡單:如果設(shè)備在上電(或其他配置恢復(fù)事件)時需要塊中的配置數(shù)據(jù),這是很好的一種方案。讀數(shù)程序會接受一個字長的指針,返回該地址的數(shù)值,寫入程序則接受一個字長的指針,然后嘗試向該地址進行寫入操作。擦除程序只是同時擦除兩個塊。

            這種方案的主要缺點就是主要優(yōu)點的反面:程序的思路太過簡單。沒有操作去判斷寫入數(shù)據(jù)是否成功—在發(fā)出寫入命令后,如果寫入失敗,處理器不會做任何事去解決問題。這也是為什么這個方案只是用來寫入已知是空的塊的原因。

            方案2

            問題:要求用非易失性存儲技術(shù)來跟蹤用電量和其他經(jīng)常變化的數(shù)據(jù)。更新經(jīng)常是一周數(shù)次或一天數(shù)次發(fā)生。

            解決方案:這是即使傳統(tǒng)也需要尋求幫助的場合。問題是:更新的頻率和所有非易失性存儲器有限的寫入壽命這樣的事實不允許反復(fù)寫入和擦除單個單元??紤]一個小時更新一次的情況,具有1萬次寫入-擦除次數(shù)限制的只需一年時間就會失效,這個時間比電表所需的十年設(shè)計目標少得太多了。

            解決這個問題的方法之一是實現(xiàn)某種形式的“損耗均衡”。這意味著不會有單個位置被反復(fù)寫數(shù)據(jù)。相反,寫入操作將呈類似合理指數(shù)分布的方式分散到整個存儲器陣列。

            損耗均衡是一種很好理解的技術(shù),在器件中使用就是出于這個目的。但它的算法非常復(fù)雜和難以理解,不過對我們來說,一個更簡單的原理介紹就足夠了。

            存儲陣列中的數(shù)據(jù)項是由數(shù)據(jù)單元(data element)號引用的,而不是地址。

            數(shù)據(jù)單元號是一個唯一識別數(shù)據(jù)單元的任意8位數(shù),因此在這種方案中,最多有255個數(shù)據(jù)單元(數(shù)據(jù)單元0是保留單元)。

            每個數(shù)據(jù)單元有一個雙字節(jié)的頭部(見圖2),包含了數(shù)據(jù)單元號和數(shù)據(jù)單元長度以及留給差錯管理使用的足夠空間,其中長度是一個兩位代碼,可表示1個、2個、3個或4個16位的字。

          圖2:數(shù)據(jù)單元的頭部結(jié)構(gòu)

            寫一個數(shù)據(jù)單元需要知道寫入數(shù)據(jù)的地址、寫入數(shù)據(jù)的單元號和長度。寫函數(shù)先尋找陣列結(jié)尾,然后緊跟最后一個記錄之后寫入新的數(shù)據(jù)單元。

            如果頁中沒有足夠的空間容納指定長度的記錄,一個表示結(jié)尾的頁標記將被寫入,并會打開一個新的頁。有關(guān)典型數(shù)據(jù)頁的結(jié)構(gòu)請見圖3。

          圖3:典型的數(shù)據(jù)頁

            在展開的數(shù)據(jù)頁中,先寫入經(jīng)常要更新的數(shù)據(jù)單元1,再寫入從不更新的數(shù)據(jù)單元4,然后寫入需要多次更新的數(shù)據(jù)單元3。最后,寫入從不更新的數(shù)據(jù)單元2。

            出現(xiàn)頁的結(jié)尾標記表明過進行過一次數(shù)據(jù)寫入嘗試,但由于數(shù)據(jù)單元太長而無法將數(shù)據(jù)單元裝進該頁,因此打開了一個新頁來容納該數(shù)據(jù)單元。整個數(shù)據(jù)結(jié)構(gòu)的結(jié)尾設(shè)定為空白單元,這個位置有望成為單元頭部。

            值得注意的是,我還沒有說明重復(fù)記錄的問題。這是因為在這種方案中重復(fù)記錄不是問題。事實上,讀寫程序是完全忽略重復(fù)記錄的。

            在寫數(shù)據(jù)時,新的記錄會寫在陣列的最后,而不管是否有相同號碼的記錄存在。在讀數(shù)據(jù)時,只有匹配請求記錄號的最后,也就是最近的記錄被讀出來。

            從陣列中讀出一個數(shù)據(jù)單元要比寫入稍微復(fù)雜一些。讀函數(shù)首先接受應(yīng)被寫入數(shù)據(jù)單元內(nèi)容的單元號碼和地址。當(dāng)被調(diào)用時,讀函數(shù)從頭開始搜索陣列。

            當(dāng)它找到與請求數(shù)據(jù)單元相匹配的記錄時,它將對應(yīng)的地址先存起來,然后繼續(xù)搜索。如果它找到另外一條匹配的記錄,它就用新的地址代替剛才存儲的地址。

            當(dāng)?shù)竭_陣列結(jié)尾時,最終存儲的地址將指向最近寫入拷貝的請求記錄。讀函數(shù)隨即在被調(diào)用時將這個數(shù)據(jù)拷貝到緩存。

            復(fù)用存儲器空間

            現(xiàn)在,我們已經(jīng)有了一種以讀取為主的可行機制用于從存儲陣列中存取記錄。剩下只有一個問題:我們還沒有建立起復(fù)用被廢棄的記錄拷貝占用的空間。(我們也還沒有建立刪除記錄的機制,但由于是用在嵌入式應(yīng)用中,這可能不是一個很重要的特性)

            如果不恢復(fù)空間,分配的空間將很快用完。恢復(fù)空間意味著擦除整個頁,因為閃存只能一次擦除一整頁。但閃存頁被隨意擦除時將會出現(xiàn)刪除有用信息的風(fēng)險。唯一的方法是在擦除舊頁時將有效信息拷貝到新的頁。

            從廢棄記錄恢復(fù)空間要分三步走:首先,打開新的閃存頁,將每個數(shù)據(jù)單元的最新版拷貝到新的頁;然后,刪除舊頁;最后,在新頁上放置頁標記以便讀程序能找到它們。



          關(guān)鍵詞: 閃存 MCU 微控制器 EEPROM

          評論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();