
物理 Linux(Ubuntu 26.04 LTS)マシン上で、 M5版StackChan の公式ファームウェアをビルド・書き込みできるよう環境を整える。
目標は「公式ファームウェアのソースを git で取得し、ビルドして、USB経由で書き込むこと」。
これができれば、自由自在に StackChan をカスタマイズできるようになるはず。
※ 本記事は、M5版StackChanファームウェアのバージョン 1.4.3 時点での情報です
Step 0:前提知識/M5版StackChan ファームウェアの全体像
0-1:OTA アップデートに注意
M5版StackChanは、起動時にサーバ側へアップデート確認しにいき、最新版に自動更新される。
必要に応じて、このあたりの挙動を無効化する設定を入れたファームを書き込むことを頭に入れておく。
これは別記事で触れる予定。
0-2:大方針
StackChan の中身は ESP32-S3 という Wi-Fi/BLE 内蔵のマイコンチップ。Windows/Linuxのような汎用的なOS は載っていない。
代わりにファームウェアが内蔵フラッシュメモリに焼かれている。
M5版のStackChan のファームウェアは C/C++ で書かれている。
今回は ESP-IDF という Espressif 公式の開発フレームワークを使い、ソースコードからクロスコンパイルして、ESP32-S3用のバイナリを生成して、USB(シリアル)経由で書き込む。
ソースコード (.c, .cpp)
↓ ESP-IDF (cmake + ninja + クロスコンパイラ)
バイナリ (stack-chan.bin)
↓ esptool.py (USB シリアル経由)
ESP32-S3 の Flash メモリに書き込み
↓ 電源ON
StackChan が起動
0-3:git リポジトリの構成
公式ファームウェアのリポジトリ (m5stack/StackChan) はこんな構造になっているっぽい。firmware/ だけが ESP32 に焼くファームウェア。残りは別モノ。
m5stack/StackChan/
├── firmware/
│ ├── CMakeLists.txt ← ビルドの設定(プロジェクト名、バージョン等)
│ ├── main/ ← StackChan 本体のソースコード
│ ├── sdkconfig.defaults ← デフォルトのビルド設定
│ ├── repos.json ← 依存ライブラリの定義
│ ├── fetch_repos.py ← 依存を git clone するスクリプト
│ ├── patches/ ← 依存ライブラリへのパッチ
│ └── partitions.csv ← Flash メモリのパーティション定義
├── server/ ← サーバー側のソース
├── remote_controller/ ← リモコンのソース
└── app/ ← モバイルアプリ
0-4:依存ライブラリ (repos.json) の仕組み
StackChan のファームウェアは単独では動かない。AI対話エンジンや UI フレームワークなど、複数のライブラリに依存している。
これらは repos.json に定義されていて、fetch_repos.py を実行すると git clone で取得されるので、あんまり意識する必要はないかも。
xiaozhi-esp32 に独自のパッチを適用して使っているっぽいのだけ把握しておく。
[
{"url": "https://github.com/Forairaaaaa/mooncake.git", "path": "components/mooncake", "branch": "v2.3.3"},
{"url": "https://github.com/78/xiaozhi-esp32.git", "path": "xiaozhi-esp32", "branch": "v2.2.4", "patch": "patches/xiaozhi-esp32.patch"},
...
]
0-5:managed_components(ESP-IDF のコンポーネント管理)
repos.json とは別に、ESP-IDF には Component Manager という仕組みがある。
初回ビルド時に managed_components/ ディレクトリが作られて、追加依存ライブラリなどが自動ダウンロードされる。数百MB あるっぽい。
firmware/
├── components/ ← fetch_repos.py で取得するもの(gitリポジトリ)
│ ├── mooncake/
│ ├── smooth_ui_toolkit/
│ ├── ArduinoJson/
│ └── esp-now/
├── xiaozhi-esp32/ ← AI対話エンジン(パッチ適用済み)
└── managed_components/ ← idf.py build 時に自動ダウンロードされるもの
├── espressif__esp-sr/ ← 音声認識 (WakeNet, MultiNet)
├── lvgl__lvgl/ ← UI ライブラリ
├── espressif__esp32-camera/
└── ...
Step 1:必要パッケージのインストール
とりあえず必要なものを apt install でひたすらいれる。
公式ページにコマンドが載っている ので、これでいいんじゃないかなと。
私の場合は cmake, dfu-util が入っていなかった。
Ubuntuの場合
$ sudo apt-get install git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0
Step 2:ESP-IDF v5.5.4 の git クローン
私は、ホームディレクトリ配下に stackchan-m5 ディレクトリを作り、そこに環境を整えていくことにした。
ESP-IDF は Espressif(ESP32 の製造元)が提供する公式開発フレームワーク。
クロスコンパイラ、ビルドシステム、各種ライブラリ、書き込みツール(esptool)がセットになっている。
私がこの作業を行ったときは、StackChan 公式ファームウェアが ESP-IDF v5.5.4 でビルドされていたので、念のため同じバージョンを持ってくることにした。
サブモジュールも --recursive で一括で持ってくる。全体で約 5 分。
$ cd ~/stackchan-m5
$ git clone -b v5.5.4 --recursive https://github.com/espressif/esp-idf.git esp-idf-v5.5.4
Cloning into 'esp-idf-v5.5.4'...
Receiving objects: 100% (1074981/1074981), 436.94 MiB | 14.85 MiB/s, done.
Resolving deltas: 100% (783212/783212), done.
Step 3:ツールチェーンのインストール
ESP32-S3 用のツールをインストールする。
すべて ~/.espressif/ 以下に配置されるようだ。
$ cd ~/stackchan-m5/esp-idf-v5.5.4
$ ./install.sh esp32s3
Installing tools: xtensa-esp-elf-gdb, xtensa-esp-elf, riscv32-esp-elf, esp32ulp-elf, openocd-esp32, esp-rom-elfs
...
Creating a virtual environment ... done
Installing Python packages ... done
All done! You can now run:
. ./export.sh
Step 4: 環境変数の有効化と確認
ESP-IDF のツールを使うには、毎回 export.sh で環境変数(PATH 等)を設定する必要がある。
$ source ~/stackchan-m5/esp-idf-v5.5.4/export.sh
Activating ESP-IDF 5.5
Setting IDF_PATH to '/home/youruser/stackchan-m5/esp-idf-v5.5.4'.
Done! You can now compile ESP-IDF projects.
$ idf.py --version
ESP-IDF v5.5.4
Step 5:USBシリアル書き込みの設定/dialout グループへの追加
Linux で ESP32 に USB 書き込みするには /dev/ttyACM0 へのアクセス権が必要。
このデバイスファイルの所有グループは dialout なので、そこに自分のユーザーを入れてあげる。
$ sudo usermod -aG dialout youruser
確認:groups youruser を叩いて、dialout に所属していればOK
$ groups youruser
現在のシェルセッションには反映されないようなので、一度ログアウトして、再ログインする。
Step 6:USB 認識確認
Linux マシンと StackChan を USB で接続し、StackChan の電源を入れて、認識確認をする。
$ ls /dev/ttyACM*
/dev/ttyACM0
$ lsusb | grep -i espressif
Bus 003 Device 004: ID 303a:1001 Espressif USB JTAG/serial debug unit
303a:1001 は Espressif の USB ベンダーID:プロダクトID。
ESP32-S3 の内蔵 USB-Serial/JTAG コントローラとして認識された。
Step 7:公式ファームウェアの取得とビルド
ようやく環境が整ったので、ここからが本番。
公式リポジトリのソースを取得して、手元でビルドする。コンパイルさえ通ればこちらのもの!
7-1:ソースの取得
公式リポジトリ (m5stack/StackChan) を ~/stackchan-m5/ 配下に git clone する。
$ cd ~/stackchan-m5/
$ git clone https://github.com/m5stack/StackChan.git stackchan
クローンしたバージョンを確認しておく。
$ cd ~/stackchan-m5/stackchan
$ git log --oneline -1
b72b3ed Merge pull request #100 from m5stack/firmware-dev
$ grep PROJECT_VER firmware/CMakeLists.txt
set(PROJECT_VER "1.4.3")
7-2:依存ライブラリの取得
fetch_repos.py を走らせて、依存ライブラリの取得を行う。パッチ適用もしてくれる。
$ cd ~/stackchan-m5/stackchan/firmware
$ python3 ./fetch_repos.py
Cloning into '.../components/mooncake'...
HEAD is now at 572a7e4 bump version ← mooncake v2.3.3
Cloning into '.../components/mooncake_log'...
HEAD is now at 554d55c Update README.md ← mooncake_log v1.5.0
Cloning into '.../components/smooth_ui_toolkit'...
HEAD is now at 2b20e5c bump version ← smooth_ui_toolkit v2.12.0
Cloning into '.../xiaozhi-esp32'...
HEAD is now at 24f9a09 ... ← xiaozhi-esp32 v2.2.4
Applied patch patches/xiaozhi-esp32.patch ← パッチ適用
Cloning into '.../components/ArduinoJson'...
HEAD is now at e0850a2 v7.4.2 ← ArduinoJson v7.4.2
Cloning into '.../components/esp-now'...
HEAD is now at c33383d Merge branch 'fix/wireless-debug' into 'master'
7-3:ビルド (idf.py build)
いよいよビルドする。
export.sh で環境変数を与えてから、idf.py build でビルドする。
$ source ~/stackchan-m5/esp-idf-v5.5.4/export.sh
$ idf.py build
初回ビルド時のログ(抜粋):
-- IDF_TARGET is not set, guessed 'esp32s3' from sdkconfig
-- App "stack-chan" version: 1.4.3
NOTICE: Processing 60 dependencies:
NOTICE: [1/60] 78/esp-ml307 (3.6.5)
NOTICE: [14/60] espressif/esp-sr (2.3.1)
NOTICE: [53/60] lvgl/lvgl (9.4.0)
...
[2489/2491] Linking CXX executable stack-chan.elf
[2490/2491] Generating binary image from built executable
Successfully created esp32s3 image.
Generated .../build/stack-chan.bin
stack-chan.bin binary size 0x39c4e0 bytes. Smallest app partition is 0x4f0000 bytes. 0x153b20 bytes (27%) free.
Project build complete.
最終的なバイナリサイズは大体 3.6 MiB だった。
初回のビルド時間は managed_components のダウンロード含めて約 5〜8 分。
2回目以降は差分コンパイルになるので 1分くらいで収まる。
Step 8:ビルドしたファームウェアの書き込み
StackChan を Linux マシンに USB 接続した状態として、ビルドしたファームウェアを、USBシリアル経由で書き込む。
所要時間は約 30 秒。
$ idf.py -p /dev/ttyACM0 flash
書き込みログ(抜粋):
esptool.py --chip esp32s3 -p /dev/ttyACM0 -b 460800 write_flash ...
Serial port /dev/ttyACM0
Connecting...
Chip is ESP32-S3 (QFN56) (revision v0.2)
Features: WiFi, BLE
Crystal is 40MHz
USB mode: USB-Serial/JTAG
MAC: XX:XX:XX:XX:XX:XX
Uploading stub...
Running stub...
Changing baud rate to 460800
Changed.
Compressed 23792 bytes to 15336...
Writing at 0x00000000... (100 %) ← bootloader
Wrote 23792 bytes (15336 compressed) at 0x00000000 in 0.2 seconds
Compressed 3785952 bytes to 2127784...
Writing at 0x00020000... (0 %) ← stack-chan.bin
Writing at 0x003b6dbb... (100 %)
Wrote 3785952 bytes (2127784 compressed) at 0x00020000 in 19.3 seconds (effective 1566.2 kbit/s)
Compressed 2298032 bytes to 1028976...
Writing at 0x00a00000... (1 %) ← generated_assets.bin
Writing at 0x00c2dc58... (100 %)
Wrote 2298032 bytes (1028976 compressed) at 0x00a00000 in 10.4 seconds
Hard resetting via RTS pin...
Done
書き込み完了後、StackChan が自動リセットされて、起動してきたら書き込み完了!
おつかれさまでした。