PlatformIOでESP8266を開発する

PlatformIOのインストール


最近になって、PlatformIOという開発環境の存在を知り ました。
2019年現在、PlatformIO Core(CUI環境)と、PlatformIO IDE(GUI環境)という2つの環境が有ります。
WindowsでPlatformIO IDE + Visual Studio Code(VSC)を使った開発については、色々なところで紹介されています。
今回、Raspberry PiにPlatformIO Coreをインストールして、ESP8266のファームを開発してみました。

なお、PlatformIOのインストールや使い方については、以下のページを大いに参考にさせて頂きました。
ありがとうございます。

https://blog.emattsan.org/entry/2017/12/31/094954


https://dbpro.xyz/5195

https://qiita.com/nanbuwks/items/97af91561abd91046fbc



始めにpipとgitをインストールします。
aptでインストールできるpipは最新とは限らないので、一度古いバージョンを入れてからアップデートします。
$ sudo apt install python3-pip git

$ python -m pip -V
pip 21.1.1 from /usr/lib/python3.8/site-packages/pip (python 3.8)

$ python -m pip install -U pip

$ python -m pip -V
pip 21.1.2 from /home/nop/.local/lib/python3.8/site-packages/pip (python 3.8)

続いてPlatformIOをインストールします。
$ python -m pip install -U platformio

[-U]を付けないとなぜかエラーになります。

次にPlatfromIOの実行ファイルへのパスを追加します。
PlatfromIOの実行ファイルは$HOME/.local/binにあります。
そこで、$HOME/.profileの末尾に以下の1行を追加します。

PATH=$HOME/.local/bin:$PATH

以下のコマンドでパスを有効にします。
$ source .profile



この時点で、アカウントにUSBポートのアクセス権を与えておきます。
これをしないと、ファームの書き込み時にパーミッションのエラーとなります。
ESP8266をUSB経由でホストマシンに接続すると、USBポートを所有しているグループが分かります。
$ ls -l /dev/ttyUSB*
crw-rw-rw- 1 root dialout 188, 0 Oct 29 15:08 /dev/ttyUSB00
$ sudo usermod -a -G dialout ログインユーザ名

一旦ログアウトして再ログインすると、設定が有効になります。



PlatformIOではそれぞれのプログラムはプロジェクトという単位で管理されています。
そこで、プロジェクトのホームディレクトリを作成します。
特に何でもいいですが、私は「platformio」にしました。
このディレクトの中に色々なプロジェクトを作ることになります。
Arduino-IDEでのスケッチブックの保存場所に相当します。

最初のプロジェクトはやはりLチカです。
platformioディレクトの下にproject1のサブディレクトリを作ります。
$ mkdir platformio
$ cd platformio
$ mkdir project1
$ cd project1

今回のターゲットマイコンはNodeMCU 1.0 (ESP-12E Module)です。
そこで、ESP8266のサポートボードを以下のコマンドで調べます。
$ pio boards | grep ESP8266
gen4iod               ESP8266        80MHz     512KB   80KB   4D Systems gen4 IoD Range
huzzah                ESP8266        80MHz     4MB     80KB   Adafruit HUZZAH ESP8266
oak                   ESP8266        80MHz     4MB     80KB   DigiStump Oak
esp_wroom_02          ESP8266        80MHz     2MB     80KB   ESP-WROOM-02
espduino              ESP8266        80MHz     4MB     80KB   ESPDuino (ESP-13 Module)
espectro              ESP8266        80MHz     4MB     80KB   ESPectro Core
espino                ESP8266        80MHz     4MB     80KB   ESPino
espresso_lite_v1      ESP8266        80MHz     4MB     80KB   ESPresso Lite 1.0
espresso_lite_v2      ESP8266        80MHz     4MB     80KB   ESPresso Lite 2.0
esp12e                ESP8266        80MHz     4MB     80KB   Espressif ESP8266 ESP-12E
esp01_1m              ESP8266        80MHz     1MB     80KB   Espressif Generic ESP8266 ESP-01 1M
esp01                 ESP8266        80MHz     512KB   80KB   Espressif Generic ESP8266 ESP-01 512k
esp07                 ESP8266        80MHz     4MB     80KB   Espressif Generic ESP8266 ESP-07
esp8285               ESP8266        80MHz     423.98KB 80KB   Generic ESP8285 Module
heltec_wifi_kit_8     ESP8266        80MHz     4MB     80KB   Heltec Wifi kit 8
nodemcu               ESP8266        80MHz     4MB     80KB   NodeMCU 0.9 (ESP-12 Module)
nodemcuv2             ESP8266        80MHz     4MB     80KB   NodeMCU 1.0 (ESP-12E Module)
modwifi               ESP8266        80MHz     2MB     80KB   Olimex MOD-WIFI-ESP8266(-DEV)
phoenix_v1            ESP8266        80MHz     4MB     80KB   Phoenix 1.0
phoenix_v2            ESP8266        80MHz     4MB     80KB   Phoenix 2.0
sparkfunBlynk         ESP8266        80MHz     4MB     80KB   SparkFun Blynk Board
thing                 ESP8266        80MHz     512KB   80KB   SparkFun ESP8266 Thing
thingdev              ESP8266        80MHz     512KB   80KB   SparkFun ESP8266 Thing Dev
esp210                ESP8266        80MHz     4MB     80KB   SweetPea ESP-210
espinotee             ESP8266        80MHz     4MB     80KB   ThaiEasyElec ESPino
d1                    ESP8266        80MHz     4MB     80KB   WEMOS D1 R1 (Retired)
d1_mini               ESP8266        80MHz     4MB     80KB   WeMos D1 R2 & mini
d1_mini_lite          ESP8266        80MHz     1MB     80KB   WeMos D1 mini Lite
d1_mini_pro           ESP8266        80MHz     16MB    80KB   WeMos D1 mini Pro
wifi_slot             ESP8266        80MHz     4MB     80KB   WiFi Slot
wifiduino             ESP8266        80MHz     4MB     80KB   WiFiduino
wifinfo               ESP8266        80MHz     1MB     80KB   WifInfo
wio_link              ESP8266        80MHz     4MB     80KB   Wio Link
wio_node              ESP8266        80MHz     4MB     80KB   Wio Node
xinabox_cw01          ESP8266        80MHz     4MB     80KB   XinaBox CW01

