LoginSignup
8
8

More than 3 years have passed since last update.

STM32内蔵のEEPROMを使用する方法

Last updated at Posted at 2019-12-19

STM32L0シリーズやSTM32L1シリーズにはEEPROMが内蔵されています。
内蔵EEPROMに記録した内容は電源が切れても保持されるため設定などを記録しておくのに便利です。
今回はHLAを使用してSTM32L081を例に内蔵EEPROMにデータを読み書きする方法を紹介します。

EEPROMの場所について

STM32に使われているCortex-Mでは、メモリマップという方式を用いて1つの線形メモリ上にSRAMやFlash ROM、IOポートなどを割り当てて管理しています。このようにすることでC言語上からはポインタを用いてSRAM以外にFlash ROMやIOポートにもアクセスすることができるようになります。以下の図はSTM32L0x1のメモリマップです1image.png

EEPROMも同様に同じ線形メモリ上に割り当てられているため、ポインタを用いてアクセスすることができます。データシートを見ると、STM32L081のEEPROMの場所は0x08080000から0x080817FFまでの6kBであることが分かります。
image.png

EEPROMに書き込む

EEPROMにデータを書き込むにはHAL_FLASHEx_DATAEEPROM_Programという関数を使用します。
ただし、通常の状態だとEEPROMは書き込み保護がされているため書き込む前に保護を解除する必要があります。EEPROMの保護を解除するにはHAL_FLASHEx_DATAEEPROM_Unlockという関数を、再度保護するにはHAL_FLASHEx_DATAEEPROM_Lockという関数を使用します。

HAL_FLASHEx_DATAEEPROM_Program (uint32_t TypeProgram, uint32_t Address, uint32_t Data);
HAL_FLASHEx_DATAEEPROM_Unlock(void);
HAL_FLASHEx_DATAEEPROM_Lock(void);

第1引数のTypeProgramには何バイト単位で書き込むかを指定します。指定できるのは以下の3種類です。

  • FLASH_TYPEERASEDATA_BYTE    1byte(8bit)単位
  • FLASH_TYPEERASEDATA_HALFWORD 2byte(16bit)単位
  • FLASH_TYPEERASEDATA_WORD    4byte(32bit)単位

第2引数には書き込み先のアドレスを指定します。EEPROMの範囲外のアドレスを指定するとHardFaultします。
STM32L081では0x08080000から0x080817FFまでの値を指定することができます。

第3引数には実際に書き込むデータを入力します。

以上のことを踏まえて、4byte(32bit)単位でデータを書き込む関数を作ると以下のようになります。

void eeprom_writeWord(uint32_t address, uint32_t value) {
    if (!IS_FLASH_DATA_ADDRESS(address)) {
        return;
    }
    HAL_FLASHEx_DATAEEPROM_Unlock();
    HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WORD, address, value);
    HAL_FLASHEx_DATAEEPROM_Lock();
}

なお、IS_FLASH_DATA_ADDRESS(address)addressで指定した値がEEPROMのアドレスの範囲内にあるかどうかを判定するマクロです。(stm32l0xx_hal_flash_ex.hの中で定義されています。)
実際にEEPROMに書き込む前に、上記の例のように指定されたアドレスがEEPROMの範囲内であるか判定するようにすることでエラーを防ぎます。

EEPROMから読み出す

HALにEEPROMからデータを読み出す関数は存在しません。というのも、1つの線形メモリ上にEEPROMが存在するため、ポインタを用いて直接アドレスを指定するだけで読めてしまうからです2
以下のようにしてデータを読み出すことができます。addressにはEEPROM上の読みたいデータがある場所を指定します

uint8_t  value = *(__I uint8_t *)address; //1byte(8bit)単位で読み出し
uint16_t value = *(__I uint16_t*)address; //2byte(16bit)単位で読み出し
uint32_t value = *(__I uint32_t*)address; //4byte(32bit)単位で読み出し

__Iという見慣れない修飾子がついていますが、これはvolatileと同義です。STM32でアドレスを直接指定してデータを読み出すときに必要になるようです3

まとめ

4byte(32bit)単位でデータを読み書きする関数の例を以下にまとめておきます。(もう少しまともな実装例がある気がしますが、気が向いたら更新します。)

void eeprom_writeWord(uint32_t address, uint32_t value) {
    if (!IS_FLASH_DATA_ADDRESS(address)) {
        return;
    }
    HAL_FLASHEx_DATAEEPROM_Unlock();
    HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WORD, address, value);
    HAL_FLASHEx_DATAEEPROM_Lock();
}

void eeprom_readWord(uint32_t address, uint32_t* value) {
    if (!IS_FLASH_DATA_ADDRESS(address)) {
        return;
    }
    *value = *(__I uint32_t*)address;
}

  1. STM32L0x1 Reference Manuals (RM0377) https://www.st.com/content/st_com/en/products/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus/stm32-ultra-low-power-mcus/stm32l0-series/stm32l0x1/stm32l081cb.html 

  2. EEPROMに書き込む場合もポインタを用いて直接書き込むことができるように思えますが、推奨しません。正しく書き込むためには書き込み前と後にいくつかの手順が必要なようです。stm32l0xx_hal_flash_ex.cの中を見るとそれが分かります。HALを使用する場合、書き込みには素直にHAL_FLASHEx_DATAEEPROM_Programを用いましょう。 

  3. STM32以外にもCortex-Mを用いたARM系のマイコンでは同様のようです。詳細は「C言語 volatile」などでググってみたり、CMSISのリファレンスを覗いてみたりしましょう。 

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8