STM8L EEPROM DATA數據讀寫

一、概要
STM8系列一般擁有如下幾種三種數據區

  • 用戶啓動區域(UBC)
  • 數據EEPROM(DATA)
  • 主程序區
  • 選項字節(Option byte)

用戶啓動區域(UBC)包含有復位和中斷向量表,它可用於存儲IAP及通訊程序;
數據EEPROM(DATA)區域可用於存儲用戶具體項目所需的數據;
主程序區是指在FLASH程序存儲器中用於存儲應用代碼的區域;
選項字節用於配置硬件特性和存儲器保護狀態。

作爲應用而言,一般主要使用EEPROM(DATA),存放各種參數、或者離線數據、狀態數據等等。
下面以以STM8L052R8爲例,簡單說明對其的訪問方法。

根據STM8L052R8的手冊,其有Memory信息如下:

■ Memories
– 64 KB Flash program memory and 256 bytes data EEPROM with ECC, RWW
– Flexible write and read protection modes
– 4 KB of RAM

可知其具有256字節的EEPROM。並帶有ECC校驗,和RWW(讀同時寫)功能。

RWW特性允許戶在執行程序和讀程序存儲器時對DATA EEPROM區域進行寫操作,
因此執行的時間被優化了。相反的操作是不允許的:即不允許在寫程序寄存器是對其進行讀操作。
RWW特性是一直有效的而且可以在任意時刻使用

對EEPROM編程也有如下幾種方式,顧名思義,很容易理解其含義。
字節編程方式最易於理解,也最簡單。

  • 字節編程
  • 字編程
  • 塊編程

二、更深入的細節
STM8系列有存儲器存取安全系統(MASS),在復位後,主程序和DATA區域都被自動保護以防止無意的寫操作。
在修改其內容前必須對其解鎖,而解鎖的機制由存儲器存取安全系統(MASS)來管理。(UBC始終爲寫保護)
因此寫操作時需要先解除寫保護,並在完成寫入後恢復寫保護(視應用而定)。

Unlock的具體操作是,向FLASH_DUKR寄存器連續寫入兩個被叫作MASS密鑰的值:

  • 第一個硬件密鑰: 0b1010 1110 (0xAE)
  • 第二個硬件密鑰: 0b0101 0110 (0x56)

如果解鎖成功,FLASH_IAPSR中的DUL位被置爲1,表示成功。
應用必須檢測這個標誌纔可進行後續操作。
(編程區與之類似,但寫入的是PUKR,且2個密鑰順序相反)

對EEPROM的讀寫其實非常簡單,就是直接對地址按字節進行賦值和取值。
但是在操作後,需要等待其操作完成。判斷方法是:

  • 對於EEPROM(DATA)數據區:FLASH_IAPSR寄存器的HVOFF(高壓結束標誌位)變爲1
  • 對於編程區:FLASH_IAPSR寄存器的EOP(編程結束標誌位)變爲1

另外,試圖向被保護頁進行寫操作時,會發生錯誤,此時FLASH_IAPSR得WR_PG_DIS標誌位會置1。
所以,最終的判斷方法是:
HVOFF或者WR_PG_DIS被置爲1,前者爲正常介紹,後者表示出錯

三、示例代碼

地址範圍定義(讀寫範圍爲0~127字節)

#define DATA_MEMORY_START_ADDR (FLASH_DATA_EEPROM_START_PHYSICAL_ADDRESS)
#define DATA_MEMORY_STOP_ADDR  (FLASH_DATA_EEPROM_START_PHYSICAL_ADDRESS + 128)

初始化函數

void flash_init(void)
{
    // 設置編程時間,指定標準編程時間即可
    FLASH_SetProgrammingTime(FLASH_ProgramTime_Standard);

    // 解鎖EEPROM區域(注意type是Data)
    FLASH_Unlock(FLASH_MemType_Data);

    // 等待解鎖成功
    // 本質是判斷FLASH->IAPSR寄存器的DUL標誌位是否變爲1。1表示寫保護消除,0爲保護中
    // 任何時候都可以通過變更此標誌位爲0來恢復寫保護狀態
    while (FLASH_GetFlagStatus(FLASH_FLAG_DUL) == RESET);
}

讀函數

