STM32單片機內部EEPROM的讀寫

STM32L系列單片機內部提供了EEPROM存儲區域,但實質上,其FLASH也是EEPROM類型,只不過有一塊區域被開放出來專門用作EEPROM操作而已。STM32L的EEPROM使用壽命設計爲100000次擦寫以上,容量爲2K-4K,這對於一般設備的參數存儲來說是非常理想的。但從EEPROM使用方式看,其不適用於被反覆修改的數據存儲使用,一般作爲配置參數,其修改次數往往是比較少量的。

    STM32L的EEPROM和FLASH是統一編址,操作共用同一個讀寫電路,所以在EEPROM讀寫的時候STM32L覈對於FLASH的一切訪問和操作都將暫停,只有當EEPROM的操作完成後,才繼續執行後續代碼,在這期間只有EEPROM的讀寫電路工作,CPU處於掛起狀態。

    讀操作,和FLASH以及內存一樣,EEPROM的數據讀取直接用總線讀週期讀出即可,不需要進行額外操作和設置。

  1. #define EEPROM_BASE_ADDR    0x08080000    
  2. #define EEPROM_BYTE_SIZE    0x0FFF  
    以上定義EEPROM區的起始位置和大小,給定偏移量之後,可以按字節/半字/字/雙字方式讀出,但要注意的是最好偏移地址都按四字節對齊,以免產生總線訪問錯誤或是取不正確:

    

  1. /*------------------------------------------------------------ 
  2.  Func: EEPROM數據按字節讀出 
  3.  Note: 
  4. -------------------------------------------------------------*/  
  5. void EEPROM_ReadBytes(uint16 Addr,uint8 *Buffer,uint16 Length)  
  6. {  
  7.     uint8 *wAddr;  
  8.     wAddr=(uint8 *)(EEPROM_BASE_ADDR+Addr);  
  9.     while(Length--){  
  10.         *Buffer++=*wAddr++;  
  11.     }     
  12. }  
    
  1. /*------------------------------------------------------------ 
  2.  Func: EEPROM數據讀出 
  3.  Note: 
  4. -------------------------------------------------------------*/  
  5. void EEPROM_ReadWords(uint16 Addr,uint16 *Buffer,uint16 Length)  
  6. {  
  7.     uint32 *wAddr;  
  8.     wAddr=(uint32 *)(EEPROM_BASE_ADDR+Addr);  
  9.     while(Length--){  
  10.         *Buffer++=*wAddr++;  
  11.     }     
  12. }  


    以上方法使用字節和字方式讀出,在後面方法中,在一個字的存儲空間內只使用了16個位,另16位不用,這樣以避免產生對齊問題。

    EEPROM的編程比讀操作要複雜的多,本質上來說,擦除操作和寫入操作是一樣的,擦除只是在相應的地方寫入0x00000000,但在STM32L的實現上,根據其手冊說明貌似把這種擦除和寫入區分開了,當寫入0x00或0x0000或0x00000000時,自動執行一次擦除操作,在值爲非0時,才執行一次所謂的寫入操作。數據的寫入過程先要對EEPROM進行解鎖,這通過對特殊寄存器寫入特殊序列實現,然後在寫入之前進行擦除操作,其擦除是按字/ 雙字/頁進行的,推薦使用頁擦除方式進行,先把參數讀到內存,並修改,再進行頁擦除,最後將參數寫回,這種方式比較通用,否則很容易出現地址對齊或長度問題。在數據擦除完成之後,即可進行寫入,每寫一字節/半字/雙字,都需要判斷其是否寫入完成,這和內部高壓擦寫電路有關,只有在上次操作完成之後再進行其它操作纔有意義。最後,對EEPROM進行加鎖,以保護數據。

 

    下是手冊給出的解鎖命令碼:

    

  1. #define PEKEY1  0x89ABCDEF      //FLASH_PEKEYR  
  2. #define PEKEY2  0x02030405      //FLASH_PEKEYR  
    以下分別實現按字節和字方式寫入:   

  1. /*------------------------------------------------------------ 
  2.  Func: EEPROM數據按字節寫入 
  3.  Note: 
  4. -------------------------------------------------------------*/  
  5. void EEPROM_WriteBytes(uint16 Addr,uint8 *Buffer,uint16 Length)  
  6. {  
  7.     uint8 *wAddr;  
  8.     wAddr=(uint8 *)(EEPROM_BASE_ADDR+Addr);  
  9.     DIS_INT  
  10.     FLASH->PEKEYR=PEKEY1;                //unlock  
  11.     FLASH->PEKEYR=PEKEY2;  
  12.     while(FLASH->PECR&FLASH_PECR_PELOCK);  
  13.     FLASH->PECR|=FLASH_PECR_FTDW;        //not fast write  
  14.     while(Length--){  
  15.         *wAddr++=*Buffer++;  
  16.         while(FLASH->SR&FLASH_SR_BSY);  
  17.     }  
  18.     FLASH->PECR|=FLASH_PECR_PELOCK;  
  19.     EN_INT  
  20. }  
    
  1. /*------------------------------------------------------------ 
  2.  Func: EEPROM數據按字寫入 
  3.  Note: 字當半字用 
  4. -------------------------------------------------------------*/  
  5. void EEPROM_WriteWords(uint16 Addr,uint16 *Buffer,uint16 Length)  
  6. {  
  7.     uint32 *wAddr;  
  8.     wAddr=(uint32 *)(EEPROM_BASE_ADDR+Addr);  
  9.     DIS_INT  
  10.     FLASH->PEKEYR=PEKEY1;                //unlock  
  11.     FLASH->PEKEYR=PEKEY2;  
  12.     while(FLASH->PECR&FLASH_PECR_PELOCK);  
  13.     FLASH->PECR|=FLASH_PECR_FTDW;        //not fast write  
  14.     while(Length--){  
  15.         *wAddr++=*Buffer++;  
  16.         while(FLASH->SR&FLASH_SR_BSY);  
  17.     }  
  18.     FLASH->PECR|=FLASH_PECR_PELOCK;  
  19.     EN_INT  
  20. }  
    以上代碼中,在寫入數據之前先關閉系統中斷DIS_INT,寫入完成之後打開系統中斷EN_INT,這樣避免在執行寫操作的過程中被中斷過程所打斷,引起CPU異常或鎖死,在在使用中一定要注意。在MDK環境中,兩個可以這樣定義:

    

  1. #define EN_INT          __enable_irq();     //系統開全局中斷  
  2. #define DIS_INT         __disable_irq();    //系統關全局中斷  


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章