Open11

PlatformIO Tips

さいとてつやさいとてつや

ビルドの開始前に必要なファイルをコピーするextra_scriptsの設定

実機のファイルシステム(LittleFSなど)にコピーするファイルをdataフォルダに置きたいが,ビルドする対象によってファイルを変えたい場合などに使える。

copy_fiie.pyスクリプトを用意する。

copy_file.py
Import("env")

import os
import shutil

file_from = os.path.normpath(env.GetProjectOption("custom_copy_file_from"))
file_to = os.path.normpath(env.GetProjectOption("custom_copy_file_to"))

print("Copy %s to %s" % (file_from, file_to))
shutil.copyfile(file_from, file_to)

platformio.iniに以下の設定を追加。ファイルの相対パスはプロジェクトディレクトリが起点になる。ここではscripts/copy_file.pyに置くことを想定している。

platformio.ini
[env:sample]
custom_copy_file_from = examples/Deepest/sound-effect-bin.wav
custom_copy_file_to = data/sound-effect.wav
extra_scripts = pre:scripts/copy_file.py

preを指定しているので,ビルドを実行してすぐにスクリプトが起動する。

Processing example (platform: espressif32@6.3.2; framework: arduino; board: m5stack-atom)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
Copy examples\Deepest\sound-effect-bin.wav to data\sound-effect.wav # スクリプト実行
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/m5stack-atom.html
PLATFORM: Espressif 32 (6.3.2) > M5Stack-ATOM
HARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash
DEBUG: Current (cmsis-dap) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES:
さいとてつやさいとてつや

ファームウェアにバイナリを埋め込む

WAVやMP3などに音源ファイルを利用する際,ファイルシステム(LittleFSなど)に置いて読み込んだり,ソースコードに変換してファームウェアに埋め込む手法[1]があるが,PlatformIOのboard_build.embed_filesに指定するとファームウェアの.rodata(Read Only Data)セクションに埋め込むことができる[2]。

platformio.ini
board_build.embed_files = data/sound-effect.wav

ソースコードで参照する場合は,開始位置をasm(_binary_シンボル名_start),終了位置をasm(_binary_シンボル名_end)で取得する。シンボル名は指定した名前の記号をすべて_に置換した形になる。例えば,上の例は開始位置が「_binary_data_sound_effect_wav_start」,終了位置が「_binary_data_sound_effect_wav_end」になる。

sample.cpp
extern const uint8_t SOUND_EFFECT_WAV_START[] asm("_binary_data_sound_effect_wav_start");
extern const uint8_t SOUND_EFFECT_WAV_END[] asm("_binary_data_sound_effect_wav_end");
static const size_t SOUND_EFFECT_WAV_SIZE = (SOUND_EFFECT_WAV_END - SOUND_EFFECT_WAV_START);

ちなみにboard_build.embed_txtfilesを使うとテキストファイルを埋め込むことができる。board_build.embed_filesとの違いは,Null終端が付加されるかどうかである。

参考文献

  1. M5Stack ATOM EchoにWaveファイルを埋め込んで再生する(2020年6月15日 Lang-ship)
  2. Embedding Binary Data(Espressif Systems)
さいとてつやさいとてつや

ファイルシステムにファイルを転送する

SPIFFSやLittleFSなどのファイルシステムにファイルを転送するには,platformio.inienvセクションでdata_dirに指定したフォルダ(デフォルトではdataフォルダ)にファイルを置いて,PlatformIOメニュー(図1)のPROJECT TASKにある「Upload Filesystem Image」を選択する。

platformio.ini
[platformio]
data_dir = data

Upload Filesystem Image図1:PlatformIOメニュー

例えば,/data/hoge.pngをUpload Filesystem Imageを選択して転送すると,プログラムからは/hoge.pngでアクセスできるようになる。

PlatformIO CLIで以下のコマンドを入力してアップロードすることもできる。

pio run --target uploadfs

