先看Flash操作的簡(jiǎn)單流程
1、確定要寫(xiě)入Flash的首地址(稍后介紹確定地址的方法)
2、解鎖Flash
3、對(duì)Flash進(jìn)行操作(寫(xiě)入數(shù)據(jù))
4、對(duì)Flash重新上鎖
但是在實(shí)際項(xiàng)目中,直接操作FLASH地址的話(huà),會(huì)導(dǎo)致單片機(jī)flash壽命大大降低,具體用啥方法呢,在官方給的優(yōu)化文檔中,采用虛擬地址的方法來(lái)讀寫(xiě)存儲(chǔ)數(shù)據(jù)。
一、falsh模擬eeprom,如何移植到自己的工程中,非常詳細(xì)的,然后我們?cè)诜治鎏摂M地址,下面是具體操作流程
1、在ST 的網(wǎng)站上下載 AN2594 及例程。
2、在例程中src目錄中找到eeprom.c 及inc目錄中找到eeprom.h拷貝到自己的工程目錄中。
3.、在工程中添加這個(gè)eeprom.c
4、在工程中的外設(shè)庫(kù)里添加 stm32f10x_flash.c
5、在eeprom.c 文件中包含 #include "stm32f10x_flash.h"
6、main.c中包含include "eeprom.h"
7、添加數(shù)據(jù),在 AN2594中,存入到FLASH的數(shù)據(jù)是以16位的方式存的。每個(gè)數(shù)據(jù)包含數(shù)據(jù)本身,還需要存16位的虛擬地址。所以在main.c中需要定義虛地址。:
/* Virtual address defined by the user: 0xFFFF value is prohibited */
uint16_t VirtAddVarTab[NumbOfVar] = {0x5555, 0x6666, 0x7777};
需要多少個(gè)16位的數(shù)據(jù),將定義在 eeprom.h 中的將NumbOfVar修改成需要的個(gè)數(shù)。虛地址需要是16位,非0xFFFF,互不重復(fù)就可以。
定義數(shù)據(jù),如果實(shí)際的數(shù)據(jù)不是16位的,可以定義一個(gè)聯(lián)合來(lái)解決。
union {
uint16_t SeatStorage[NumbOfVar+1];
uint8_t SeatByte[NumbOfVar * 2+2];
}Seat;
8、使用時(shí),先初始化
EE_Init();
讀出數(shù)據(jù)
if((0 == EE_ReadVariable(VirtAddVarTab[0], &Seat.SeatStorage[0])) &&
(0 == EE_ReadVariable(VirtAddVarTab[1], &Seat.SeatStorage[1])) &&
(0 == EE_ReadVariable(VirtAddVarTab[2], &Seat.SeatStorage[2])))
// 可以用EE_ReadVariable的返回值是否為0判斷FLASH中存儲(chǔ)的數(shù)據(jù)是否有效。
就是把虛擬地址的數(shù)據(jù)讀出到數(shù)組SeatStorage中。
二、虛擬地址的具體原理分析
這是STM32模擬EEPROM的使用和優(yōu)化文檔的部分截圖
如圖中所示,你就明白什么是虛擬地址。
對(duì)于EPPROM,讀取數(shù)據(jù)是通過(guò)I2C的,傳入的是Addr,讀出的是數(shù)據(jù)。這里地址就是物理地址。
對(duì)于FLASH模擬EPPROM,我們假設(shè)FLASH里面的一塊區(qū)域0x10000000-0x10001000這4K空間用來(lái)模擬,其中數(shù)據(jù)結(jié)構(gòu)都是
typedef Struct
{
UINT16 data;
UINT16 Address;
}STRUCT_EPPROM;
若在0x10000000處的數(shù)據(jù)為{0x0001, 0x5555}這里面0x10000000就是物理地址,結(jié)合一些邏輯和接口,就可以通過(guò)0x5555(結(jié)構(gòu)體中的Address)這個(gè)地址找到數(shù)/數(shù)組,也就是被稱(chēng)為虛擬地址的原因data就是內(nèi)部存儲(chǔ)的數(shù)據(jù)。
意思就是如果變量是 16 位,則每個(gè)變量都占用 32 位( 16 位數(shù)據(jù)加 16 位虛擬地址),這意味著每次寫(xiě)入新數(shù)據(jù)時(shí),各個(gè)變量分別使用 4 字節(jié)的 Flash 。也就是每個(gè)變量實(shí)際占用四個(gè)物理地址,每個(gè) 1 KB 頁(yè)在變滿(mǎn)之前可執(zhí)行 256 次 變量寫(xiě)入。
#define EEPROM_START_ADDRESS ((uint32_t)0x0800F000) /* EEPROM emulation start address:
after 4KByte of used Flash memory */
結(jié)束地址就是0x0800FFFF,就是4k的空間
舉個(gè)實(shí)例
在EEPROM.H中修改
/* Variables' number */
#define NumbOfVar ((uint8_t)0x03) 定義要寫(xiě)的 halfword 數(shù)量。
用的時(shí)候需要定義一個(gè)數(shù)組
/* Virtual address defined by the user: 0xFFFF value is prohibited */
uint16_t VirtAddVarTab[NumbOfVar];
需要初始化
1.虛擬地址寫(xiě)數(shù)據(jù)
uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data); //寫(xiě)VirtAddress 取VirtAddVarTab中內(nèi)容,相當(dāng)于編號(hào)為0至NumbOfVar-1個(gè)數(shù)據(jù)寫(xiě)入模擬EEPROM中,寫(xiě)入時(shí)寫(xiě)入數(shù)據(jù)緊跟后面寫(xiě)入虛地址VirtAddVarTab(0<=i<NumbOfVar)
相同地址再次寫(xiě)入時(shí)不會(huì)把上次寫(xiě)的擦掉,而是在模擬EEPROM區(qū)尾部未寫(xiě)過(guò)的地方再次寫(xiě)入數(shù)據(jù)、虛地址,讀的時(shí)候是從尾部開(kāi)始匹配地址,也就是讀取最后一次寫(xiě)的內(nèi)容。模擬EEPROM區(qū)分為2頁(yè),如果一頁(yè)滿(mǎn)了把這一頁(yè)內(nèi)地址不重復(fù)的數(shù)據(jù)復(fù)制到另一頁(yè)后擦除,2頁(yè)交替使用。
2.虛擬地址讀數(shù)據(jù)
uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data); //讀
這個(gè)函數(shù)返回的是虛擬地址所對(duì)應(yīng)的數(shù)據(jù),虛擬地址是作為一個(gè)參數(shù)被傳送的。只有最后更新的被讀取。這個(gè)函數(shù)進(jìn)入的時(shí)候是一個(gè)循環(huán),在這個(gè)循環(huán)內(nèi)讀變量目錄到最后一個(gè)。如果找不到該地址,讀狀態(tài)變量將返回1,否則就重置表明變量已經(jīng)被發(fā)現(xiàn)并且變量值被返回到Data變量。