ESP8266のReset動作


ESPシリーズに搭載されているFlushメモリーのサイズを調べたときに、EspClassと 呼ばれる関数群があることが分かりました。
EspClass関数群の中に興味深い関数が有りました。
ESP.reset()
ESP.restart()

どうやら強制的に再起動を行う関数のようです。
そこで、これらの関数を実行したときに、RTCのユーザエリアはクリアされるのかどうか確認してみました。
使用したスケッチは以下のスケッチです。
/*
 ESP.reset()/ESP.resart()でRTC User Memoryがクリアされるかどうかのテスト
*/

//RTC memory(512Byte)の定義
struct {
  uint32_t crc32; // CRC
  uint8_t data[508]; // User Data
} rtcData;


// 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;
}

// Print RTC memory
void printMemory(int sz) {
  char buf[3];
//  for (int i = 0; i < sizeof(rtcData); i++) {
  for (int i = 0; i < sz; i++) {
    sprintf(buf, "%02X", rtcData.data[i]);
    Serial.print(buf);
    if ((i + 1) % 32 == 0) {
      Serial.println();
    }
    else {
      Serial.print(" ");
    }
  }
  Serial.println();
}


void setup() {
  delay(10000);
  Serial.begin(9600);
  Serial.println();
  Serial.println("Wake Up");
 
  // RTC memoryからデータを読み込む
  if (ESP.rtcUserMemoryRead(0, (uint32_t*) &rtcData, sizeof(rtcData))) {
//    Serial.println("Read: ");
//    printMemory(10);
  // 読み込んだデータでCRC32を計算する
    uint32_t crcOfData = calculateCRC32(((uint8_t*) &rtcData) + 4, sizeof(rtcData) - 4);
//    Serial.print("CRC32 of data: ");
//    Serial.println(crcOfData, HEX);
//    Serial.print("CRC32 read from RTC: ");
//    Serial.println(rtcData.crc32, HEX);
  // CRC32が一致しないので初回起動時
    if (crcOfData != rtcData.crc32) {
      Serial.println("CRC32 in RTC memory doesn't match CRC32 of data. Data is probably invalid!");
      for (int i = 0; i < sizeof(rtcData); i++) {
        rtcData.data[i] = 0;
      }
    }
  // CRC32が一致したのでDeelSleepからの復帰
    else {
      Serial.println("CRC32 check ok, data is probably valid.");
      rtcData.data[0]++;
    }
  }

  // CRC32を再計算
  rtcData.crc32 = calculateCRC32(((uint8_t*) &rtcData) + 4, sizeof(rtcData) - 4);
  // RTC memoryにデータを書き込む
  if (ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcData, sizeof(rtcData))) {
//    Serial.println("Write: ");
//    printMemory(10);
  }

  Serial.print("rtcData.data[0]=");
  Serial.print(rtcData.data[0]);
  Serial.print(" millis=");
  Serial.println(millis());
  if ((rtcData.data[0] % 2) == 0) {
    Serial.println("Do ESP.reset");
    delay(1000);
    ESP.reset();
  } else {
    Serial.println("Do ESP.restart");
    delay(1000);
    ESP.restart();
  }
}

void loop()
{
}

結果は以下の通りです。


rtcData.data[0]の値はインクリメントされています。
ESP.reset() ESP.restart() ともに、RTCのユーザエリアはクリアされないことが分かりました。
millis()の値は初期化されるようです。

これ、非常に面白いです。
例えば、1つのスケッチの中で、WifiのSoftAPモードとStationモードを切り替えたり、
1つのスケッチの中で、UDPとTCPを使い分けることができます。

そこで、次回はReset動作を利用した時刻合わせを紹介します。
続く....