はじめに
方言を話す、おしゃべり猫型ロボット「ミーア」を開発中。
前回、こちらの記事で、AWS IoT関連の設定ファイルをLittleFS領域からNVS領域に移動するのを実装した。
ただ、このままだとセキュリティ的に脆弱なので、今回はNVS暗号化の実装を試みようとしたところ、下記記載に遭遇。
https://github.com/espressif/arduino-esp32/issues/9233
Flash EncryptionとSecure BootはArduino IDEでは提供されていないし、今後も提供する予定がないとのことorz
というわけで、まずは、今使用しているArduinoフレームワークからESP-IDFフレームワークヘ変更する必要がある。
ちなみに、現在のplatform.iniファイルでの設定は下記。
; PlatformIO Project Configuration File
; https://docs.platformio.org/page/projectconf.html
[env]
platform = espressif32
framework = arduino
board = esp32dev
今回は、フレームワーク変更をPlatformIOでどのように行うかに関して記載。
下記Espressif公式サイトの説明参照
https://docs.platformio.org/en/latest/frameworks/espidf.html#configuration
下記順番で進めていく
- platform.iniのframeworkにespidfを追加
- CmakeLists.txtファイルをルートとsrcディレクトリに追加
- sdkconfig.defaultsファイルを追加し、arduinoでも起動できるように必要な設定を追加
- arduinoライブラリでesp-idfでも起動するのに必要なものは追加
ESP-IDFフレームワーク概要
CmakeLists.txtファイルとは?
ESP-IDFフレームワークはCMakeというビルドシステムを用いている。
CMakeLists.txtファイルは、CMakeビルドシステムに対してプロジェクトのビルド方法を指示するファイル。ESP-IDFを使用する際、プロジェクトの構成とビルドプロセスを管理するために必要となる。
PlatformIOでESP-IDFを使用するプロジェクトは、通常、以下の構造を持つ。
project_dir/
├── include/
├── src/
│ ├── CMakeLists.txt
│ └── main.c
├── CMakeLists.txt
└── platformio.ini
ルートディレクトリ、srcディレクトリの2つのCmakeLists.txtファイルが存在することがわかる。それぞれの用途と記載方法を見ていく。
ルートディレクトリにあるCMakeLists.txt
プロジェクト全体の設定を行う。一般的に、このファイルには以下のような内容が含まれる。
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16.0)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(project-name)
project-name
は CMake の中で設定するプロジェクトの名前で、これは任意の名前を指定することができる。この名前は、CMake はこの名前を使用してプロジェクト固有の変数を生成し、ビルドプロセスを管理する。
PlatformIO のプロジェクト名は主に PlatformIO の環境内で使用され、CMake の project-name
は CMake と ESP-IDF のビルドシステム内で使用されるので、PlatformIOのプロジェクト名を一致させる必要はないが、一致させた方が可読性が高まる。
srcディレクトリ内のCMakeLists.txt
特定のコンポーネント(この場合はアプリケーションのメインコンポーネント)のビルドプロセスを制御する。最小限の設定では、以下のようにコンポーネントをビルドシステムに登録する
idf_component_register(SRCS "main.c")
これらのCMakeLists.txt
ファイルは、プロジェクトがESP-IDFのビルドシステムを使用して正しくビルドされるために必要。また、追加のコンポーネントや特別なビルド設定が必要な場合には、これらのファイルに対応する設定を追加する。
sdkconfig.defaults
platformio.ini
ファイルは、PlatformIOプロジェクトの主要な設定ファイルであり、プロジェクトのビルド設定、使用するボード、フレームワーク、ライブラリ依存関係などを定義する。
一方、sdkconfig.defaults
はESP-IDF固有の設定ファイルで、ESP-IDFフレームワークの様々な設定を事前に定義できる。システムの動作、機能の有効化/無効化、パフォーマンスのチューニングなどが含まれる。プロジェクトのルートディレクトリに設置する。
ESP-IDFフレームワークの概要を把握したところで、実際に現在の設定を置き換えていく。
platformio.iniの更新:frameworkにespidfを追加
platformio.ini
ファイルのframeworkの部分をarduinoからespidfに変更する。
当初、framework = espidfと指定しなければいけないと思っていたし、公式サイトにもそのように記載されていたのでその手順で進めていた。
その場合、下記作業が発生して、大変になる(実際途中まで進めてしまいかなり大変だった)
Arduinoライブラリの管理:
- Arduinoのライブラリを使用するためには、
components
フォルダ配下にArduinoライブラリを全てgit clone
する必要があり、これにより、プロジェクトのファイル容量が数GBになる可能性がある。
コードの書き換え
- espidfフレームワークを指定してビルドすると、arduinoライブラリ関連は全てエラーが出るので、Arduinoライブラリが
Arduino.h
でインクルードされている部分をすべて書き換える必要がある。
In file included from src/app_config.cpp:1:
src/app_config.h:1:10: fatal error: FS.h: No such file or directory
************************************************************
* Looking for FS.h dependency? Check our library registry!
*
* CLI > platformio lib search "header:FS.h"
* Web > https://registry.platformio.org/search?q=header:FS.h
*
************************************************************
1 | #include <FS.h>
| ^~~~~~
compilation terminated.
Compiling .pio/build/release/src/donwload.cpp.o
In file included from src/button_manager.cpp:1:
src/button_manager.h:1:10: fatal error: Arduino.h: No such file or directory
*****************************************************************
* Looking for Arduino.h dependency? Check our library registry!
*
* CLI > platformio lib search "header:Arduino.h"
* Web > https://registry.platformio.org/search?q=header:Arduino.h
*
*****************************************************************
しかし下記の記述で、PlatformIOでArduinoとESP-IDFのフレームワークを併用することができるとのこと。自分の場合は、途中でこれに気づいて、かなり時間を食ってしまった。
[env]
platform = espressif32 @ 6.7.0
framework = arduino, espidf
このように指定することで、既存の多くのArduinoライブラリを直接利用できるため、コードのポーティングや書き直しの手間を省くことができる。
というわけで、framework = arduino, espidf を設定する。
実際にespidf公式でも、espidfとarduinoをplatform.iniで併用しているexample(blink, wifiscan)が記載されている
CMakeLists.txtの作成(ルート・src)
プロジェクトのルートディレクトリにCMakeLists.txt
ファイルを作成する。以下の内容を記述。
cmake_minimum_required(VERSION 3.16.0)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(clocky_platformio) #プロジェクト名
src
フォルダにもう1つのCMakeLists.txt
ファイルを作成する。以下の内容を記述。
file(GLOB_RECURSE app_sources *.cpp)
idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "."
INCLUDE_DIRS "json"
)
まず、ワイルドカードを使ってsrc
ディレクトリ内のすべての.cpp
ファイルをビルド対象として指定する。
file
: CMakeの組み込みコマンドで、ファイルシステムの操作を行う。GLOB_RECURSE
: ファイルパターンを再帰的に検索するオプション。ディレクトリとそのサブディレクトリを再帰的に検索し、指定されたパターンに一致するファイルを見つける。app_sources
: 検索結果を格納する変数の名前。この変数には、見つかったファイルのパスが格納される。
というわけで、以下のコードを実行すると、src
ディレクトリおよびそのサブディレクトリ内のすべての.cpp
ファイルを検索し、それらのパスをapp_sources
変数に格納する。
file(GLOB_RECURSE app_sources *.cpp)
また、INCLUDE_DIRS "."
により、src
ディレクトリ内のヘッダーファイルがインクルードパスに含まれる。同様に、jsonサブディレクトリをビルド対象に含めたいので、INCLUDE_DIRS “json”と追加する。
file(GLOB_RECURSE app_sources *.cpp)
idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "."
INCLUDE_DIRS "json"
REQUIRES esp-idf)
sdkconfig.defaultsの作成
ESP-IDFでは、必要な設定をsdkconfig.defaults
に記載することで初期設定を行うことができる。
新規にsdkconfig.defaults
ファイルをプロジェクトのルートディレクトリに作成し、下記を記載する
CONFIG_AUTOSTART_ARDUINO=y
CONFIG_FREERTOS_HZ=1000
CONFIG_MBEDTLS_PSK_MODES=y
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
CONFIG_AUTOSTART_ARDUINO=y
- 機能: Arduinoライブラリを自動的に起動する設定。
- 理由: この設定を有効にすることで、ESP-IDFの環境でArduinoのスケッチ(setup()とloop()関数)を自動的に実行できるようになる。つまり、ESP-IDFのデフォルトのapp_main()関数を使用する必要がなくなる。ESP-IDFとArduinoフレームワークを併用する際に、Arduinoのライブラリや関数が適切に動作するようにするために必要。
CONFIG_FREERTOS_HZ=1000
- 機能: FreeRTOSのシステムティックレート(Hz)を1000に設定。
- 理由: デフォルトのシステムティックレートは100Hzだが、Arduinoのスケッチやライブラリは一般的に1msの精度(1000Hz)を前提として動作する。したがって、この設定を行うことで、Arduinoのコードが正確に動作するようにする。
CONFIG_MBEDTLS_PSK_MODES=y
- 機能: mbedTLSでPSK(Pre-Shared Key)モードを有効にする。
- 理由: PSKモードは、事前共有鍵を使用した暗号化通信を可能にする。セキュリティ機能を強化するために、この設定を有効にすることで、PSKを使用した暗号化通信を実装できる。
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
- 機能: mbedTLSでPSKによる鍵交換を有効にする。
- 理由: PSKモードを有効にした場合、PSKによる鍵交換も有効にする必要がある。これにより、事前共有鍵を使った安全な鍵交換が可能になり、セキュリティ通信を確立できる。
MQTT通信でTLS/SSLを使用し、PSKを用いる場合には、CONFIG_MBEDTLS_PSK_MODES
とCONFIG_MBEDTLS_KEY_EXCHANGE_PSK
の設定が必要。
menuconfigでsdkconfigを設定することも可能
ちなみにsdkconfigの設定は、下記でplatformIOでESP-IDFのmenuconfigを開くことで設定も可能
pio run -t menuconfig
下記画面が開くので、設定項目にチェックをつけていく
CONFIG_AUTOSTART_ARDUINO
:「Component config」->「Arduino Configuration」->「Autostart Arduino setup and loop on boot」CONFIG_FREERTOS_HZ
:「Component config」->「FreeRTOS」->「Tick rate (Hz)」
指定項目をチェック後、保存しようとすると保存先のファイルを指定できるので、選択するとファイルに設定が反映される。
もちろん、GUIでの設定が面倒な場合はsdkconfigファイルを直接修正してもよい。
LittleFSリンカーエラー対応
上記設定でビルドすると、LittleFSリンカーエラーが発生した
Linking .pio/build/debug/firmware_debug.elf
/Users/ky/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch5/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/debug/src/main.cpp.o:(.literal._Z11setupCommonv+0x24): undefined reference to `fs::LittleFSFS::begin(bool, char const*, unsigned char, char const*)'
ESP-IDFとArduinoの両方のフレームワークを使用している場合に、ArduinoのLittleFSライブラリが正しくリンクされていないことが考えられる。
同じような問題に直面している人を発見。
https://github.com/platformio/platform-espressif32/issues/965
Componentsフォルダにesp_littlefsライブラリを追加→失敗
littlefsライブラリのクローン
プロジェクトのcomponentsフォルダにesp_littlefsライブラリをクローンする。
https://github.com/joltwallet/esp_littlefs.git
mkdir -p components
cd components
git clone --branch v1.14.4 https://github.com/joltwallet/esp_littlefs.git
CMakeLists.txtの修正
プロジェクトのルートにあるCMakeLists.txtファイルを修正してesp_littlefs
ライブラリを含める。
cmake_minimum_required(VERSION 3.16.0)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
list(APPEND EXTRA_COMPONENT_DIRS "${CMAKE_SOURCE_DIR}/components/esp_littlefs")
project(clocky_platformio)
上記でビルドしたところ、リンクエラーが解消されず
components/esp_littlefs/src/esp_littlefs.c:12:10: fatal error: littlefs/lfs.h: No such file or directory
#include "littlefs/lfs.h"
^~~~~~~~~~~~~~~~
compilation terminated.
idf_component.ymlを使用してesp_littlefsライブラリを管理→成功
先ほどの同じ問題に遭遇した人のスレッドで、下記の記載があったのでトライ
Add managed components by adding
idf_component.yml
See as example https://github.com/Jason2866/Arduino_IDF_LittleFS/blob/main/src/idf_component.yml
idf_component.yml
ファイルの作成:
プロジェクトのsrc
フォルダにidf_component.yml
ファイルを作成し、以下の内容を追加。
dependencies:
idf: ">=4.4"
esp_littlefs:
git: https://github.com/joltwallet/esp_littlefs.git
CMakeLists.txtの修正:
プロジェクトのルートディレクトリにあるCMakeLists.txt
ファイルを修正し、managed_components
フォルダをビルドシステムに追加する。
cmake_minimum_required(VERSION 3.16.0)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
list(APPEND EXTRA_COMPONENT_DIRS managed_components)
project(clocky_platformio)
managed_components
フォルダが生成されるのは、idf_component.yml
の仕様によるもの。生成されるのはcomponents
フォルダではない。これは、ESP-IDFのコンポーネント管理システムが依存関係を自動的にダウンロードして配置するためのフォルダ。
idf_component.yml
を使用することで、ESP-IDFのビルドシステムは依存関係を自動的に管理し、必要なライブラリを正しいバージョンでダウンロードして配置したのか?明確な理由は不明だが。
祈るような気持ちでcompileが終わるのを待つ。
ようやくCompileエラーをクリア!
無事ビルド完了するも、、
無事ビルドできた!
ここまでくるのに、正味15時間以上かかったのでは?orz
ファイル数が多くなってきたので、C++のコンパイルに時間がかかるようになり、エラーを1つずつ解消すると、少しずつコンパイル進むのだが、より後のコンパイルでエラーがある場合は表示されるようになるので、待機時間が長く、「よしこの修正で次こそは!」と思っても最後の方でコンパイルエラーが発生するとガックリというのを繰り返した。。
と思ったら、Wifi接続後のMQTT通信後に下記エラーが発生。
***ERROR*** A stack overflow in task loopTask has been detected.
一難去って、また一難。上記エラーの解消記事はこちら