Arduino – ESP32 WiFiClientSecure ライブラリのハングアップ問題がついに解決!

記事公開日:2017年7月12日

スポンサーリンク

こんばんは。

アマチュア電子工作家の私としては、今回は一歩も二歩も踏み込んで問題を解決してみました。
おかげで疲労困ぱい状態でございます。

GitHub にある、Arduino core for ESP32 WiFi chip の WiFiClientSecure ライブラリを使って、Web上の SSL ( https )サイトを GET していると、200回以下で必ずフリーズ(ハングアップ)して、 ESP32 ( ESP-WROOM-32 )が一切動かなくなってしまう症状がありました。

最近はデュアルコア(マルチタスク)も試していますが、そのうちの 1core だけが動かなくなってしまいます。

これには長らく悩まされていましたが、今回、ついに解決しました!!!

結論は、mbedtls ライブラリの MPI ハードウェアアクセラレーションが有効になっていたことが原因です。

ただ、mbedtls ライブラリの設定は、ESP-IDF では簡単に変えることができるのですが、Arduino core for ESP32 では変えられないんです。
Web上のどこにもその手順は無く、自分で解決せざるを得ませんでした。
要は、GitHub 上のライブラリでバグ修正してくれれば話は早いのですが、今、issue で問題点を投げかけている最中です。
ですが、何とか自力で解決できましたので私的には満足です。
本家のライブラリがアップデートされるまでの間の対処方法として、十分使えると思いますよ。

実は、以下に述べる方法は、私としてはとても画期的で、目から鱗のようなノウハウが沢山ありました。
これらは、Arduino IDE で ESP32 をデュアルコア(マルチタスク)で動かすことの参考にもなりますし、豊富な機能の ESP-IDF と Arduino IDE を連携させることにも役立つ方法です。

このノウハウを身に付けることによって、ESP32 の開発が飛躍的に伸びる可能性大です。

では、方法を説明しますが、その前に、Twitter でもいろいろ情報を頂戴している けりさん ( @Ryokeri14 )の以下のブログ記事からは、大変良いヒントを頂きました。

ESP32でデュアルコアを使おう!

この記事は WiFiClientSecure ライブラリと関係ないと思うかもしれませんが、実は後でジワジワと効いてきますので、合わせてご覧ください。

ハングアップ原因の特定方法

Arduino core for ESP32 の WiFiClientSecure ライブラリを使って、SSL ( https )ページから定期的に記事を取得していると、ある時フリーズ(ハングアップ)します。

プログラムがストップしている個所を詳細に知るためには、下図の様に デバッグを最高レベルの Verbose にしておきます。

mbedtls_01

すると、シリアルモニターでこんな感じに表示されます。

mbedtls_02

私の場合、いつも ssl_client.cpp ファイルの 153行目でフリーズ(ハングアップ)してしまい、固まって動かなくなっていました。

ssl_client.cpp ファイルは Windows10 の場合、以下のパスにあります。

C:\Users\User-name\Documents\Arduino\hardware\espressif\esp32\libraries\WiFiClientSecure\src

ssl_client.cpp ファイルをテキストエディタで開いてみます。
すると、下図のようになっていて、153行目はデバッグログの出力です。
よって、その後の while ループで固まっていることが分かりました。

mbedtls_03

そこで、whileループ内に独自にタイムアウト制御を作って置いてみましたが、一向にタイムアウトしてくれません。

ということは、mbedtls_ssl_handshake 関数でフリーズしていることが断定できます。

では、mbedtls_ssl_handshake 関数はどこで定義されているのか?

それは、Windows のエクスプローラーのファイル検索をかけると、意外と簡単に見つけられます。

Windows10 の場合、下図の様にエクスプローラーの詳細オプションをクリックして、ファイルコンテンツにチェックを入れてください。
その後、右側の検索ワード覧に下図の様に mbedtls_ssl_handshake と入力すれば、そのワードが使われているファイルを検索してくれます。

すると、こんな感じで6つのファイルが見つかりました。

mbedtls_04

ssl_client.cpp ファイル内には、mbedtls_ssl_handshake 関数のソースはありませんでした。
その他はヘッダファイルと、拡張子が a のファイルだけです。
ヘッダファイルには関数の宣言だけしかありません。
ということは、拡張子が a の2つのファイルだけに絞ることができます。