参考

  1. SPIFFS Filesystem(Espressif Systems)
  2. data_dir(PlatformIO)
さいとてつやさいとてつや

ターミナルからPlatformIO CLIを起動できるようにする

Windows

環境変数PATH%USERPROFILE%\.platformio\penv\Scriptsを追加する。

macOS・Linux

環境変数PATH$HOME/.local/binを追加する。

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

必要なファイルから$HOME/.local/binへシンボリックリンクをはる。

ln -s ~/.platformio/penv/bin/platformio ~/.local/bin/platformio
ln -s ~/.platformio/penv/bin/pio ~/.local/bin/pio
ln -s ~/.platformio/penv/bin/piodebuggdb ~/.local/bin/piodebuggdb

参考

  1. Install Shell Commands(PlatformIO)
さいとてつやさいとてつや

platformio.iniの設定内容を確認する

プロジェクトフォルダ(platformio.iniがあるフォルダ)でpio project configを実行する。-dでプロジェクトフォルダを指定することもできる。

console
$ pio project config --help
Usage: pio project config [OPTIONS]

Options:
  -d, --project-dir DIRECTORY
  --lint
  --json-output
  -h, --help                   Show this message and exit.
console
$ pio project config
Computed project configuration for C:\home\saito\src\the-deepest-offertory-box
platformio
----------
default_envs  =  firmware-release
data_dir      =  C:\home\saito\src\the-deepest-offertory-box\data

env
---
platform                 =  espressif32@6.3.2
platform_packages        =  platformio/tool-esptoolpy@1.40501.0
                            platformio/framework-arduinoespressif32@3.20011.230801
framework                =  arduino
board                    =  m5stack-atom
board_build.f_cpu        =  240000000L
board_build.f_flash      =  80000000L
board_build.mcu          =  esp32
board_build.flash_mode   =  dio
board_build.partitions   =  no_ota.csv
lib_deps                 =  M5Unified@0.1.8
lib_ldf_mode             =  deep
monitor_speed            =  115200
monitor_filters          =  esp32_exception_decoder
                            time
upload_speed             =  1500000
custom_firmware_version  =  0.0.2
custom_firmware_name     =  the_deepest_offertory_box_firmware
custom_firmware_suffix   =  .bin
custom_firmware_dir      =  firmware

tof
---
lib_deps  =  M5Unified@0.1.8
             https://github.com/pololu/vl53l0x-arduino

debug
-----
build_type   =  debug
build_flags  =  -DCORE_DEBUG_LEVEL=4
                -DDEBUG

firmware
--------
build_flags              =  -DDISTRIBUTION_FIRMWARE
board_build.embed_files  =  data/sound-effect.wav
extra_scripts            =  post:generate_user_custom.py

env:firmware-release
--------------------
extends                  =  tof
                            firmware
build_flags              =  -DCORE_DEBUG_LEVEL=3
                            -DDISTRIBUTION_FIRMWARE
custom_firmware_version  =  0.0.2_release
board_build.embed_files  =  data/sound-effect.wav
extra_scripts            =  post:generate_user_custom.py
lib_deps                 =  M5Unified@0.1.8
                            https://github.com/pololu/vl53l0x-arduino
platform                 =  espressif32@6.3.2
platform_packages        =  platformio/tool-esptoolpy@1.40501.0
                            platformio/framework-arduinoespressif32@3.20011.230801
framework                =  arduino
board                    =  m5stack-atom
board_build.f_cpu        =  240000000L
board_build.f_flash      =  80000000L
board_build.mcu          =  esp32
board_build.flash_mode   =  dio
board_build.partitions   =  no_ota.csv
lib_ldf_mode             =  deep
monitor_speed            =  115200
monitor_filters          =  esp32_exception_decoder
                            time
upload_speed             =  1500000
custom_firmware_name     =  the_deepest_offertory_box_firmware
custom_firmware_suffix   =  .bin
custom_firmware_dir      =  firmware

