ESP32 で EEPROM を使うと Guru Meditation Error

# 状況

スイッチにつなげたピンに状態変化割り込みをかけて、EEPROM に書き込みを行っている最中にスイッチを連打すると時々リセットがかかってしまう。

# 環境

- ESP32 by Espressif System Version 1.0.4
- Arduino 1.8.13
- ESP32 WROOM-32E

# エラー出力

リセット時、シリアルモニターに以下のエラーが出る

```

Guru Meditation Error: Core  1 panic'ed (Cache disabled but cached memory region accessed)

```

# コード

EEPROMにデータを保管するルーチン

```

void eeprom_write() {

  int data[10];
  data[0] = log_aaa;
  data[1] = log_bbb;
  data[2] = log_ccc;
  data[3] = log_ddd;
  data[4] = log_eee;
  data[5] = log_fff;
  data[6] = log_ggg;
  data[7] = log_hhh;
  data[8] = log_iii;
  data[9] = log_jjj;
  int n = 0;
  for (int i = 0; i < 10; i++) {
    EEPROM.put(n, data[i]);
    n += 4; // 4バイト毎
  }
  delay(100);
  EEPROM.commit(); // EEPROMに書き込み確定


}
```

# 対策

「ESP32 core 1 panic'ed when EEPROM and timer interrupt used together- ESP32 Forum」
https://esp32.com/viewtopic.php?t=13861

ではタイマー割り込みとの競合で同様のエラーが起こっている。
しかしながら最後の解決として以下の投稿がある。

> 1.  Find the amount of time it takes to finish all the activities on the onTimer() routine using millis().
> 2. Just before EPROM.commit()
>  - stop the timer(hw_timer_disarm(void))
>  - Optional: detach interrupt
>  - Depending on what you found in step 1 above put a delay (n) , so if you found that control spends 10ms in the timer routine then put a Delay(10).
> 3.execute EPROM.commit() after the above steps.
> 4. Arm/Start the timer , in case you detached the interrupt attach it back.


今回のトラブルは状態変化割り込みによるものであるが、タイマーも使用していたので以下のように対処することにする


- 書き込み中のタイマーを停止
- 書き込み中の状態変化割り込みを停止
- 今回はタイマー処理で要する時間はほぼ無いが、念の為に 100ミリ秒ウェイトをかけてから EEPROM.commit をかける
- 状態変化割り込みを復元
- タイマーを復元


# 対応したコード


```

void eeprom_write() {
  // EEPROM操作のためにタイマーを停止
  timerAlarmDisable(timer);    // stop alarm
  timerDetachInterrupt(timer); // detach interrupt
  timerEnd(timer);      // end timer
  // EEPROM操作のために割り込みを停止
  detachInterrupt(ENCODER1_A_PIN);
  detachInterrupt(ENCODER1_B_PIN);
  detachInterrupt(ENCODER1_SWITCH_PIN);
  detachInterrupt(ENCODER2_A_PIN);
  detachInterrupt(ENCODER2_B_PIN);   // rotary_encoder
  detachInterrupt(ENCODER2_SWITCH_PIN);  // rotary_encoder push switch

  int data[10];
  log_ozone =  log_ozone10 / 10;
  data[0] = log_aaa;
  data[1] = log_bbb;
  data[2] = log_ccc;
  data[3] = log_ddd;
  data[4] = log_eee;
  data[5] = log_fff;
  data[6] = log_ggg;
  data[7] = log_hhh;
  data[8] = log_iii;
  data[9] = log_jjj;
  int n = 0;
  for (int i = 0; i < 10; i++) {
    EEPROM.put(n, data[i]);
    n += 4; // 4バイト毎
  }
  delay(100);
  EEPROM.commit(); // EEPROMに書き込み確定

  // 割り込み再設定
  attachInterrupt(ENCODER1_A_PIN, ISR, CHANGE);   // rotary_encoder
  attachInterrupt(ENCODER1_B_PIN, ISR, CHANGE);   // rotary_encoder
  attachInterrupt(ENCODER1_SWITCH_PIN, RELEASE1, RISING);  // rotary_encoder push switch
  attachInterrupt(ENCODER2_A_PIN, ISR, CHANGE);   // rotary_encoder
  attachInterrupt(ENCODER2_B_PIN, ISR, CHANGE);   // rotary_encoder
  attachInterrupt(ENCODER2_SWITCH_PIN, RELEASE2, RISING);  // rotary_encoder push switch
  // タイマー再稼働
  timer = timerBegin(0, 80, true);
  timerAttachInterrupt(timer, &onTimer, true);
  timerAlarmWrite(timer, 20000, true);  // 20m sec
  timerAlarmEnable(timer);

}
```

これでエラーが解消できました。