ただ、このファイルは既にコンパイルされたアセンブラ形式のバイナリファイルです。
これを直接編集することはできません。

そこで、ネットで検索したり、GitHub の issue を検索したりしました。

結果、ESP-IDF の issue #630 Bug: mbedtls_ssl_handshake() hangs after several calls にそれらしき解決策がありました。

そこにある答えは、

mbedtls ライブラリの MPI ハードウェアアクセラレーションが原因でハングアップするので、それを解除すれば良いとのこと。

MPI ハードウェアアクセラレーションを使えば、本来は SSL 処理が速くなるらしいです。
ESP-IDF 開発環境では、コンパイルする前に、make menuconfig コマンドで設定できます。

ということは、mbedtls が問題なので、libmbedtls.a ファイルに原因があるとほぼ断定できます。

私は今まで Arduno IDE しか使ったことが無かったので、どうやったら良いか全く分かりませんでした。
よって、Arduino core for ESP32 の issue #481 で質問してみました。
(英語が不得意なので、翻訳機能を使っています。)

すると、現在の ESP-IDF ではデフォルトで MPI ハードウェアアクセラレーションが外されているとのこと。
現段階では、MPI ハードウェアアクセラレーションはバグが多いらしいです。
つまり、ESP-IDF で設定して、SSL ページ取得するプログラムを組めば、全く問題ない動作をするそうなのです。

また、Arduino IDE のハングアップを解決するためには、開発チームの @me-no-dev さんに libmbedtls.a ファイルをコンパイルしてもらうように依頼して下さいとの回答でした。

ちょっと途方に暮れてしまいましたが、もしかしたら、ESP-IDF を使えば libmbedtls.aファイルを自分でコンパイルできるかも知れないと思いつつ実験してみることにした次第です。

ESP-IDF 開発環境のインストール

ESP-IDF 開発環境は、本家 Espressif 社推奨のものです。
私はずっと Arduino IDE しか使ったことが無かったので、これを使い始めたのはほんの2週間前で、かなり出遅れました。

Arduino IDE と違って、かなり取っ付きにくいので、以下の記事に私なりにまとめてみました。
コマンドラインで環境設定やコンパイル書き込みを行います。
理解するまでに少々時間がかかるのは覚悟しておいてください。

ESP-IDF ( ESP32 開発環境 ) の使い方

これは、ESP32 ( ESP-WROOM-32 ) のポテンシャルや機能をフルに使おうとするならば、覚えていて損はありません。
一度覚えてしまえば、それほど難しいことは無いと思われます。

今回は、Arduino core for ESP32 ライブラリの libmbedtls.a をコンパイルし直すために使います。

ESP-IDF で、Arduino IDE 環境用に libmbedtls.a をコンパイルする為の準備

では、Arduino core for ESP32 の WiFiClientSecure ライブラリでハングアップした原因の libmbedtls.a ファイルを修正していきます。
ここでは、ESP-IDF で Arduino IDE 環境用に拡張子.a 形式ファイルをコンパイルする方法を説明します。

普通に ESP-IDF でコンパイルするだけでも、拡張子.a 形式ファイルはビルドされるのですが、それを Arduino IDE にコピペしただけでは動作しません。

そこで、Arduino core for ESP32 を ESP-IDF コンポーネント化して、ESP-IDF でコンパイルするという方法を使います。
その方法は、お馴染みの GitHub の以下のリンクページの終わりの方に、Using as ESP-IDF component とあり、そこに掲載されています。

mbedtls_10

これを読んでもイマイチ分からないところがあるので、順番に説明します。

1.ESP-IDF をダウンロード、インストール

私なりにまとめた以下のページを参照してください。
先ほども紹介しましたが、インストールが済んでいたらここは飛ばしてください。

ESP-IDF ( ESP32 開発環境 ) の使い方

2.プロジェクトを作成

ここで、ESP-IDF の examples/protocols フォルダの中にある、https_request をコピペして、プロジェクトを作成します。
私の場合は、プロジェクトは d:\msys32\home の中に作成していますので、そこへコピペしてください。
このhttps_request フォルダが新たに作ったプロジェクトフォルダになります。

mbedtls_11

