STM32F103を使ってみる

EEPROM emulation機能


Arduino_STM32 CoreにはEEPROM emulation機能が有ります。
こ ちらに詳しい解説が有りますが、Flash Memoryの一部をEEPROMとして使う機能です。
Arduino_STM32 Coreには、そのためのラ イブラリも用意されていて、サ ンプルコードも含まれていますが、今一つ使い方が分かりません。
そこで、まずはどの程度の大きさのEEPROMが使えるのか、以下のコードで確認してみました。
#include <EEPROM.h>

#define EPSIZE 254


void setup() {
  uint16 StartAddress = 0x10;
  uint16 AddressWrite;
  uint16 DataWrite;
  uint16 Status;
  uint16 Data;


  delay(1000);
  Serial.begin(9600);

  for(int i=0;i<EPSIZE;i++) {
    AddressWrite = StartAddress + i;
    DataWrite = AddressWrite;
    Status = EEPROM.write(AddressWrite, DataWrite);
    Serial.print("EEPROM.write(0x");
    Serial.print(AddressWrite, HEX);
    Serial.print("[");
    Serial.print(AddressWrite);
    Serial.print("], 0x");
    Serial.print(DataWrite, HEX);
    Serial.print(") : Status : ");
    Serial.println(Status, HEX);
  }

  for(int i=0;i<EPSIZE;i++) {
    AddressWrite = StartAddress + i;
    Status = EEPROM.read(AddressWrite, &Data);
    Serial.print("EEPROM.read(0x");
    Serial.print(AddressWrite, HEX);
    Serial.print(" = 0x");
    Serial.print(Data, HEX);
    Serial.print(" : Status : ");
    Serial.println(Status, HEX);
  }

}

void loop() {
  // put your main code here, to run repeatedly:

}

EPSIZEとStartAdressを色々変えて試したところ、0x10番地から254ワード(508バイト)がEEPROMとして使えること が分かりました。
StartAdressがこれよりも小さいとエラーとなります。
またアドレスが0x10Dを超えるとエラーとなります。

ESP8266にも似た機能のRTC User Areaが有ります。
ESP8266のRTC User Areaは通電しない状態でしばらく放置するとデータが初期化されてしまいます。
そこで、STM32のEEPROMについても以下のコードで確認してみました。
EEPROMの先頭32BitをCRCとして使って、起動時に読み込んだEEPROMのCRCが一致すればBlueLEDを点滅、一致しなけれ ばRedLEDが点滅します。
初回実行時は必ずRedLEDが点滅します。
#include <EEPROM.h>

//#define EPSIZE 252
#define EPSIZE 252

#define Red  PA0
#define Blue PA1

//EEPROM(254Word)の定義
struct EPROM{
  uint32_t crc32; // CRC
  uint16_t data[EPSIZE]; // User Data
};


int readEPROM(EPROM* hoge) {
  uint16 AddressWrite = 0x10;
  uint16 Status;
  uint16 Data;
  uint32_t crc32;
 
  Status = EEPROM.read(AddressWrite++, &Data);
  Serial.print("read crc(0)=");
  Serial.print(Data, HEX);
  Serial.print(" : Status : ");
  Serial.println(Status, HEX);
  if (Status != 0) return Status;
  crc32 = Data << 16;
 
  Status = EEPROM.read(AddressWrite++, &Data);
  Serial.print("read crc(1)=");
  Serial.print(Data, HEX);
  Serial.print(" : Status : ");
  Serial.println(Status, HEX);
  if (Status != 0) return Status;
  crc32 = crc32 + Data;
  hoge->crc32 = crc32;
 
  for(int i=0;i<EPSIZE;i++) {
    Status = EEPROM.read(AddressWrite, &Data);
    Serial.print("EEPROM.read(0x");
    Serial.print(AddressWrite, HEX);
    Serial.print(", &..) = 0x");
    Serial.print(Data, HEX);
    Serial.print(" : Status : ");
    Serial.println(Status, HEX);
    if (Status != 0) return Status;
    hoge->data[i] = Data;
    AddressWrite++;
  }
  return 0;
}

int writeEPROM(EPROM* hoge) {
  uint16 AddressWrite = 0x10;
  uint16 Status;
  uint16 Data;
  uint32_t crc32;

  Serial.println("[writeEPROM]");
  crc32 = hoge->crc32;
  Data = (crc32 >> 16) & 0xffff;
  Status = EEPROM.write(AddressWrite++, Data);
  Serial.print("write crc(0)=");
  Serial.print(Data, HEX);
  Serial.print(" : Status : ");
  Serial.println(Status, HEX);
  if (Status != 0) return Status;

  Data = crc32 & 0xffff;
  Status = EEPROM.write(AddressWrite++, Data);
  Serial.print("write crc(0)=");
  Serial.print(Data, HEX);
  Serial.print(" : Status : ");
  Serial.println(Status, HEX);
  if (Status != 0) return Status;
 
  for(int i=0;i<EPSIZE;i++) {
    Data = hoge->data[i];
    Status = EEPROM.write(AddressWrite, Data);
    Serial.print("EEPROM.write(0x");
    Serial.print(AddressWrite, HEX);
    Serial.print(", &..) = 0x");
    Serial.print(Data, HEX);
    Serial.print(" : Status : ");
    Serial.println(Status, HEX);
    if (Status != 0) return Status;
    AddressWrite++;
  }
  return 0;
}

// Calculate CRC
uint32_t calculateCRC32(const uint8_t *data, size_t length)
{
  uint32_t crc = 0xffffffff;
  while (length--) {
    uint8_t c = *data++;
    for (uint32_t i = 0x80; i > 0; i >>= 1) {
      bool bit = crc & 0x80000000;
      if (c & i) {
        bit = !bit;
      }
      crc <<= 1;
      if (bit) {
        crc ^= 0x04c11db7;
      }
    }
  }
  return crc;
}

void setup() {
  struct EPROM romData;

  delay(1000);
  Serial.begin(9600);

  pinMode(Blue,OUTPUT);
  pinMode(Red,OUTPUT);
  digitalWrite(Blue,LOW);
  digitalWrite(Red,LOW);

  uint32_t crcOfData;
  readEPROM(&romData);
  crcOfData = calculateCRC32(((uint8_t*) &romData) + 4, sizeof(romData) - 4);
  Serial.print("CRC32 of calculate: ");
  Serial.println(crcOfData, HEX);
  Serial.print("CRC32 read from EEPROM: ");
  Serial.println(romData.crc32, HEX);

  if (crcOfData == romData.crc32) {
    Serial.println("CRC is Valid!!");
    while(1) {
      digitalWrite(Blue,HIGH);
      delay(100);
      digitalWrite(Blue,LOW);
      delay(100);
    }
  } else {
    Serial.println("CRC is InValid!!");
    romData.crc32 = crcOfData;
    writeEPROM(&romData);
    while(1) {
      digitalWrite(Red,HIGH);
      delay(100);
      digitalWrite(Red,LOW);
      delay(100);
    }
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}

初回実行後、通電せずにまる1日放置し、再度通電しました。
BlueLEDが点滅しました。永遠に初期化されない様です。
どのタイミングでEEPROMの初期化を行えばいいのか、これはこれで悩ましいとろこです。

次回はEEPROMの初期化方法を紹介します。

続く...