すっさんぽ
  1. Posts/

ESP32の無限リセット & LCDが動作しない問題への対処

·

ESP32(ESP-WROOM-32, ESP32-DevKitC-32E)で、書き込んだスケッチが実行されずに、無限リセットされる問題に遭遇しました。 その調査と対処をまとめます。

発生した問題 #

ESP-WROOM-32に書き込んだスケッチが実行されず、リセットされ続ける問題に遭遇しました。以下のログが継続的に何度も出力される現象です。このとき、スケッチの setup()まったく実行されていません

00:10:32.828 -> ets Jul 29 2019 12:21:46
00:10:32.828 -> 
00:10:32.828 -> rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
00:10:32.828 -> configsip: 0, SPIWP:0xee
00:10:32.828 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
00:10:32.828 -> mode:DIO, clock div:1
00:10:32.828 -> load:0x3fff0030,len:1420
00:10:32.828 -> ho 0 tail 12 room 4
00:10:32.828 -> load:0x40078000,len:13540
00:10:32.828 -> load:0x40080400,len:3604
00:10:32.828 -> entry 0x400805f0

調査1 #

まず、 rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 のログを頼りに調査しました。 すると、以下の可能性が出てきました。

  1. 電流が不足しているから、別電源をとるとよい
  2. Flash Frequencyを80MHzから40MHzに落としたらよい
  3. Flash ModeをQIOではなくDIOに変更するとよい
  4. CPUの速度を下げたらよい

いずれも解決しませんでした。

調査2 #

同じESP-WROOM-32をつかった温湿度計は、問題なく動作していました。このことから、空のスケッチを書き込み、動作しなくなるところまで少しずつ実装を足してみることにしました。

すると、以下のコードが入った途端に、スケッチが実行されなくなることがわかりました。

#include <LiquidCrystal.h>

const int rs = 23, en = 22, d4 = 21, d5 = 19, d6 = 18, d7 = 5;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);  // この行

先述のログが出力され、スケッチは実行されなくなりました。

一方、LiquidCrystalを、グローバルではなくローカルスコープにインスタンスを作成すると、スケッチは無事実行されました。

#include <LiquidCrystal.h>

const int rs = 23, en = 22, d4 = 21, d5 = 19, d6 = 18, d7 = 5;

void setup() {
    LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

    lcd.begin(20, 4);
    delay(500);

    lcd.print("hello, world!");  // 問題なく表示される
}

以上から、LiquidCrystalのインスタンスをグローバルスコープで初期化したときだけ、スケッチが動作しなくなるとわかりました。したがって、おそらくLiquidCrystalの初期化処理に問題があるとの見当が付きました、

調査3 #

LiquidCrystalのソースを確認するため、GitHubへ行きます。そして、まずIssueを覗きます。「ESP32」などのワードで、Issueが上がっていないか確認します。

Issueがありました。 LiquidCrystal causing ESP32-S2-Wrover-I to crash. #41

私が遭遇した現象も、Issueに書いてある内容と全く同じ現象でした。そこで、そのやり取りにある以下の変更を試してみることにしました。

Commenting out the ‘begin(16,1)’ call from the ‘LiquidCrystal::init’ function in ‘LiquidCrystal.cpp’ and placing it in the sketch (where it should be already, with proper display size) solves the issue, because the ‘delayMicroseconds()’ function will work.

LiquidCrystal.cppLiquidCrystal::init関数からbegin(16,1)をコメントアウトすると問題は解決するとのことです。

やってみました。 まず、LiquidCrystal.cppを探します。私の環境では以下のところにありました。OSは、MacOSです。

1.6系までは以下の場所です。

/Applications/Arduino.app/Contents/Java/libraries/LiquidCrystal/src/LiquidCrystal.cpp

2.0系からは、以下の場所です。

${HOME}/Documents/Arduino/libraries/LiquidCrystal/src/LiquidCrystal.cpp

適当なテキストエディタで開きます。そして、53-76行にあるinit関数のなかから、最後にある begin(16,1);をコメントアウトします。(バージョン1.0.7の場合)

void LiquidCrystal::init(
    uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
    uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
    uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) 
{
    ...
    ...

    // begin(16, 1);
}

これを保存して、改めて、スケッチをコンパイル & 書き込みしてみます。

ついに表示されました!

Arduino IDEをアップデートするたびに、この対応する必要があります。
LiquidCrystalはIDEにバンドルされたライブラリです。そのため、IDEを更新するたびに、この対応が必要になります。

まとめ #

ESP-WROOM-32でLCDを使うと、スケッチが実行されなくなる問題への対応方法を書きました。ライブラリのソースを変更するという直接的な方法で、スケッチを実行できるようにしました。

Issueによると、スケッチが動かなくなる原因はおそらく、delayMicroseconds()がまだ使用できない段階で、それを含むbegin(16,1)が実行されていたから、とのこと。また、すでに対応済みのプルリクエストがあったようですが、ライブラリをArduinoリポジトリから専用リポジトリへ切り出す際に、どういうわけかそのプルリクエストはIssueに変更され、ブランチは塩漬け状態になっているとのことでした。


ちなみに、ESP-WROOM-32でLCDが動作しない現象に遭遇してから、今回の解決まで2ヶ月かかりました。仕事が忙しかったのもありますが、相性が悪いのだろうと、半ば諦めていたためでもあります。 数日前にESP-WROOM-02からLCDが動作できたのをきっかけに、あらためてESP-WROOM-32でもどうにか動かしたい欲求が高まり、今回の解決方法を見つけました。これで、当初作りたいと思っていたものを実装できそうです。