env:firmware-debug
------------------
extends                  =  tof
                            firmware
                            debug
build_flags              =  -DDISTRIBUTION_FIRMWARE
                            -DCORE_DEBUG_LEVEL=4
                            -DDEBUG
custom_firmware_version  =  0.0.2_debug
build_type               =  debug
board_build.embed_files  =  data/sound-effect.wav
extra_scripts            =  post:generate_user_custom.py
board_build.f_cpu        =  240000000L
board_build.f_flash      =  80000000L
board_build.mcu          =  esp32
board_build.flash_mode   =  dio
board_build.partitions   =  no_ota.csv
lib_ldf_mode             =  deep
monitor_speed            =  115200
monitor_filters          =  esp32_exception_decoder
                            time
upload_speed             =  1500000
custom_firmware_name     =  the_deepest_offertory_box_firmware
custom_firmware_suffix   =  .bin
custom_firmware_dir      =  firmware

platformio.iniの設定が正しいかどうか確認したい場合はpio project config--lintを付けて実行する。例えば,platformioセクションでしか指定できないdata_direnvセクションで指定した場合には以下のように表示される。

console
$ pio project config --lint
Warning  Ignore unknown configuration option `data_dir` in section [env]
さいとてつやさいとてつや

extendsで重複した設定項目をマージする

セクションや環境をextendsした際に設定項目が重複すると,設定値がマージされずに後からextendsした値でどんどん上書きされていきます(extendsの説明の「警告」を参照)。

以下の例だとlib_deps1lib_depsの値は,その後にextendsされるlib_deps2lib_depsの値で上書きされます。

platformio.ini
[base]
platform = teensy
framework = arduino
board = teensy31

[lib_deps1]
lib_deps =
    monstrenyatko/ArduinoMqtt @ ^1.5.1
    bblanchon/ArduinoJson @ ^6.18.3
    knolleary/PubSubClient @ ^2.8

[lib_deps2]
lib_deps =
    sstaub/Ticker @ ^4.3.0
    thijse/ArduinoLog @ ^1.1.1
    adafruit/RTClib @ ^1.14.0

[env:final]
extends = base, lib_deps1, lib_deps2
; `lib_deps1`の値は`lib_deps2`の値で上書きされるため,最終的に`lib_deps`は以下と同じになります。
; lib_deps =
;    sstaub/Ticker @ ^4.3.0
;    thijse/ArduinoLog @ ^1.1.1
;    adafruit/RTClib @ ^1.14.0

このとき,extendsで重複する設定値を明示的に指定することでマージすることができます。

platformio.ini
[env:final]
extends = base, lib_deps1, lib_deps2
lib_deps = ${lib_deps1.lib_deps} ${lib_deps2.lib_deps}
; 以下と同じになります。
; lib_deps   =  monstrenyatko/ArduinoMqtt @ ^1.5.1
;               bblanchon/ArduinoJson @ ^6.18.3
;               knolleary/PubSubClient @ ^2.8
;               sstaub/Ticker @ ^4.3.0
;               thijse/ArduinoLog @ ^1.1.1
;               adafruit/RTClib @ ^1.14.0

参考

  1. extends(PlatformIO)
さいとてつやさいとてつや

M5Stackに必要な基本ライブラリ・ツールのバージョン指定方法

バージョン指定は@,指定したバージョン以降の場合は@^で指定する。

2024年3月31日(日)現在の最新版を指定する場合は以下のようになる。

platformio.ini
[env]
platform = espressif32@6.6.0
platform_packages =
    platformio/framework-arduinoespressif32@3.20014.231204
    platformio/tool-esptoolpy@1.40501.0

platformio/espressif32

platformio.ini
[env]
platform = espressif32@6.6.0 ; Espressif 32 v6.6.0

platformio/framework-arduinoespressif32

platformio.ini
[env]
platform_packages = platformio/framework-arduinoespressif32@3.20014.231204 ; arduino-esp32 v2.0.14

