PlatformIOで最新のArduino-ESP32を使ってみた
手軽にマイコンを使った開発を体験することのできる環境としてArduinoが有名である。Arduinoは、ハードウェアとしてのArduinoボードだけでなく、抽象的なコードと操作だけでの開発を可能にする様々なソフトウェア要素と組み合わせて構成されている。Arduino IDEはそのようなソフトウェア環境をまとめて提供するものであり、また、ソフトウェア要素のセットであるボードパッケージを追加することで、Arduinoボード以外のボードや単品のマイコンでもArduinoと同様の使用感での開発を可能にする機能もある。一方で、エディタとしての機能は貧弱で、VSCodeなどのちゃんとしたエディタよりも書き心地は劣る。以前はVSCodeでArduino IDEと同等の機能を使える拡張機能が存在したが、現在は廃止されてしまっている。
有名なマイコンの開発環境として、PlatformIOというのもある。PlatformIO自体はエディタを持たず、VSCodeと連携することができ、使い心地はArduino IDEよりも優れている。PlatformIOもArduino IDEと同様にソフトウェア要素のセットである「プラットフォーム」を定義することで、Arduino環境を含む様々な環境向けの開発を可能にしている。しかし、標準のESP32向けプラットフォームでは、古いバージョンのArduino環境が使われてしまう。新しいArduino環境の使い方は少し調べれば出てくるが、それをすると何がどうなるのか、というところまで踏み込んだ説明はあまり見当たらなかったので、まとめてみることにした。
Arduino-ESP32とは
Arduino IDEではボードパッケージとしてArduino-ESP32を追加することでESP32向けの開発を行うことができるが、これはEspressifが公式に提供しているものである。ボードパッケージには、digitalWrite()のようなArduino APIの実装、gccなどのビルドツールやesptoolのような書き込みツール(の入手先)とその使い方、などが含まれており、抽象化レイヤのようなものだとも言える。
実装されているAPIには、Arduino APIだけでなく、ESP32固有の機能を簡単に使うためのAPIも含まれている。たとえば、赤外線リモコン信号の送受信に特化したモジュールであるRMTの操作も簡略化されている。
Arduino-ESP32にはいくつかバージョンがあり、特にESP32固有のAPIについてはバージョンによって仕様が異なっているものもある。また、新しいチップに対応していたり、APIが変わっていないものでも実装が改善されている可能性もある。実装に使われるフレームワークであるESP-IDFのバージョンも変わってくる。たとえば、Arduino-ESP32 v2.0.17はESP-IDF v4.4.7ベースだが、v3.x系ではv5.x系ベースである。固有APIについても、ESP-IDFでの仕様が変更されたことに伴なってか、Arduino-ESP32 v3.x系でも変更が加えられている。
なお、Arduino-ESP32は常に最新版を使うことが想定されているのか、Webの公式ドキュメントではバージョンを指定することができない。GitHubの過去のコミットにあるソースを参照することで情報を得ることができる。旧バージョンに限った話ではないが、情報量が乏しい項目もあり、その場合はソースコード上のコメントやスケッチ例が参考になる。
PlatformIOのプラットフォームとは
PlatformIOでのボードパッケージに相当するものが「プラットフォーム」である。Arduino環境においては、Arduinoのボードパッケージと同じような情報をPlatformIO向けに書き直したようなものとなっているが、API実装についてはArduinoのボードパッケージ内のものを参照する形になっている。AVRマイコン(を搭載するArduinoボードを含む)向けのArduinoCore-avrやATTinyCoreを参照するプラットフォームや、ESP32シリーズ向けのArduino-ESP32を参照するプラットフォームなどがPlatformIO公式から提供されている。
今回問題になっているのがこの公式提供のESP32向けプラットフォームであり、EspressifとPlatformIOとの間で何やら対立があったらしく、参照するArduino-ESP32のバージョンが古いまま(v2.0.17)となっている。最新のv3.xとは上記に述べたような違いがあり、無印ESP32など従来のマイコンをArduinoボードの代わりとして使うだけならば特に気にならないが、新しいESP32シリーズを使ったり、ESP32固有の機能を使ったりする場合やESP-IDFも併用する場合には問題が出てくる可能性がある。
pioarduino版プラットフォーム
「公式提供の」ESP32向けプラットフォームが問題なのであれば、非公式のESP32向けプラットフォームを使えばよい。PlatformIOのESP32(とESP8266)特化のフォークとしてpioarduinoなるものがあり、本家PlatformIOを差し置いてArduino-ESP32の公式ドキュメントで紹介されている。pioarduinoは独自で最新のArduino-ESP32を参照するESP32プラットフォームを有しているが、これをPlatformIOでも利用することができる。あくまで公式実装の参照であってpioarduinoが実装しているわけではないため、非公式だからとAPI実装の品質を心配する必要はない。
これの使い方は様々な記事で紹介されている通りで、これまでplatform = espressif32としていたところを公式ドキュメントに従ってGitHubのURLに変更するだけで利用できるようになる。なお、斜め読みしたり適当なブログ記事を読んだりして「はいはいGitHubのURLね」とか思ってリポジトリのルートのURLを指定すると安定版でないものが使われてしまうので注意。
pioarduino版のパッケージ名(?)は公式と同じであるため、一度pioarduino版がインストールされるとこれが最新版として扱われるようになり、platform = espressif32に戻してもこちらが使われ続けてしまう。公式版に戻すためにはplatform = espressif32@^6などとバージョン指定するか、platform = platformio/espressif32と提供元を明示的に指定する必要がある。プラットフォームやフレームワークにどれが使われているかはpio pkg listで確認できる。
余談: ESP-IDFとの併用
ESP-IDFをメインとして、Arduino-ESP32をESP-IDFのコンポーネントとして読み込むような使い方もできるらしい。PlatformIO流のframework = espidf, arduinoと記述する方法では、純正プラットフォームではESP-IDFのほうが古いArduino-ESP32に合わせてv4.4.7になってしまう。pioarduinoでは最新版の組み合わせになるが、依存コンポーネントらしきものがmanaged_componentsディレクトリにぶちまけられてカオスになる。framework = espidf(純正プラットフォーム定義でも最新版のESP-IDFが使われる)とした上でESP-IDF流の方法で読み込むこともできるが、IDF Component ManagerがPlatformIO環境では使えないっぽいため、プロジェクト内にArduino-ESP32をcomponentsディレクトリを作成して直接配置する方法をとる必要があり、この方法でもmanaged_componentsは発生する。なお、いずれの方法でも、手動でCONFIG_FREERTOS_HZ=1000を設定しないとpio run -t menuconfig(設定用のTUIツール)すら動作しないという罠がある。
あとがき
RMTを使った赤外線リモコン信号の送信機を作る記事を書いていたところ、Arduino-ESP32のバージョン差についてだけで記事が一本書ける量になってしまったので切り出してみた。Arduino IDEと歩調を合わせられるほか、RMTに限らず色々と改善されているものと思われるので、PlatformIOでESP32を使う場合はpioarduino版プラットフォームを試してみるとよいかもしれない。