PlatformIOでサポートしているESP8266のボードがずらずらと表示されます。
esp12e や esp07 などの単体モデルも有ります。
NodeMCU 1.0 (ESP-12E Module)の場合、ボードにnodemcuv2を選びますが、FLASHサイズが同じボードであれば、esp12eでもd1_miniでも構いませ ん。
Arduino-IDEのツールメニューでボードを選ぶのと同じです。

そこで、このボード用に初期設定を行います。
以下のコマンドを実行するとカレントディレクトリに、このボード用のディレクトリやプロジェクトファイルが作られます。
$ pio init -b nodemcuv2

$ tree -a --charset=C
.
|-- .gitignore
|-- include
|   `-- README
|-- lib
|   `-- README
|-- platformio.ini
|-- src
|-- test
|   `-- README
`-- .travis.yml

$ cat platformio.ini
; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:nodemcuv2]
platform = espressif8266
board = nodemcuv2
framework = arduino


こちらの ページからblink.cppのコードをコピペして、blink.cppを作ります。
Arduino-IDEと全く同じ言語仕様です。
この時点で、ディレクトリには以下のファイルができます。
$ vi src/blink.cpp

blink.cppのコードをそのままコピペ

$ tree -a --charset=C
.
|-- .gitignore
|-- include
|   `-- README
|-- lib
|   `-- README
|-- platformio.ini
|-- src
|   `-- blink.cpp
|-- test
|   `-- README
`-- .travis.yml

ここまで、toolchainの類は何もインストールしていません。ただ、ソースをコピペしただけです。
ここからがPlatformIOの素晴らしいところです。
瞬きしないで見ててください。
以下のコマンドを実行すると、コンパイルに必要なtoolchaninなどが、ドサドサと落ちてきます。
$ platformio run
Processing nodemcuv2 (platform: espressif8266; board: nodemcuv2; framework: arduino)
---------------------------------------------------------------------------------------------------------------------------
PlatformManager: Installing espressif8266
Downloading  [####################################]  100%
Unpacking  [####################################]  100%
espressif8266 @ 1.8.0 has been successfully installed!
The platform 'espressif8266' has been successfully installed!
The rest of packages will be installed automatically depending on your build environment.
PackageManager: Installing toolchain-xtensa @ ~1.40802.0
Downloading  [####################################]  100%
Unpacking  [####################################]  100%
PackageManager: Installing tool-esptool @ <2
Downloading  [####################################]  100%
Unpacking  [####################################]  100%
PackageManager: Installing framework-arduinoespressif8266 @ ~2.20402.0
Downloading  [####################################]  100%
Unpacking  [####################################]  100%
CorePackageManager: Installing tool-scons @ ~2.20501.7
Downloading  [####################################]  100%
Unpacking  [####################################]  100%
tool-scons @ 2.20501.7 has been successfully installed!
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif8266/nodemcuv2.html
PLATFORM: Espressif 8266 > NodeMCU 1.0 (ESP-12E Module)
HARDWARE: ESP8266 80MHz 80KB RAM (4MB Flash)
Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF MODES: FINDER(chain) COMPATIBILITY(soft)
Collected 26 compatible libraries
Scanning dependencies...
No dependencies
Compiling .pioenvs/nodemcuv2/src/main.cpp.o
Generating LD script .pioenvs/nodemcuv2/ld/eagle.app.v6.common.ld
Archiving .pioenvs/nodemcuv2/libFrameworkArduinoVariant.a
Indexing .pioenvs/nodemcuv2/libFrameworkArduinoVariant.a
Compiling .pioenvs/nodemcuv2/FrameworkArduino/Esp-version.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/Esp.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/FS.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/FunctionalInterrupt.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/HardwareSerial.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/IPAddress.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/MD5Builder.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/Print.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/Schedule.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/ScheduledFunctions.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/Stream.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/StreamString.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/Tone.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/Updater.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/WMath.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/WString.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/abi.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/base64.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/cbuf.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/cont.S.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/cont_util.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_eboot_command.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_flash_utils.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_i2s.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_main.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_noniso.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_phy.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_postmortem.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_si2c.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_sigma_delta.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_timer.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_waveform.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_wiring.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_wiring_analog.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_wiring_digital.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_wiring_pulse.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_wiring_pwm.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/core_esp8266_wiring_shift.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/debug.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/gdb_hooks.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/heap.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/libb64/cdecode.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/libb64/cencode.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/libc_replacements.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/pgmspace.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/sntp-lwip2.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/spiffs/spiffs_cache.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/spiffs/spiffs_check.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/spiffs/spiffs_gc.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/spiffs/spiffs_hydrogen.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/spiffs/spiffs_nucleus.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/spiffs_api.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/spiffs_hal.cpp.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/time.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/uart.c.o
Compiling .pioenvs/nodemcuv2/FrameworkArduino/umm_malloc/umm_malloc.c.o
Archiving .pioenvs/nodemcuv2/libFrameworkArduino.a
Indexing .pioenvs/nodemcuv2/libFrameworkArduino.a
Linking .pioenvs/nodemcuv2/firmware.elf
Building .pioenvs/nodemcuv2/firmware.bin
Retrieving maximum program size .pioenvs/nodemcuv2/firmware.elf
Checking size .pioenvs/nodemcuv2/firmware.elf
Memory Usage -> http://bit.ly/pio-memory-usage
DATA:    [===       ]  34.2% (used 27980 bytes from 81920 bytes)
PROGRAM: [==        ]  23.7% (used 247900 bytes from 1044464 bytes)
============================================== [SUCCESS] Took 140.25 seconds ==============================================

最後の方で「.pioenvs/nodemcuv2/firmware.bin」のバイナリが作られています。

ここまで来たら、NodeMCUをRaspberryPiにUSBで接続します。
一応、デバイスを確認します。
$ ls /dev/ttyUSB*
/dev/ttyUSB0

今回実行するblink.cppではLチカするポートを以下の様に定義しています。
#ifndef LED_BUILTIN
#define LED_BUILTIN 13
#endif

LED_BUILTINは以下に定義されています。
/home/pi/.platformio/packages/framework-arduinoespressif8266/variants/nodemcu/pins_arduino.h

#define LED_BUILTIN 16

つまりGPIO16をLチカすることになります。
そこで、GPIO16にLEDを繋げて、以下のコマンドを実行します。
$ pio run -t upload

Processing nodemcuv2 (platform: espressif8266; board: nodemcuv2; framework: arduino)
---------------------------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif8266/nodemcuv2.html
PLATFORM: Espressif 8266 > NodeMCU 1.0 (ESP-12E Module)
HARDWARE: ESP8266 80MHz 80KB RAM (4MB Flash)
Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF MODES: FINDER(chain) COMPATIBILITY(soft)
Collected 26 compatible libraries
Scanning dependencies...
No dependencies
Compiling .pioenvs/nodemcuv2/src/blink.cpp.o
Linking .pioenvs/nodemcuv2/firmware.elf
Building .pioenvs/nodemcuv2/firmware.bin
Retrieving maximum program size .pioenvs/nodemcuv2/firmware.elf
Checking size .pioenvs/nodemcuv2/firmware.elf
Memory Usage -> http://bit.ly/pio-memory-usage
DATA:    [===       ]  34.2% (used 27980 bytes from 81920 bytes)
PROGRAM: [==        ]  23.7% (used 247900 bytes from 1044464 bytes)

Warning! Please install `99-platformio-udev.rules`.
Mode details: https://docs.platformio.org/en/latest/faq.html#platformio-udev-rules

Configuring upload protocol...
Looking for upload port...
Auto-detected: /dev/ttyUSB0
Uploading .pioenvs/nodemcuv2/firmware.bin
Uploading 252048 bytes from .pioenvs/nodemcuv2/firmware.bin to flash at 0x00000000
................................................................................ [ 32% ]
................................................................................ [ 64% ]
................................................................................ [ 97% ]
.......                                                                          [ 100% ]
============================================== [SUCCESS] Took 35.53 seconds ==============================================

なんか、ワーニングが出ていますが、ちゃんと書き込めて、GPIO16がLチカします。
非力なRPiですが、たった35秒でコンパイルとボードへの書き込みが終わっています。



Flashへの書き込み時に、この様なワーニングが出ることが有ります。
Warning! Please install `99-platformio-udev.rules`.
Mode details: https://docs.platformio.org/en/latest/faq.html#platformio-udev-rules

また、インストール後、ある程度時間が経過すると、この様なワーニングが出ることが有ります。
Warning! Your `/etc/udev/rules.d/99-platformio-udev.rules` are outdated. Please update or reinstall them.
Mode details: https://docs.platformio.org/en/latest/faq.html#platformio-udev-rules

こ ちらにその回避方法が紹介されていますが、以下のコマンドを実行することでワーニングは出なくなります。
$ sudo apt install curl

$ curl -fsSL https://raw.githubusercontent.com/platformio/platformio-core/develop/scripts/99-platformio-udev.rules | sudo tee /etc/udev/rules.d/99-platformio-udev.rules

$ sudo service udev restart



ここで試しにボードを追加してみます。
以下の2つのボードは、基本的に同じハード構成なので、Arduino-IDEではどちらのボードを選んでも、同じボードに書き込みをすることが で きます。
nodemcuv2         ESP8266        80MHz     4MB     80KB   NodeMCU 1.0 (ESP-12E Module)
d1_mini           ESP8266        80MHz     4MB     80KB   WeMos D1 R2 & mini

そこで、以下のコマンドで、このプロジェクトにd1_miniを追加します。
プロジェクトのiniファイルにd1_miniの環境(environment)が追加されます。
$ pio init -b d1_mini

$ cat platformio.ini
; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:nodemcuv2]
platform = espressif8266
board = nodemcuv2
framework = arduino

[env:d1_mini]
platform = espressif8266
board = d1_mini
framework = arduino

d1_miniの環境を使う場合、LED_BUILTINは以下の定義を使います。

/home/pi/.platformio/packages/framework-arduinoespressif8266/variants/d1_mini/pins_arduino.h

#define LED_BUILTIN 2

このように、環境ごとにLED_BULITENの定義を変えることができます。

d1_minの環境(environment)を指定して書き込みます。
$ pio run -e d1_mini -t upload

今度はGPIO2がLチカします。



環境を指定しないと、iniファイルの上から順にコンパイルされます。
-t uploadが指定されていると、iniファイルの上から順にコンパイルされ、順次書き込みが行われます。
今回はたまたま、nodemcuv2でもd1_miniでも書き込みができるハードを使っているので、
環境を指定しない場合、
@nodemcuv2のコンパイルと書き込み
Ad1_miniのコンパイルと書き込み
が順次行われ、最終的にd1_miniの環境が実行されます。



ESP8266のtoolchainは以下のディレクトに格納されています。
$ ls $HOME/.platformio/packages/toolchain-xtensa/bin
esptool.py                     xtensa-lx106-elf-gcc-ranlib
xtensa-lx106-elf-addr2line     xtensa-lx106-elf-gcov
xtensa-lx106-elf-ar            xtensa-lx106-elf-gdb
xtensa-lx106-elf-as            xtensa-lx106-elf-gprof
xtensa-lx106-elf-c++           xtensa-lx106-elf-ld
xtensa-lx106-elf-cc            xtensa-lx106-elf-ld.bfd
xtensa-lx106-elf-c++filt       xtensa-lx106-elf-nm
xtensa-lx106-elf-cpp           xtensa-lx106-elf-objcopy
xtensa-lx106-elf-ct-ng.config  xtensa-lx106-elf-objdump
xtensa-lx106-elf-elfedit       xtensa-lx106-elf-ranlib
xtensa-lx106-elf-g++           xtensa-lx106-elf-readelf
xtensa-lx106-elf-gcc           xtensa-lx106-elf-size
xtensa-lx106-elf-gcc-4.8.2     xtensa-lx106-elf-strings
xtensa-lx106-elf-gcc-ar        xtensa-lx106-elf-strip
xtensa-lx106-elf-gcc-nm

ちなみにtoolchainのバージョンは以下で確認することができます。
$ $HOME/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-gcc --version
xtensa-lx106-elf-gcc (crosstool-NG 1.20.0) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

続く...