platformio/tool-esptoolpy

platformio.ini
[env]
platform_packages = platformio/tool-esptoolpy@1.40501.0 ; esptool v4.5.1
さいとてつやさいとてつや

複数のサンプルプログラムを環境を切り替えてコンパイルする

+-- project
     +-- .pio
     +-- .vscode
     +-- examples
      |    +-- example01
      |     |    +-- main.cpp
      |    +-- exampl02
      |          +-- main.cpp
     +-- include
      |    +-- Hoge.hpp
     +-- src
           +-- Hoge.cpp

上記の構成になっているライブラリでexample01example02をコンパイルできるようにするには,platformio.iniを以下のように指定する。

build_src_filtersrc_dir(デフォルトではsrc)からの相対パスで指定する。

[env]
build_src_filter =
    +<*.cpp> 
    +<*.hpp>

[env:example01]
build_src_filter =
    ${env.build_src_filter}
    +<../examples/examples/example01/main.cpp>

[env:example02]
build_src_filter =
    ${env.build_src_filter}
    +<../examples/examples/example02/main.cpp>
さいとてつやさいとてつや

リンク時にfirmware.mapが見つからないと言われる

ファームウェアをリンクする際にマップファイル(firmware.map)が開けないと言われる。エラーを見るとfirmware.mapが見つからないと表示されている。

Linking .pio\build\m5stack-stamps3\firmware.elf
c:/users/saito/.platformio/packages/toolchain-xtensa-esp32s3@8.4.0+2021r2-patch5/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld.exe: \
cannot open map file C:/Users/saito/デスクトップ/m5stack-platformio-boilerplate-code/.pio/build/m5stack-stamps3/firmware.map: No such file or directory
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\m5stack-stamps3\firmware.elf] Error 1

ソースコードを置いているフォルダのパスにASCIIではない文字(日本語など)やスペースがある場合にPlatfromIOがfirmware.mapを見つけられずにエラーになる。上記の場合,C:\Users\saito\デスクトップという日本語が含まれるパスに置いているため,エラーになっている。

ASCIIではない文字やスペースがない場所にソースコードを置くことで回避できる。

さいとてつやさいとてつや

PlatformIOでinoファイルをコンパイルする

PlatformIOではsrc_dir(デフォルトではsrc)で指定したディレクトリ直下にあるinoファイルのみino.cppに変換してコンパイルするため,Arduinoライブラリのexamplesをコンパイルする場合はsrc_dirをexamples以下にする必要がある。

実際に変換された場合の表示は以下のようになる。

PACKAGES:
 - framework-arduinoespressif32 @ 3.20014.231204 (2.0.14)
 - tool-esptoolpy @ 1.40501.0 (4.5.1)
 - toolchain-riscv32-esp @ 8.4.0+2021r2-patch5
 - toolchain-xtensa-esp32s3 @ 8.4.0+2021r2-patch5
Converting encoder.ino

参考

  1. Arduino IDEとPlatformIO for VSCodeでM5Stack用ライブラリのソースツリーを共有する
さいとてつやさいとてつや

SPIFFSからLittleFSへの移行

特にツールを入れずにファイルイメージを作って実機にアップロードできる。

  1. platformio.ini[env]セクションに以下を追加する。
    [env]
    ...
    board_build.filesystem = littlefs
    
  2. ソース内のSPIFFSLittleFSに置換する。
  3. ファームをビルドしてアップロードする。
  4. PlatformIOメニューからUpload Filesystem Imageを選択するか,コマンドラインからpio run --target uploadfsを実行する。

参考

  1. LITTLEFS_PlatformIOarduino-esp32のGitHubリポジトリにある例)
    ※このやり方は古いので注意
  2. ダイヤル解錠トリガーをSPIFFSからLittleFSに移行した際の差分ダイヤル解錠トリガーのGitHubリポジトリ)