STM32L系列單片機內部提供了EEPROM存儲區域,但實質上,其FLASH也是EEPROM類型,只不過有一塊區域被開放出來專門用作EEPROM操作而已。STM32L的EEPROM使用壽命設計爲100000次擦寫以上,容量爲2K-4K,這對於一般設備的參數存儲來說是非常理想的。但從EEPROM使用方式看,其不適用於被反覆修改的數據存儲使用,一般作爲配置參數,其修改次數往往是比較少量的。
STM32L的EEPROM和FLASH是統一編址,操作共用同一個讀寫電路,所以在EEPROM讀寫的時候STM32L覈對於FLASH的一切訪問和操作都將暫停,只有當EEPROM的操作完成後,才繼續執行後續代碼,在這期間只有EEPROM的讀寫電路工作,CPU處於掛起狀態。
讀操作,和FLASH以及內存一樣,EEPROM的數據讀取直接用總線讀週期讀出即可,不需要進行額外操作和設置。
- #define EEPROM_BASE_ADDR 0x08080000
- #define EEPROM_BYTE_SIZE 0x0FFF
- /*------------------------------------------------------------
- Func: EEPROM數據按字節讀出
- Note:
- -------------------------------------------------------------*/
- void EEPROM_ReadBytes(uint16 Addr,uint8 *Buffer,uint16 Length)
- {
- uint8 *wAddr;
- wAddr=(uint8 *)(EEPROM_BASE_ADDR+Addr);
- while(Length--){
- *Buffer++=*wAddr++;
- }
- }
- /*------------------------------------------------------------
- Func: EEPROM數據讀出
- Note:
- -------------------------------------------------------------*/
- void EEPROM_ReadWords(uint16 Addr,uint16 *Buffer,uint16 Length)
- {
- uint32 *wAddr;
- wAddr=(uint32 *)(EEPROM_BASE_ADDR+Addr);
- while(Length--){
- *Buffer++=*wAddr++;
- }
- }
EEPROM的編程比讀操作要複雜的多,本質上來說,擦除操作和寫入操作是一樣的,擦除只是在相應的地方寫入0x00000000,但在STM32L的實現上,根據其手冊說明貌似把這種擦除和寫入區分開了,當寫入0x00或0x0000或0x00000000時,自動執行一次擦除操作,在值爲非0時,才執行一次所謂的寫入操作。數據的寫入過程先要對EEPROM進行解鎖,這通過對特殊寄存器寫入特殊序列實現,然後在寫入之前進行擦除操作,其擦除是按字/ 雙字/頁進行的,推薦使用頁擦除方式進行,先把參數讀到內存,並修改,再進行頁擦除,最後將參數寫回,這種方式比較通用,否則很容易出現地址對齊或長度問題。在數據擦除完成之後,即可進行寫入,每寫一字節/半字/雙字,都需要判斷其是否寫入完成,這和內部高壓擦寫電路有關,只有在上次操作完成之後再進行其它操作纔有意義。最後,對EEPROM進行加鎖,以保護數據。
下是手冊給出的解鎖命令碼:
- #define PEKEY1 0x89ABCDEF //FLASH_PEKEYR
- #define PEKEY2 0x02030405 //FLASH_PEKEYR
- /*------------------------------------------------------------
- Func: EEPROM數據按字節寫入
- Note:
- -------------------------------------------------------------*/
- void EEPROM_WriteBytes(uint16 Addr,uint8 *Buffer,uint16 Length)
- {
- uint8 *wAddr;
- wAddr=(uint8 *)(EEPROM_BASE_ADDR+Addr);
- DIS_INT
- FLASH->PEKEYR=PEKEY1; //unlock
- FLASH->PEKEYR=PEKEY2;
- while(FLASH->PECR&FLASH_PECR_PELOCK);
- FLASH->PECR|=FLASH_PECR_FTDW; //not fast write
- while(Length--){
- *wAddr++=*Buffer++;
- while(FLASH->SR&FLASH_SR_BSY);
- }
- FLASH->PECR|=FLASH_PECR_PELOCK;
- EN_INT
- }
- /*------------------------------------------------------------
- Func: EEPROM數據按字寫入
- Note: 字當半字用
- -------------------------------------------------------------*/
- void EEPROM_WriteWords(uint16 Addr,uint16 *Buffer,uint16 Length)
- {
- uint32 *wAddr;
- wAddr=(uint32 *)(EEPROM_BASE_ADDR+Addr);
- DIS_INT
- FLASH->PEKEYR=PEKEY1; //unlock
- FLASH->PEKEYR=PEKEY2;
- while(FLASH->PECR&FLASH_PECR_PELOCK);
- FLASH->PECR|=FLASH_PECR_FTDW; //not fast write
- while(Length--){
- *wAddr++=*Buffer++;
- while(FLASH->SR&FLASH_SR_BSY);
- }
- FLASH->PECR|=FLASH_PECR_PELOCK;
- EN_INT
- }