uint8_t flash_read(uint32_t FlashAddr, uint8_t *dest, uint8_t nbyte)
{
    uint8_t i = 0;
    // 越界判斷
    if((FlashAddr < DATA_MEMORY_START_ADDR)||(FlashAddr+ nbyte > DATA_MEMORY_STOP_ADDR)) {
        return FALSE;
    }
    // 按字節讀
    for(i=0; i<nbyte; i++) {
        *(dest+i)=FLASH_ReadByte(FlashAddr+i);

        // 等待操作完成,此處未處理錯誤
        FLASH_WaitForLastOperation(FLASH_MemType_Data);
    }

    return nbyte;
}

寫函數

uint8_t flash_write(uint32_t FlashAddr, uint8_t *source, uint8_t nbyte)
{
    uint8_t i = 0;
    // 越界判斷
    if((FlashAddr < DATA_MEMORY_START_ADDR)||(FlashAddr+ nbyte > DATA_MEMORY_STOP_ADDR)) {
        return FALSE;
    }
    // 按字節寫
    for(i=0;i<nbyte;i++) {
        FLASH_ProgramByte((FlashAddr+i),*(source + i));

        // 等待操作完成,此處未處理錯誤
        FLASH_WaitForLastOperation(FLASH_MemType_Data);
    }
    return nbyte;
}

四、庫函數實現解析

FLASH_Unlock函數

void FLASH_Unlock(FLASH_MemType_TypeDef FLASH_MemType)
{
  /* Unlock program memory */
  if(FLASH_MemType == FLASH_MemType_Program)
  {
    FLASH->PUKR = FLASH_RASS_KEY1;
    FLASH->PUKR = FLASH_RASS_KEY2;
  }

  /* Unlock data memory */
  // 連續兩次賦值密鑰(固定值)
  if(FLASH_MemType == FLASH_MemType_Data)
  {
    FLASH->DUKR = FLASH_RASS_KEY2; /* Warning: keys are reversed on data memory !!! */ /* 0xAE */
    FLASH->DUKR = FLASH_RASS_KEY1; /* 0x56 */
  }
}

FLASH_ReadByte、FLASH_ProgramByte、FLASH_EraseByte
由下可知,讀寫擦出均爲直接操作地址。

uint8_t FLASH_ReadByte(uint32_t Address)
{
  /* Read byte */
  return(*(PointerAttr uint8_t *) (MemoryAddressCast)Address);
}

void FLASH_ProgramByte(uint32_t Address, uint8_t Data)
{
  *(PointerAttr uint8_t*) (MemoryAddressCast)Address = Data;
}

void FLASH_EraseByte(uint32_t Address)
{
  *(PointerAttr uint8_t*) (MemoryAddressCast)Address = FLASH_CLEAR_BYTE; /* Erase byte */
}

FLASH_WaitForLastOperation 操作等待

FLASH_Status_TypeDef FLASH_WaitForLastOperation(FLASH_MemType_TypeDef FLASH_MemType))
{
  uint16_t timeout = OPERATION_TIMEOUT;
  uint8_t flagstatus = 0x00;

  /* Wait until operation completion or write protected page occurred */
  // 程序區等待IAPSR的EOP或者WR_PG_DIS標識位被置爲1
  if(FLASH_MemType == FLASH_MemType_Program)
  {
    while((flagstatus == 0x00) && (timeout != 0x00))
    {
      flagstatus = (uint8_t)(FLASH->IAPSR & (uint8_t)(FLASH_IAPSR_EOP |
                                                       FLASH_IAPSR_WR_PG_DIS));
      timeout--;       // 貼心的超時處理
    }
  }
  else
  {
   // 數據區的話,等待IAPSR的HVOFF或者WR_PG_DIS標識位被置爲1
    while((flagstatus == 0x00) && (timeout != 0x00))
    {
      flagstatus = (uint8_t)(FLASH->IAPSR & (uint8_t)(FLASH_IAPSR_HVOFF |
                                                      FLASH_IAPSR_WR_PG_DIS));
      timeout--;        // 貼心的超時處理
    }
  }

  if(timeout == 0x00)
  { 
    // 超時
    flagstatus = FLASH_Status_TimeOut;
  }

  return((FLASH_Status_TypeDef)flagstatus);
}

以上,相比直接操作寄存器,用庫做STM開發還是比較有效率的。

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