3.プロジェクトフォルダ内に components フォルダを作成し、Arduino – ESP32 をダウンロードする

次に、先ほどコピペした https_request フォルダ内に、components フォルダを作成します。
ESP-IDF では、components フォルダにいろいろなアイテムが入っています。
要するにプラグインやライブラリみたいな役割をするものを入れるフォルダです。
下図の様に作成します。
(もちろん、MSYS2 コマンドラインで mkdir コマンドで作成しても良いです)

mbedtls_12

次に、MSYS2 ( mingw32.exe または mingw64.exe )を起動して、cd コマンドで components フォルダまで移動します。
ここでは、

cd /d/msys32/home/https_request/components

と入力してエンターを押します。

mbedtls_13

次に、git clone コマンドを使って、Arduino core for ESP32 をダウンロードします。
(GitHub から ZIP ファイルをダウンロードして解凍しても良いと思います)

git clone https://github.com/espressif/arduino-esp32.git arduino

このコマンドを打つと、components フォルダに arduino フォルダが作成され、そこにダウンロードされます。

因みに、コマンドをコピペしたい場合はショートカットキーを使わず、Windows の場合は右クリックでコピペしてください。
mbedtls_14

Enter すると、ダウンロードが始まり、完了すると下図の様になります。
mbedtls_15

実際にフォルダを見てみると、ダウンロードされているのが分かると思います。
mbedtls_16

この後は get.exe を実行する必要はありません。
そのままでOKです。

これで、ESP-IDF で make menuconfig 画面で、Arduino IDE 用の設定ができるようになります。

menuconfig で、mbedtls と Arduino の設定をする

では、https_request ファイルをコンパイルする前に、menuconfig 画面でコンパイルビルドのオプション設定をしていきます。
ここに mbedtls の MPI ハードウェアアクセラレーション設定や、Arduino IDE 設定をすることができます。
先ほどやったように、components フォルダに Arduino – ESP32 をダウンロードすると、menuconfig 画面で Arduino 設定項目が表示されるようになるわけです。

下図の様に、先ほどのMSYS2 画面の続きで、

cd ..

というコマンドを打ち、https_request フォルダに移動します。

mbedtls_20

次に、

make menuconfig

というコマンドを打ちます。

mbedtls_21

しばらくすると下図の様な画面になります。
ちょっとフリーズしたような間がありますので、辛抱強く待ってください。

mbedtls_22

矢印カーソルキー[↓] で下図の様に Component config にカーソルを持っていき、Enter します。

mbedtls_23

次に、下図のように Arduino Configuration にカーソルを合わせ、Enter します。

mbedtls_24
(この、Arduino Configuration という項目は、プロジェクト内のcomponents フォルダに Arduino-ESP32 がインストールされていると表示されるものです。ただ単に ESP-IDF だけ使っていたらこの項目は表示されません。)

次に下図の様に
Autostart Arduino setup and loop on boot (メインにloop 関数を使う)
Disable mutex locks for HAL (HAL mutex locks を無効にする)
のところでキーボードの[Y]キーを押して、チェックをいれます。
Autostart Arduino は有効にしておかないと、Arduino でコンパイルが通りません。
HAL mutex locks については私はよく知りませんが、これは無効にしておいた方がよさそうです。

mbedtls_25

次に[Esc]キーを2回連続で押すか、<Exit> を選んで、前の画面に戻ります。
ここで保存しなくても、最後に保存すれば良いです。
そうしたら、下図の様にESP32-specific にカーソルを合わせ、Enterします。

mbedtls_26

次に、CPU frequency (160 MHz) にカーソルを合わせ Enter します。

mbedtls_27

そうしたら、下図のように ESP32 の CPU クロック周波数をご自分の好きな Hz に合わせて Enterキーを押せば反映されて、前の画面に戻ります。
ただ、今回の場合は libmbedtls.a ファイルをコンパイルすることが目的なので、あまり意味ないかもしれませんが、念のためやっておきます。

mbedtls_28

すると自動的に前の画面に戻り、下図の様に 240 MHz に反映されていることがわかります。

mbedtls_29

次に、[Esc]キーを2回連続で押すか、<Exit> を選んで、前の画面に戻り、下図の様に FreeRTOS にカーソルを合わせ Enter します。

