24LC16 介紹及EEPROM使用技巧

1.關於EEPROM

EEPROM是現在很常用的一種資料儲存裝置,關於EEPROM的介紹可以參考維基百科

電子抹除式可複寫唯讀記憶體

什麼時候會用到EEPROM?在MCU工作的時候如果有需要儲存參數、數據的時候就會使用到EEPROM,除了EEPROM外也有其他的儲存裝置,例如FLASH、FRAM等常見的裝置。

2.關於24LC16

24LC16是一提供16Kbit儲存容量的EEPROM裝置,使用I2C通訊介面做存取,支援高速400KHz I2C通訊。

24LC16提供的erase/write是現在常見典型的100萬次。

具有外部資料保護控制腳(WP),WP腳為Hi時,則EEPROM資料唯讀,WP腳為Low時,可進行寫入操作。

2.1記憶區塊的配置

24LC16內的16Kbit儲存位置分配於8個不同的區塊(Block)當中,也就是每個區塊(Block)大小為256byte,而每個address大小為1byte,所以24LC16總共有2Kbyte的儲存空間。

256byte×8Block = 2048byte = 16384bit

2.2Device Addressing

Spec中有詳述關於使用I2C時Address的定義,如下圖

24lc16-1

Control Code(bit7~bit4):為固定位元

Block Select Bits(bit3~bit1):為8個Block的選擇位元也就是從0~7共8Block

Read/Write Bits:則是讀取/寫入的操作控制bit

2.3資料儲存位置

在使用I2C操作讀取或寫入時,均要遵照Spec中所提的資料格式,如下圖

24lc16-2

然而剛開始使用的時候,很容易會將Word Address誤會為是1Wrod的長度而寫入2byte的資料位址,實際上在24LC16中,每個Block的資料位址都是由0x00~0xFF也就是0~255而已,所以此處的Word Address的長度也只有1byte。

2.4Page Write

24LC16的Page Write長度為16byte,也就是說,每次最多可寫入16byte長度的資料,而寫入的起始地址也不能為任意值,必須由位址0開始每16byte作為一個page來看待,也就是說,每次寫入的起始位址,都必須為16的倍數。

24lc16-3

 

2.5Write cycle time

EEPROM的寫入均須要有處理時間,每個EEPROM的處理時間都不一樣,而在Spec中都會有提到(如下圖)

24lc16-4

 

以24LC16為例不管是Byte Write或Page Write都最大的等待時間都需要5ms,假使在連續寫入的時候沒有遵循這個時間,可能會造成寫入失敗,另外有時候雖Spec標稱最大5ms,而實際測試時可能只需要2ms就可完成寫入,但建議還是遵照Spec滿足這5ms的等待時間,因EEPROM可能會隨批製造過程的些許差異,而等待時間可能也會有不同的變化,故可能這次使用的24LC16可以僅需等待2ms但不保證下批的24LC16也僅需要2ms就可完成。

3.EEPROM的使用技巧

在使用EEPROM做資料存取的時候,通常我會在意兩個問題

3.1如何預估寫入的次數壽命

因EEPROM均有寫入跟抹除的壽命限制,典型常見的次數為100萬次,而這100萬次指的是每個位址的生命次數,也就是說2048byte每個位址均有100萬次的寫入保證,假使我們今天對固定的位置,每秒做一次寫入的動作,而這個時間就相當好計算,

1000000(寫入次數)×1(秒/寫入) = 1000000(秒)/86400(秒/天) ≒ 11.6(天)

也就代表說,這個位址如果一秒寫入一次的情況下這個位址在連續寫入11.6天之後就會往生了。

延長EEPROM寫入次數上的做法有很多,例如

a.增長寫入的時間隔,如十秒寫一次等

b.紀錄每個位址寫入的次數做保護機制

c.使用擴展的方式,每次將資料寫入不同的位址

類似這樣的做法很多,每個人都可以有自己的想法跟做法,並沒有說怎樣的作法才是正確的,考慮任何作法之前,我們必須先理解我們的需求,例如:

a.資料儲存的時間要求,如最慢一秒儲存一次或最慢30秒儲存一次等

b.總資料儲存的長度,如全部必須儲存的資料長度為10bye或N byte之類

這兩個參數條件,會直接影響到的EEPROM寫入程式的設計要求。

 3.2如何確保資料的正確性

畢竟24LC16對於MCU來說也是屬於外部的儲存裝置,只要有通訊,難免就會遇到干擾,遇到干擾就難免害怕資料會有出錯的機會,有時是在通訊過程中出現的錯誤,使的寫入的資料錯誤,有時因為其他環境因素,都有可能造成資料異常,故再將EEPROM寫入後,如何確保資料正確性也就變得相當重要。

常見的做法不外乎如下

a.將寫入的資料讀出重複確認。

b.將寫入的資料帶入檢查碼的機制如checksum等。

c.將資料寫入不同的address block中做交叉比對。

做法很多,與先前提到的一樣,沒有說怎麼樣做才是正確的,考慮任何作法之前,我們還是必須先理解我們的需求,例如:

資料出錯的可能性影響有多大?如何將資料出錯的影響降至最低?資料量很大且儲存的頻率很高時計算checksum時是否會影響整體效能?另外將資料儲存之後,為了就是讓開機時可以將資料載回,要如何使用對於自己最有利的方法載回又能同時確保資料正確性就變得很重要。

3.3我喜歡的做法

這邊要分享一個我喜歡的儲存作法,當然就以24LC16為例做設計。

假設我的總資料儲存量約200byte,而MCU每天工作時間8小時,每次儲存資料的時間格為10秒來看

我採用的是使用輪循的儲存方式,以Block為單位,每次寫入的時候在最後擺上write count與checksum作為檢查使用,但是程式在寫入的時候,我就不再重新讀出確認檢查,具體的流程與做法如下:

Drawing1 (1)

此做法有幾個特性:

a.可有效的延長寫入的壽命

1000000(寫入次數)×10(秒/寫入) = 10000000(秒)/86400(秒/天) ≒ 116(天) × 8Block = 928天(2.5年)

如果以8小時為計算則

1000000(寫入次數)×10(秒/寫入) = 10000000(秒)/28800(秒/8hr) ≒ 347(天) × 8Block = 2776天(7.6年)

b.寫入時資料異常時

假設,某個N時間點,因某種原因造成資料寫入錯誤,即便有錯誤的資料寫入,開機時也不會載入到錯誤的資料,此可透過檢查checksum得到防護,而該時間的資料遺失,可能會造成10秒前的資料回朔,但假使在第N+1的時間點後資料進行儲存於下一個block中,只要不發生異常,則前一次的異常就可忽略。

這種輪循的儲存方式,比較適合儲存最新資料的架構,也就是說,程式不須要記錄歷史值,而只要記錄最新值的情況下,使用輪循的方式儲存我認為相當好用,也很容易理解與撰寫。

c.當Block內有損壞時

假設某個一Block中有部分地址損壞造成無法寫入,則在儲存過程中就會有lost近10秒的資料,假設,當Block是連續有損壞時,例如第5與第6個Block均有損壞,則就會有機會lost 10秒×2(block)的資料。

如果可以加入Block檢查機制的話,就可以避免該問題的產生。不過一旦出現Block損壞時,則代表該EEPROM應已使用一段時間,或者為原料不良。

d.可掌握EEPROM的寫入次數

透過writeCount選擇儲存Block順序外,也可以作為監視EEPROM寫入次數的Count。

e.載回資料容易

在要載回EEPROM內部儲存資料時,只要依序讀取各Block資料並重新計算checksum後尋找最大值的writeCount該Block即為最後儲存的資料區塊。

24lc16-5

4.補充資料

a.EEPROM說明 (Wikipedia)

b.24LC16 英文Spec

 

發表迴響