本文介紹何謂記憶體中的“損耗均衡”技巧,並探討會影響EEPROM壽命的因素,包含溫度、電壓、靜電等等。同時使用C語言時做一個簡單的演算法讓記憶體可以達到平均磨損,避免特定區塊被寫入太多次導致整個元件失效。{alertInfo}
目錄
前言
EEPROM常被用來作為非揮發性儲存,存放系統斷電後還要維持的資料,像是系統組態設定、使用者參數或者特殊狀態。而且它的應用不只在小型專案上,大型商業器具、工業儀器都有它的身影,如何延長使用壽命與可靠度是一直以來無法忽視的問題。
為何需要wear-leveling
使用非揮發性記憶體的時候都需要指定一個位址,接著給一串資料,然後經過一小段時間記憶體才能真正將資料存放到每一個資料單元裡面。由於非揮發性記憶體的讀寫速度相比於可動態存取的 RAM而言非常慢,所以在使用上再寫入前都需要確認前一次的寫入已經完成,才不會造成寫入衝突。但這種記憶體沒辦法自動分配位址,會造成同一個位址寫入次數達到上限,損壞後造成記憶體可靠度降低。
在簡易的DIY應用中,大部分不會仔細去設計EEPROM的寫入位址,常常固定位址一直擦寫。這在小案子中是可以被接受的,畢竟產品生命週期較短,同時記憶體的讀寫量也沒有非常巨大。但每個記憶體都有其固定的使用壽命,在工業應用、或者高頻率讀寫的應用中,長時間讀寫同一個位址很容易造成記憶體單元(Cell)損壞。這就有點像一張白紙,我固定拿鉛筆寫同一個地方,然後又用橡皮擦掉,又寫,又擦,這樣反覆很多次紙張就擦破了。
當記憶體有一個位址失效後,會間接影響到EEPROM裡整排的儲存單元,有可能是一整頁的記憶體,或者隨機分佈的位址,整顆EEPROM逐漸不穩定。目前市面上EEPROM讀寫次數都有100,000次以上,現在製程進步,STMicro生產的M95640就宣稱可讀寫次數有4,000,000次。
為了讓紙張不破洞,其中一種方法就是平均在紙張的各個區域做記號。記憶體也是一樣,我們把讀寫的地方平均分配,讓記憶體的每一個位置被平均磨損,降低記憶單元失效的機會來延長記憶體壽命。
Waer-leveling種類
常見的損耗平均方法有三種,第一種是動態損耗平衡(Dynamic wear levelig),這種方法保留靜態區域,只針對特定空間進行損耗平衡。它們的比例可能是80%/20%或者75%/25%。這種方式不需要重新映射所有的記憶體位址,保留速度的彈性。
第二種是靜態損耗均衡(Static wear leveling)則是將整快記憶體所有位址做重新映射,讓全部的記憶體單元能被平均擦寫,讓記憶體壽命最大化,但缺點是每次虛擬記憶體位址與實體記憶體位址都要重新映射,避免特定單元寫入太多次,這會造成系統速度變慢。但在這次的應用中我們講求的是記憶體壽命,同時EEPROM本身速度就很慢所以根本沒差。會考量到速度的只有在RAM的應用中。
Wear-leveling概念實作
為了讓系統在重新上電後還能讀到舊資料,我們需要一個區塊來儲存上次斷電的寫入位址(我們暫命名為Addr_prev),EEPROM總空間為64kbit(8Kbyte),每個分頁是32byte。假設每次系統斷電都有8byte的數據要紀錄,不包含Addr_prev,這樣全部記憶體可以寫入的資料數量有1024次。
現在加入Addr_prev這個變數,我們讓它用一個bit從1變0來表示目前的位址指標。若這個變數要儲存1024個不同位址,則需要1024bit的空間來存這個資訊,換算一下就是128byte。其概念如下圖所示:
實際上總共能計數的次數還要扣除Addr_prev本身的大小,因此能用的空間剩下8Kbyte-128byte=8064byte,需要的Addr_prev也縮小一點變成1008bit,但這影響太小了,為了實作簡單就先不迭代計算。
定義好Addr_prev與儲存空間的關係後,就可以實作靜態損耗均衡:
// Include the EEPROM read/write function
#include "EEPROM.h"
// Assume Addr_prev is storage at address 0x0001
#define ADDR_PREV_ADD 0x0001
// Declare the previous storage address
uint16_t EEPROM_Addr = 0;
// Declare bitwaise counter
uint16_t Nbit = 0;
// Read previous storage address
Addr_prev = EEPROM_read_2byte(ADDR_PREV_ADD);
// Now we got previous storage address, assume is 0xFFE0
// mapping to physical assress
// Check address bit
for(Nbit = 0; Nbit < 1024; Nbit++){
// Right shift the address, check which bit is set to 1
if(Addr_prev >> Nbit && 0x01)
break;
}
//Calculate physical storage address
EEPROM_Addr = 8 * Nbit; // Assume we write 8byte data once
// Update Addr_prev variable to 0x0001 for next power cycle
// This is where wear leveling happened
Addr_prev &= Addr_prev << 1;
// Store Addr+prev into EEPROM
EEMROM_write(ADDR_PREV_ADD, Addr_prev); //(address, data)
...
// Use the new address to storage data
EEPROM_write(EEPROM_Addr, data); //(address, data)
以上是簡易的靜態損耗均衡演算法,但市面上還有很多依據不同條件的演算法被應用在記憶體上,有興趣的讀者可以自己搜尋。而記憶體除了天生的讀寫壽命之外,還有很多因素會影響記憶體的使用時間,讓我們繼續探討。
影響記憶體壽命的因素
除了讀寫次數之外,影響記憶體壽命的還有工作電壓、工作溫度、儲存溫度以及靜電的影響。
設計微控制器電源的時候常會忽略濾波電容的數值,放不夠大,或者輸入電壓劇烈變化導致轉換器響應不夠快,Vdd過衝產生Spike等等超出EEPROM的容許範圍的情況都有可能導致記憶體損毀。而解決這些因素的方式就是使用更穩定的電源供應、檢查PCB線路的走線是否被電路其它雜訊干擾、或者使用更大的濾波電容來維持記憶體所需。此外還有一項是EEPROM寫入時斷電的狀況。許多應用場合會在系統斷電時,利用內部大電容維持微處理機與EEPROM的工作電壓,這一小段時間將系統最後的狀態儲存起來。但這麼做的風險是當電容老化後,電容容值降低導致維持時間不足。若記憶體寫到一半被強制斷電,還是有可能造成資料遺失的問題。
溫度方面,高溫環境下操作記憶體,規格外的故障是必然的,但儲存溫度也一樣重要。記憶體在超過儲存溫度下放置,會讓記憶體單元漏電流變大,資料容易流失,這樣就喪失使用EEPROM的目的。靜電則需要注意IC各個腳位是否有增加額外的EDS元件保護記憶體,避免記憶體受到突波擊穿記憶單元造成資料遺失。
結論
以上就是會造成EEPROM壽命減少的因素,以及為何使用wear-leveling可以延長壽命的原因。並且這次的文章說明如何使用C語言實作wear-leveling的技巧,並透過簡易的 bit waise來映射記憶體位址與實體位址。除了本文的方法,讀者也可以自己設計一套新的損耗平衡演算法,更可針對不同應用與記憶體特性來調整。
參考資料
EEPROM Wear Leveling - Embedded GurusEEPROM Reliability and Wear Leveling
AVR101: High Endurance EEPROM Storage
延伸閱讀
Microchip Serial EEPROM Endurance這篇Microchip提供的手冊說明EEPROM的失效定義,以及EEPROM的基本構造原理。想進一步瞭解EEPROM的讀者可以閱讀這份文件更加深對記憶體的了解。
張貼留言
留個言吧