mbedtls_30

ESP32 の CPU をデュアルコア(マルチタスク)で動かす場合が多いと思いますので、下図の様にチェックが外れているか確認してください。

mbedtls_31

次に、[Esc]キーを2回連続で押すか、<Exit> を選んで、前の画面に戻り、下図の様に mbedTLS を選択して Enter します。

mbedtls_32

ここからが今回の最も重要な点です。
下図の様に、mbedTLS のハードウェアアクセラレーションのチェックを外してください
最近のIDF ではデフォルトで外れています。

ここの文章でも書いてありますが、「buggy」とありますね。
要するに、バグが多いらしいので、今はまだ使うべからずです。

mbedtls_33

以上で menuconfig の設定が終わりなので、下図の様に矢印カーソルキー[→]で <Save>に合わせて Enter します。

mbedtls_34

すると、下図の様になるので、OKします。

mbedtls_35

すると下図の様になり、保存完了です。

mbedtls_36

その後、[Esc]キーを2回連続で押すか、<Exit> をひたすら Enter して、画面を抜けると下図の様にconfigファイルが make されます。

mbedtls_37

以上、menuconfig 設定でした。
このように、Arduino components を作ることによって、Arduino IDE 用の設定ができるので、今後様々なところで応用ができるかもしれません。

make コマンドでコンパイルして、新たな libmbedtls.a ファイルを作成する

では、いよいよコンパイルです。

先ほどのMSYS2 画面に続いて、make コマンドのみ打ち込んでコンパイルします。

mbedtls_40

そうすると、下図の様にエラーメッセージが出ると思います。
コンパイルは2分くらいかかりますので、あまりにも早く終わったら明らかにエラーです。

mbedtls_41

エラーが出ると、libmbedtls.a ファイルは作成されません。
このメッセージを見てみると、https_request フォルダの中の SimpleBLE ライブラリに必要なファイルが無いのでエラーになっているというメッセージです。

今回は Bruetooth は使いませんので、このライブラリをフォルダごと削除してしまいます。

mbedtls_42

その後、再度、MSYS2 画面で make コマンドを実行してみてください。
下図の様にエラーメッセージが無ければ成功です。
結構長い時間(約2分)かかりました。

mbedtls_43

では、下図の様にhttps_request フォルダの中に build フォルダが形成されていて、その中に mbedtls フォルダがあります。
パスはこんな感じです。

D:\msys32\home\https_request\build\mbedtls

そこに、libmbedtls.a ファイルが作成されていれば成功です。

mbedtls_44

Arduino core for ESP32 ライブラリを修正する

では、新たに作った、libmbedtls.a ファイルを本来の Arduino core for ESP32 のライブラリと入れ替えます。

Windows10 の場合の Arduino core for ESP32 の libmbedtls.aフォルダパスは以下のようになります。

C:\Users\User-Name\Documents\Arduino\hardware\espressif\esp32\tools\sdk\lib

そこに、下図の様にコピペ上書きして、置き換えてください。

mbedtls_50

次に、下図の様に本来の Arduino core for ESP32 ライブラリ中の sdkconfig.h ファイルをテキストエディタで修正します。
パスは以下のところにあります。

C:\Users\User-Name\Documents\Arduino\hardware\espressif\esp32\tools\sdk\include\config

mbedtls_51

下図の様に、ハードウェアアクセラレーター関係を全てコメントアウトして保存してください。
合計4つあります。

line  48: #define CONFIG_MBEDTLS_MPI_USE_INTERRUPT 1
line  85: #define CONFIG_MBEDTLS_HARDWARE_AES 1
line 106: #define CONFIG_MBEDTLS_HARDWARE_SHA 1
line 126: #define CONFIG_MBEDTLS_HARDWARE_MPI 1

mbedtls_52

Arduino core for ESP32 のライブラリ設定は以上です。
ですが、実はこれだけでは動作しないんですね。

次に進みます。

Arduino メインループのスタックメモリを増やす

いよいよ、最後の設定です。

ライブラリを修正しただけでは、コンパイルは通りますが、HALTエラーになってしまって動作しません。

そこで、下図の様に、Arduino IDE のメインloop 関数のソースコードをテキストエディタで開いて下さい。
パスは以下のところにあります。

