24系列EEPROM/FRAM通用介面
1.寫在前面
“24系列”的EEPROM,一般地我們認為是以i2c為通訊介面的一系列序列EEPROM,各大半導體廠商出產的該系列EEPROM都遵循這個規則,而且電路和控制程式上也相容。如AT24C02、ST24C02等。
FRAM(鐵電儲存器)是近幾年來比較熱門的一項儲存技術,並且有相關實際產品的應用。FRAM具有ROM和RAM的特點,擦寫壽命長、讀寫速度快、讀寫功耗極低。24系列的FRAM在電路和程式設計師相容24系列的EEPROM,但由於FRAM寫速度遠高於EEPROM,因此不再需要傳統EEPROM“頁寫”之間的延時或者匯流排空閒檢查的操作,這也是兩者程式的主要差別。當然存在延時也可以,並不影響資料的正確性,只是降低寫效率。
除此之外,還有“25系列”的EEPROM,該系列則是以spi序列控制介面,在讀寫時序上稍有差別,具體頁寫演算法可以和24系列的一致。相應地,也有25系列的FRAM,這塊用得少,具體差別還有待驗證。說個題外話,個人覺得spi介面的EEPROM並無太大優勢,甚至有點浪費資源。雖然spi傳輸速度可以高於i2c,但EEPROM的寫速度實在太低了,像i2c這樣的低速匯流排仍需“等待”,所以使用spi並無優勢,還佔用多個IO口。但,spi介面的FRAM就有優勢了,FRAM讀寫速度遠高於EEPROM,儲存資料量較大時,可以優先考慮spi介面的FRAM。
2.介面抽象
2.1 目的
統一介面,遮蔽底層差異,方便移植。使用時只需設定好具體EEPROM型號、從地址、頁寫延時函式、防寫函式等即可驅動起來,讓使用者將更多時間花在業務功能上。
2.2 使用範圍
1)MCU裸機程式上。
2)RTOS(實時系統)上。
3)其他。
2.3 實現功能
1)根據型號自動識別頁大小、片容量大小。
2)帶頁寫演算法,自動翻頁,自動識別非整齊頁。
3)相容EEPROM和FRAM。
2.4 API
2.4.1 裝置物件
在介紹API前,有個關鍵的結構體“_24cxx_dev_t”,在“_24cxx_dev.h”中,每個EEPROM外設必須對應一個該結構體,一般地我們參考Linux的叫法稱為“裝置物件”或者“檔案控制代碼”。該結構體需要程式設計師初始化,指定相關引數或者函式指標例項化。後面的讀、寫、擦除函式介面的第一個引數必須都是傳入該物件地址(指標),如果物件為空或者未初始化,則返回錯誤。
/*24cxx eeprom devcie struct*/ typedef struct { struct i2c_dev_device *i2c_dev; /*i2c bus device struct*/ uint8_t slave_addr; /*eeprom i2c addr*/ _24_model_t model; /*eeprom model*/ void(*wp)(uint8_t ctrl); /*protect of write function*/ void(*page_write_delay)(void); /*there is a delay in continuous writin for EEPROM,FRAM not need*/ }_24cxx_dev_t;
1)引數一“i2c_dev”,為控制EEPROM的i2c匯流排裝置,可參考“i2c抽象/模擬i2c”文章,使用的是模擬i2c ,也可以根據定義使用硬體i2c;
2)引數二“slave_addr”,為EEPROM的器件從地址,7bit地址,不包括讀寫位;
3)引數三“model”,為具體EEPROM的型號,該型別為自定義的列舉型,枚舉了24c01—24c1024的型號的EEPROM/FRAM;
4)引數四“wp”,為防寫函式,如果EEPROM的防寫引腳“WP”通過MCU控制,則需實現該函式;實現“WP”引腳IO翻轉即可;
5)引數五“page_write_delay”,為頁寫延時函式,程式中採用了頁寫演算法,EEPROM如果連續頁寫,則需要實現該函式, 否則寫會出錯;FRAM則不需要。
2.4.2 讀EEPROM
int16_t _24cxx_read(_24cxx_dev_t *pdev,uint32_t addr, uint8_t *pbuf, uint32_t size);
引數 | 功能描述 |
---|---|
pdev | EEPROM/FRAM裝置物件 |
addr | 起始地址 |
pbuf | 讀取的資料(快取) |
size | 讀取資料大小(位元組) |
_24cxx_write(_24cxx_dev_t *pdev,uint32_t addr,uint8_t *pbuf,uint32_t size);
引數 | 功能描述 |
---|---|
pdev | EEPROM/FRAM裝置物件 |
addr | 起始地址 |
pbuf | 待寫的資料 |
size | 待寫資料大小(位元組) |
原則上EEPROM並不存在“擦除”操作,“擦除”一般指用於flash寫入前的操作。但特殊場合下,需賦予EEPROM預設值,如賦值0或者0xff,此時可以使用擦除操作。為了節約記憶體,該函式內部使用的是單位元組擦除,效率不高,如有需擦除大片空間,建議直接呼叫寫函式進行擦除。
int16_t _24cxx_erase(_24cxx_dev_t *pdev,uint32_t addr,uint8_t data, uint32_t size);
引數 | 功能描述 |
---|---|
pdev | EEPROM/FRAM裝置物件 |
addr | 起始地址 |
data | 擦除為預設值 |
size | 待擦除空間大小(位元組) |
呼叫函式時,都會返回一個狀態碼,無錯誤返回0。具體狀態碼可以檢視“_24cxx_dev.h”中的定義。
/*operation state*/
enum _24CXX_ERROR
{
_24CXX_OK = 0,
_24CXX_ERR_I2C_WR = 1,
_24CXX_ERR_DEV_NONE = 2,
_24CXX_ERR_PAGE_WRITE = 3,
_24CXX_ERR_PAGE_SIZE = 4,
_24CXX_ERR_CHIP_SIZE = 5,
};
3.使用例子
目前測試並且通過的EEPROM/FRAM型號有AT24C02、AT24C16、FM24C16。其他型號暫未測試過,如廣大網友測試發現問題歡迎指出。
3.1 EEPROM系列
在測試工程下的“drivers”目錄下,原始碼檔案是“at24cxx.c”,主要初始化實現一個“_24cxx_dev_t”裝置物件。
static void page_write_delay(void)
{
uint16_t i;
i = 0xFFFF;
while(i--);
}
/**
* @brief device init
*/
const _24cxx_dev_t at24cxx_dev =
{
&i2c1_dev, /*i2c device*/
0x50, /*eeprom address*/
_24C16_E, /*eeprom model,eg AT24C16*/
0, /*no write protect*/
page_write_delay, /*delay function,must!*/
};
1)“i2c1_dev”為i2c匯流排裝置物件,在“i2c抽象/模擬i2c”文章提及,不再贅述;
2)0x50為器件從地址,不包括讀寫位;
3)器件具體型號;
4)防寫函式,這裡無,賦值NULL(0);
5)頁寫延時函式。
這一步完成,即可通過上述的API介面讀、寫EEPROM,具體demo檢視工程原始碼。
3.1.1 防寫函式
常見的使用方式都是直接將EEPROM的WP引腳拉低,沒有保護功能。如果WP引腳通過MCU控制,則需要使用上防寫函式。以為STM32為例,假設PA0控制器件的WP引腳,防寫函式實現如下,IO口時鐘、方式、狀態等暫存器需在初始化時配置。在初始化裝置物件時,賦值到防寫函式指標。
static void wp_fun(uint8_t ctrl)
{
if(ctrl == 0)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
}
else
{
GPIO_SetBits(GPIOA,GPIO_Pin_0);
}
}
3.2 FRAM系列
FRAM控制介面相容傳統EEPROM,程式上差異不大,主要是頁寫函式可以去掉,設定為NULL(0)即可。以FM24CL16為例,實現如下。
/**
* @brief device init
*/
const _24cxx_dev_t fm24clxx_dev =
{
&i2c1_dev, /*i2c device*/
0x50, /*fram address*/
_24C16_E, /*eeprom model,eg FM24C16*/
0, /*no write protect*/
0, /*delay fun,FRAM no need*/
};
4.相關文章
[1] i2c抽象/模擬i2c:
https://blog.csdn.net/qq_20553613/article/details/78878211
[2] EEPROM頁寫演算法:
https://blog.csdn.net/qq_20553613/article/details/78550427
5.原始碼