2017年8月13日日曜日

ESP-WROOM-32をMicroPythonで遊ぶ

■うだうだと前書き

猫も杓子もIoTと皆さんが仰るので、その声が大きくなればなるほど自分は遠ざかる方向で生きていたのですが、そうすると完全に煙に巻かれたお爺さんのようになりまして、今は世の中が進んでおるんじゃのぉと言うだけの人です。気付いてみればガレスタさんのDIY日記は素晴らしい勢いで開発を進めており、こんな風に生きてみたいものだと思うようになってきた今日この頃。私も負けて・・・いら・・・れ・・・うぐぐぐぐ・・・パタ。←血を吐いて倒れました。
数か月前、とある都合からESP-WROOM-32(おっ!2017年8月4日にデータシートが更新されている!)を搭載した開発ボード(えぇ、あのねむいさんが激オコの電源に問題のあるですね...)を入手していたのですが、色々な別の開発で忙殺されており全く調査が進んでいませんでした。肝心の「とある都合」もほったらかしでマズイぞ。
さてさて、このESP-WROOM-32は、プロセッサ、フラッシュロム、クロック、アンテナ配線などが集約されたモジュールとして提供されています。加えてメーカーが提供するSDKを使えば、簡単にネットワーク通信可能な小型ソリューションが出来上がるという仕掛け。開発ボードを購入すれば手間をかけずに試すことが出来て、これは面白いですよねー。(棒読み)
ここいらで触っておかないと永遠に触らない事を悟ったので、ホストOSにUbuntu 16.04.3を配備した上で重い腰を上げました。

■事前準備

まずは設定やビルドなどで必要になるパッケージをインストールします。
sudo apt-get install git wget make libncurses-dev flex bison gperf python python-serial vim screen

■ツールチェインの準備

次にツールチェインをダウンロードして適当な場所に置いた上で、パスを通します。 私は/optの配下に配置することにしました。
cd ~/Downloads
wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz
tar xvfz xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz
mv xtensa-esp32-elf /opt/
vi ~/.bash_profile
.bash_profileには以下を追記しました。
export PATH=$PATH:/opt/xtensa-esp32-elf/bin
これで次回ログイン時からパスが通った状態の環境になります。当然ながら、即座に反映させたいときはsource ~/.bash_profileして下さい。

■ESP-IDFの準備

ESP-IDFとは、 Espressif IoT Development Frameworkの略のようです。このフレームワークは、ブートローダからデバイスのペリフェラルドライバまでを包括しており、更にサンプルが上位に加わって、文字通りフレームワークとして使えるように仕立てられています。なるほど。

後々MicroPythonと組み合わせるときに気付く事になるのですが、特定のリビジョンとの組み合わせを要求されますので、git cloneでリポジトリからコードを取り出すことにします。
cd /opt
git clone https://github.com/espressif/esp-idf.git
cd esp-idf
git submodule update --init
これで準備完了。 ESP-IDFは、外部モジュールに盛大に依存していますので、最後のgit submodule update --initをお忘れなく。

■MicroPython ESP32の準備

次にMicroPython ESP32をリポジトリから取り出します。 先のツールチェインとESP-IDFは/optに配置しましたが、こちらはホームの下に作ったProjectsディレクトリにcloneすることにしました。
mkdir ~/Projects
cd ~/Projects
git clone https://github.com/micropython/micropython-esp32.git
cd micropython-esp32/
git submodule update --init
MicroPythonも外部モジュールに依存しています。git submodule update --initをお忘れないようにね!これで一通りの準備が完了!

■フローズンモジュールをビルドする

さて、最初に行うのはフローズンモジュールのビルドです。
cd ~/Projects/micropython-esp32
make -C mpy-cross
以下のような出力が出れば完了です。
LINK mpy-cross
   text    data     bss     dec     hex filename
 133038     776     872  134686   20e1e mpy-cross
これで、MicroPythonのモジュールがビルドされた状態になります。

■本体をビルドする

はじめに、ビルド時に使用する変数を設定してMakefileを呼び出すためのメイクファイルmakefileを作ります。
cd micropython-esp32/esp32
vi makefile
エディタはお好きなものを御利用下さい。makefileは、5つの変数に必要なデータを格納した上でMakefileをインクルードするように記述します。
ESPIDF = /opt/esp-idf/
PORT = /dev/ttyUSB0
FLASH_MODE = dio
FLASH_SIZE = 16MB
CROSS_COMPILE = xtensa-esp32-elf-
include Makefile
最後に本体をビルドして完成です。
cd ~/Projects/micropython-esp32/esp32
make
これで、先ほど作ったmakefileが使われて環境変数が設定された後、Makefileがインクルードされて適切なビルドが行われます。