C:\Users\User-Name\Documents\Arduino\hardware\espressif\esp32\cores\esp32

mbedtls_53

そして、下図の様に 25行目の数値を2倍の 8192 に書き換えて上書き保存してください。

mbedtls_54

このmain ソースを見てみて、ピンと来た方がいると思います。
なんと、Arduino – ESP32 のメインloop 関数は FreeRTOS を使っていて、既にデュアルコア(マルチタスク)で動作できるようになっていますね。

最初の方で紹介した、けりさん ( @Ryokeri14 )の以下のブログ記事でも述べられていましたね。

ESP32でデュアルコアを使おう!

ということで、Arduino core for ESP32 は初めのころからデュアルコア(マルチタスク)で動作させる前提で作られていたということです。

これに気付いてから、私も最近では ESP32 を Arduino でデュアルコアで動作させる実験をするようになりました。
デュアルコアで動かすと、ESP32 ( ESP-WROOM-32 ) のポテンシャルが凄すぎて、ヤバイです。

ということで、以上で Arduino core for ESP32 の WiFiClientSecure ライブラリの修正は終了です。
全てが済んだら、Arduino IDE を必ず再起動してください

これで、今までの SSL ( https )ページとコネクションするスケッチをコンパイルし直してみて下さい。
サクサク感が全然違いますよ!!!

Web GETリクエストも1000回連続でやってもフリーズは一切しなくなります。
スバラシイ!!!

まとめ

以上、WiFiClientSecure ライブラリの修正でしたが、うまく動作しましたでしょうか?

この修正方法ができるようになると、機能豊富な ESP-IDF と連携させて Arduino IDE ライブラリの機能をアップさせることも可能な気がします。

今回の件は、本家 Espressif Arduino core for ESP32 の issue ページで質問を投げかけていますので、もしかしたら近い将来修正されるかもしれません。

最近は ESP32 をArduino IDE でコンパイルして、デュアルコア(マルチタスク)で動かしていますが、その実験中に今回のライブラリ修正方法を思いついた感じです。
とても良いヒラメキを与えてくれた、「けり」さんの記事に感謝します。

次回は、ESP32 電光掲示板をマルチタスクで動かして、文字がスクロール中に停止することなく裏で Web記事を取得する方法を紹介したいと思います。

長くなりましたが、私も今回で疲れ果てました・・・。
記事を書くのが苦痛です・・・。

ではまた・・・。

mgo-tec電子工作 関連コンテンツ ( 広告含む )

スポンサーリンク

Amazon.co.jp 当ブログのおすすめ







投稿者:

mgo-tec

Arduino, ESP8266, ESP-WROOM-02 等を使って、主にスマホと連携した電子工作やプログラミング記事を書いてます。ライブラリも作ったりしてます。趣味、独学でやってますので、動作保証はしません。 電子回路やプログラミングの専門家ではありません。 畑違いの仕事をしてます。 でも、少しだけ電気の知識が必要な仕事なので、電気工事士や工事担任者等の資格は持ってます。

「Arduino – ESP32 WiFiClientSecure ライブラリのハングアップ問題がついに解決!」への2件のフィードバック

  1. 素晴らしい記事をありがとうございます。
    ぜひ参考にさせていただきます。

    1つ質問なのですが、私はESP32をスイッチサイエンスさんで販売されている
    “ESP-WROOM-32ブレイクアウトSD+”を使用しています。
    このボードではSDカードを”SDMMC”というライブラリを使うみたいで”ESP32_SD_ShinonomeFNT Beta ver 1.0″が動作しませんでした。

    できればmgo-tecさんのライブラリにSDMMC版が対応していただけるとありがたいです。

    1. カンパニーさん

      今回も当記事をご覧いただき、ありがとうございます。

      私はスイッチサイエンスさんの委託販売ボード “ESP-WROOM-32ブレイクアウトSD+” は持っておりません。
      MMCライブラリしか対応していないので、敬遠していました。

      MMC については私は使ったことが無いので、これから検討してみたいと思います。
      しばらく時間がかかるかも知れませんので、何卒ご容赦くださいませ。

コメントを残す

メールアドレスが公開されることはありません。

*画像の文字を入力してください。(スパム防止の為)