《APM32芯得》系列內容為用戶使用APM32系列產品的經驗總結,均轉載自21ic論壇極海半導體專區,全文未作任何修改,未經原文作者授權禁止轉載。
1. Flash與EEPROM簡介
1.1 Flash簡介
Flash,又叫閃存。根據存儲單元電路的不同,分為NAND Flash和NOR Flash兩種。Nor Flash由于地址線和數據線是分開的,可以按字節讀寫數據。這種特性可以用來存儲和運行代碼,MCU內部的Flash就是一種NOR Flash。
但是無論是哪種Flash,他們寫之前必須先進行擦除操作(因為只能將數據由1寫為0)。
1.2 EEPROM簡介
EEPROM,Electrically Erasable Programmable Read Only Memory,即電可擦除可編程只讀存儲器,也是一種非易失性存儲區。EEPROM也是可以按字節讀寫數據的,但是寫入之前不需要先擦除數據。
1.3 Flash與EEPROM對比
Flash 與 EEPROM都屬于非易失性存儲器,他們都可以掉電保存數據。但他們也有很多的區別,下表列出了Flash與EEPROM的主要區別:
注:這里對比的Flash是MCU內部的Flash
其實,在Linux的設備驅動歸類中,Flash其實是歸類到塊設備的,因為它的最小操作單元是扇區/塊,而EEPROM則是一種字符設備,最小操作單元是字節。
1.4 Flash模擬EEPROM的優勢
節約成本,可減少EEPROM芯片的使用
讀寫速率快,MCU內部的Flash讀寫速率要遠遠高于EEPROM
抗干擾能力強,MCU內部的Flash沒有使用I2C、SPI這類通訊總線,不存在這類總線被干擾的問題。
2. Flash模擬EEPROM原理
在前面的對比,我們可以了解到,Flash與EEPROM最大的區別就是:
Flash寫之前需要擦除
Flash與EEPROM一次操作的數據大小不同。雖然MCU內部的Flash和EEPROM一樣,可以實現按字節的讀寫,但是在寫入的時候,是必須要先按扇區擦除的,這里也可以說相當于是一次操作的數據大小不同。
那么,我們Flash模擬EEPROM主要是模擬實現什么呢?主要實現的關鍵點有:
無需用戶擦除即可按字節讀寫(擦除操作封裝在函數內部)
擦除數據時不能改變原來已經存儲的數據(讀改寫策略)
盡量減少Flash擦除次數,延長Flash壽命(擦除之前先判斷是否已經是擦除狀態)
具體如何實現?
讀操作
MCU內部的Flash讀操作很簡單,直接像內存一樣讀即可。例如讀0x08000000地址處的數據:
*(uint32_t *)0x08000000;
把0x08000000強制轉換為一個地址(指針),然后再解引用即可。
寫操作
由于Flash寫之前,都必須先要按照扇區進行擦除,所以會麻煩一點。而且,擦除數據的時候,我們不能把原有的數據都給擦了,所以可以使用讀改寫的策略。
寫數據之前,先在RAM中開辟一個與扇區相同大小的緩沖區。然后把要寫的扇區數據讀到緩存中,然后在緩存中改寫數據。最后再擦除扇區(會進行判斷,如果已經是擦除狀態,則無需再次擦除),再把數據寫到扇區。
3. APM32F4系列Flash模擬EEPROM難點
3.1 APM32F4 Flash存儲器結構
我們先了解下APM32F4的Flash存儲結構:
我們主要看主存儲模塊,一共分為12個扇區,最小的是前面4個扇區16KB,最大的扇區大小是128KB。
前面我們說過,Flash模擬EEPROM的一個關鍵點就是,在寫數據的時候,不能改變Flash原有的數據。而且,解決辦法就是在RAM中開辟一塊和Flash扇區同樣大小的緩沖區。
3.2 難點和解決辦法
難點:
但問題是:APM32F4系列的RAM大小,給用戶使用的最大大小是128KB,和最大的Flash扇區大小是一樣大。我們不可能使用APM32F4后面的Flash扇區,作為模擬EEPROM實現的空間,因為根本沒有那么大的RAM空間作為緩存。
但也不能使用第一塊16KB的扇區大小進行模擬,因為第一個扇區是MCU上電啟動會自動取指令的扇區,如果這個區域存儲的不是合法的指令,那么會造成程序跑飛。
總結起來就是:
Flash扇區太大,導致RAM不足以開辟同樣大小的緩沖區
不能使用第一個扇區,因為那個扇區是MCU啟動固定使用的
如何解決:
提供上面分析,能留給我們進行Flash模擬EEPROM所使用的扇區就只有 1~3 這3個扇區符合要求。那么我們如何使用Flash中間的扇區進行實驗呢?
我們可以定義一個const數組,然后使用編譯器屬性指定該數組在Flash的起始地址(比如我們指定起始地址就位于第1塊扇區的首地址),大小是用戶定義的Flash模擬EEPROM的大小。但是必須要必須要是扇區大小的整數倍。
代碼如下:
/* Specifies the start address of the sector. The purpose is to occupy a space at the specified address of MCU flash. */
static const uint8_t Flash_Para_Area[FLASH_EE_TOTAL_SIZE] __attribute__((section(".ARM.__at_0x08004000")));
/* The buffer that write or erase sector data */
static uint8_t Flash_EE_Ram_Buffer[FLASH_SECTOR_SIZE];
這個const的數組,其實在代碼中并沒有任何作用,它的目的就是占據這塊Flash空間,而不讓編譯器鏈接時,把代碼鏈接到這塊區域,因為這塊區域是要用于用戶存儲數據的,在這個過程中可能會被擦除。
3.3 APM32F4 Flash的存儲區域規劃
進過前面的分析和規劃,最終APM32F4 Flash的存儲區域劃分,如下圖:
第1~3這3個扇區可以劃分,作為Flash模擬EEPROM的區域,其他的扇區都是用于存放代碼的區域。
4. APM32F4系列Flash模擬EEPROM代碼介紹
可以先到Geehy官網,下載F4系列的SDK,然后隨便復制其中一個例程,在該例程編寫Flash模擬EEPROM的代碼實現。
4.1 相關宏定義
/* flash sector satrt address */
#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* 16 Kbytes */
#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* 16 Kbytes */
#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) /* 16 Kbytes */
/* flash sector size */
#define FLASH_SECTOR_SIZE ((uint32_t)(1024 * 16))
/* flash emulation eeprom total size. This value must be a multiple of 16KB */
#define FLASH_EE_TOTAL_SIZE ((uint32_t)(1024 * 16 * 2))
/* flash emulation eeprom sector start address, it's must be sector aligned */
#define FLASH_EE_START_ADDR ADDR_FLASH_SECTOR_1
/* flash emulation eeprom sector start address */
#define FLASH_EE_END_ADDR (ADDR_FLASH_SECTOR_1 + FLASH_EE_TOTAL_SIZE)
FLASH_SECTOT_SIZE:定義的Flash的扇區大小。不同系列的MCU,扇區大小不一樣。
FLASH_EE_TOTAL_SIZE:Flash模擬EEPROM的Flash總大小,該大小必須是扇區大小的整數倍。在F4上最多也只有3*16KB總大小。
FLASH_EE_START_ADDR:Flash模擬EEPROM的Flash起始地址,起始地址是必須要扇區對齊的。即只能是扇區的起始地址。
4.2 讀寫接口函數
我們在使用過程中,只需要使用讀數據、寫數據接口函數即可。
/*
* readAddr: 讀數據起始地址
* pData: 指針,指向保存讀出的數據的緩沖區
* len: 讀取數據的長度
*/
void Flash_EE_Read(uint32_t readAddr, uint8_t* pData, uint32_t len);
/*
* readAddr: 寫數據起始地址
* pData: 指針,指向需要寫入數據的緩沖區
* len: 寫入數據的長度
*/
void Flash_EE_Write(uint32_t writeAddr, uint8_t* pData, uint32_t len);
5. 另一種Flash模擬EEPROM方案介紹
前面介紹的,是Flash模擬EEPROM的其中一種方案。特點是直接對Flash進行操作,但也是實現了對Flash按字節的讀寫操作,而且不會改變Flash原有的存儲數據,而且還可以跨扇區進行讀寫數據。
另外,還有另一種Flash模擬EEPROM的實現方案。
5.1 數據存儲格式
該方案需要使用至少兩塊相同的扇區/頁,使用至少兩個相同大小的扇區/頁,其中一個扇區處于有效狀態,而另一個扇區處于擦除狀態。然后每4個字節分為:2字節data + 2字節virtual address 的存儲格式。具體數據存儲格式如下:
其中:
每個頁的第一個存儲區,保存當前的頁狀態。
flash address:就是MCU flash的實際地址,在代碼中并沒有使用到,只用到頁起始和結束地址。
data:用戶存儲的數據。
virtual address:對應數據的虛擬地址,在讀數據時,我們需要根據這個虛擬地址進行尋址。
存儲變量的個數:扇區大小 / 4 - 1。比如 2KB / 4 – 1 = 511,即最多可以存儲511個變量。
5.2 扇區/頁狀態
每個扇區/頁都有三種狀態:
有效狀態:該頁包含所有的有效數據,讀寫數據在該頁進行
擦除狀態:就是一個空的頁
數據傳輸狀態:當一個頁寫滿時,把已經寫滿的頁的有效數據復制到本頁的狀態
5.3 數據更新過程
該方案有數據讀、寫、轉移三種過程:
寫數據:從頁起始地址開始尋址,找到第一個已經被擦除的區域(比如前面的數據存儲格式的圖片,flash address = 24的位置),然后把數據和對應的虛擬地址一起寫入。當第二次改寫同一虛擬地址處的值時,會在Flash新的位置,存儲該虛擬地址的值。比如比如前面圖片的flash address = 20的地址處,存儲的虛擬地址是0x7777,是第二次出現的虛擬地址,修改數據就是會這樣在新的位置存儲新的值。其中最后一次存儲的數據,才是有效數據。
讀數據:從頁結束地址開始尋址,找到對應地址最后一次改變的數據(其實就是有效數據)。比如前面的數據存儲格式的圖片,有兩個0x7777地址對應的數據,只會返回最后一次改變的數據。
數據轉移:當頁0寫滿時,會把該頁的有效數據全部復制到另外一個空頁(頁1)。然后再擦除頁0,把頁1標記為有效狀態,再頁1繼續寫數據。
6. 后續補充
目前,我只實現了Flash模擬EEPROM第一種方法的代碼。這里留個坑,我后續會實現APM32F4系列的第二種Flash模擬EEPROM的代碼。
如果還有時間的話,把APM32F1系列的MCU,也一起實現了Flash模擬EEPROM的代碼吧。
反正暫且先留個坑吧。
-
EEPROM
+關注
關注
9文章
1022瀏覽量
81684 -
數據線
+關注
關注
8文章
283瀏覽量
37754 -
代碼
+關注
關注
30文章
4799瀏覽量
68728
原文標題:APM32芯得 EP.26 | APM32F4 Flash模擬EEPROM介紹和代碼實現
文章出處:【微信號:geehysemi,微信公眾號:Geehy極海半導體】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論