ビルド時、最初のメッセージにご注目。もしも、ESP IDFがサポート外のバージョンだった場合、以下のようなメッセージが出力されているはずです。
** WARNING **
The git hash of ESP IDF does not match the supported version
The build may complete and the firmware may work but it is not guaranteed
ESP IDF path:       /opt/esp-idf/
Current git hash:   cd5cc9927bf494e759b8bb513de3f4a9312bc4af
Supported git hash: 4ec2abbf23084ac060679e4136fa222a2d0ab0e8
ここで、無理に未知のバージョンで頑張る積極的な理由はないと思いますので、ESP IDFのディレクトリに移動して、Supported git hashに書かれたバージョンをチェックアウトして下さい。

ガチャガチャとビルドが進行し、以下のような出力が出てきたら出来上がり。
LINK build/application.elf
   text    data     bss     dec     hex filename
 703087  194764  138472 1036323   fd023 build/application.elf
Create build/application.bin
esptool.py v2.1-beta1
Create build/firmware.bin
bootloader     13248
partitions      3072
application   897984
total         963520
次にこれを書き込みます。

■フラッシュの消去

フラッシュの消去は、先ほどのmakefileに書き込んだPORTに書かれたデバイスファイルを経由して実行されます。
sudo make erase
実行すると以下のようなメッセージが出力されます。
Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.
Erasing flash
esptool.py v2.1-beta1
Connecting........_
Chip is ESP32D0WDQ6 (revision 0)
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Erasing flash (this may take a while)...
Chip erase completed successfully in 3.3s
Hard resetting...
これでフラッシュが消去されました。次にファームウェアを書き込みます。

■フラッシュの書き込み

フラッシュを消去したら、次にファームウェアを書き込みます。
sudo make deploy
実行すると以下のようなメッセージが出力されます。
Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.
Writing build/firmware.bin to the board
esptool.py v2.1-beta1
Connecting........__
Chip is ESP32D0WDQ6 (revision 0)
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Flash params set to 0x0220
Compressed 959424 bytes to 598202...
Wrote 959424 bytes (598202 compressed) at 0x00001000 in 15.3 seconds (effective 502.5 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting...
あれ?Auto-detected Flash sizeが4MBとなっとる... まぁ、とにかく書き込み出来ました。

■screenで接続してみる

screenコマンドを使ってシリアル接続してみましょう。
sudo screen /dev/ttyUSB0 115200
screenコマンドを終了させたい場合には、CTRL+Aを押してからKを押します。
試しにEnterキーを押してみてください。>>>が表示されていれば動作しています。
>>>
>>>
>>>
>>>
>>> import machine
>>> machine.
__name__        mem8            mem16           mem32
freq            reset           unique_id       idle
disable_irq     enable_irq      time_pulse_us   Timer
Pin             Signal          TouchPad        ADC
DAC             I2C             PWM             SPI
UART
更に「import machine」と打ってから「machine.」まで打ってTABを叩くと入力補間機能が使えます。あぁ、楽しいなぁ。

■物足りないよね?

こんな誰でもやるようなステップを踏んだ記事を読んでイライラしている方、居ますよね。居ます居ます。私もそう。
例えば、「ECO and Workarounds for Bugs in ESP32」を眺めて、Chip Revision 0に対するワークアラウンドがどのように実装されているのか見るのも楽しいでしょう。ESP32のRevision 0には、キャッシュ・メモリ・マネージメント・ユニットのバグによって、パワーアップ時/ディープ・スリープからのウェイク・アップ時に、間違ったウォッチドッグ・リセットが発生してしまいます。


さて、今回私が手にしたモジュールにはRevision 0のデバイスが搭載されていることが、フラッシュの消去と書き込み時の出力「Chip is ESP32D0WDQ6 (revision 0)」からわかっています。つまり、ワークアラウンドがなければ動作しない可能性があるわけです。このバグに対するワークアラウンドは、DPORT_PRO_CACHE_CTRL1_REGにあるPRO_CACHE_MMU_IA_CLRビットを1に設定し、次にそのビットを0にする事とあります。

では、これに対する実装はどこにあるのかというと、先ほどのESP-IDFで実装されているブートローダにあります。私の場合、ESP-IDFを/optの下に配置したので「/opt/esp-idf/components/bootloader/src/main」のディレクトリにあるbootloader_start.cにあります。


あぁ、楽しくなってきた。組み込みシステムのファームウェアというのは、こういう色々な事情を考慮した上で成り立っているんです。ちょっと実装して「あー動いた。終わり。」とか「あー動かないや。終わり。」という世界ではないんです。動いたら動いたで本当に意図した動作で動いているのか確かめる、動かないなら動かないでどこが意図しない動作で動いていないのか確かめる、どっちにしろ確かめるっていう姿勢が大事なんじゃないかと、ESP32にまつわる色々な記事を見ていて少し思いました。少しだけね。

■ここまでのまとめ

  • Ubuntu 16.04.3の環境構築、ビルド、書き込み、動作確認までを一巡させた。
  • 普通に動かす方法だけを書いても面白くないので、一部だけ掘り下げてみた。

■参考文献