M5 Stamp P4の価格と購入先
今回使用する M5Stack Stamp-P4(SKU: S013) は、ESP32-P4NRW32を搭載した小型マイコンモジュールです。RISC-Vデュアルコア360MHz、16MB Flash、32MB PSRAMを備えており、国内でも約2,500円で購入できます。
| 購入先 | 価格 | 購入リンク |
|---|---|---|
| スイッチサイエンス(国内) | 2,453円(税込) | 商品ページ |
| M5Stack公式ストア | US$12.95 | 商品ページ |
※価格は2026年10月20日確認時点。送料・為替・在庫状況によって変動します。
日本国内ならスイッチサイエンスで購入するのが手軽です。
なお、Stamp-P4単体にはWi-Fi機能がないため、無線通信を利用する場合は別途C6拡張モジュールなどが必要です。
M5Stamp P4(ESP32-P4)向けに、MMUのないRISC-V上で動くLinuxディストリビューションを作っています。v0.3.2 でカーネルを Linux 7.2.11 に上げ、Wi-・MicroPython まで普通に使えるようになりました。
ここまでのコミットは約250件で、ほぼすべてAI(Claude Code / Devin)と一緒に進めています。この記事では、何ができるようになったか、どう作っているか、どこでハマったかを、AIへの任せ方も含めてまとめます。
リポジトリ: https://github.com/tsuyoshi-otake/m5stamp-p4-c6-linux
できること
| 項目 | 内容 |
|---|---|
| SoC | ESP32-P4(RV32IMAC デュアルコア、360 MHz、MMUなし) |
| メモリ | PSRAM 32 MiB、SPI Flash 16 MiB |
| カーネル | Linux 7.2.11(SMPでビルド。出荷イメージは1コアで起動) |
| Wi-Fi | Stamp-AddOn C6(ESP32-C6)を4ビットSDIOでつなぎ、ESP-Hosted NG で使う |
| ユーザーランド | Buildroot、BusyBox、uClibc-ng、Dropbear SSH、MicroPython v1.22.2 |
| ファイルシステム | ルートは読み取り専用の SquashFS。/home、/root、/var/lib はRAM上の OverlayFS |
電源を入れると10秒ほどで SoftAP(SSIDは m5-XXXX)が立ち上がり、つないだPCから ssh m5@192.168.4.1 でログインできます。SSIDとパスワードは初回起動時に端末ごとに生成されるので、共通のパスワードはありません。
ログインすれば、vi でファイルを編集して python3 で実行する、という普通のLinuxの使い方ができます。
$ ssh m5@192.168.4.1
$ vi hello.py
$ python3 hello.py
逆に、sudo、nano、curl、file などは入っていません。MMUが必要だったり、メモリが足りなかったりするためです。
全体の構成
起動の流れは次のとおりです。ESP-IDFのブートローダーのあとに自作の boot-shim を挟み、PSRAMとSDIOの初期化、CPU1の解放をしてからLinuxに飛びます。
Wi-FiはP4自身ではなく、C6をSDIO経由のWi-Fiコプロセッサとして使っています。Linux側のドライバーは ESP-Hosted NG の esp32_sdio.ko です。
試し方
Releases にある16MBのイメージを、esptool でアドレス 0x0 に書き込むだけです。
gzip -d m5stamp-p4-c6-linux-smp-v0.3.2-16mb.bin.gz
esptool.py --chip esp32p4 --port COM10 --baud 460800 write_flash 0x0 m5stamp-p4-c6-linux-smp-v0.3.2-16mb.bin
C6側は ESP-Hosted NG 1.0.6 が動いている必要があります。起動ログに ESP-Hosted Version: NG-1.0.6.0.1 が出ていれば正しく認識されています。
AIとの進め方
段階に分けて、Issueで管理する
いきなり全部を目指さず、次の順に1つずつ動かしました。
- カーネルが起動する
- シリアルコンソールでログインできる
- C6をSDIO経由のWi-Fiとして認識する
- SSHでログインできる
段階ごとにIssueを立て、AIにはそのIssueの範囲だけを任せます。参考実装(why2025-linux、ESP-Hosted)を読ませて、P4向けに必要な差分を洗い出すところから、Buildroot+Dropbearの構成づくりまでAIに任せました。
実機の確認結果は、日付付きのmdに残す
実機で確かめた結果は、linux/tests/ の下に v0.3.0-feature-checks-2026-10-18.md のような日付付きのMarkdownで残しています。AIは前回の作業内容を覚えていないので、毎回これを読ませてから作業させます。
これを始めてから、同じ失敗を繰り返すことが目に見えて減りました。
モデルは難しさで使い分ける
| 作業の種類 | 使うモデル |
|---|---|
| 単純作業 | Opus 5.5 High、SWE-2 Medium |
| 難しく複雑な問題 | Opus 5.5 Max、SWE-2 Max |
ハマりどころ
1. SSHでコマンドを実行すると固まる(SSH wedge)
一番時間がかかったのがこれです。SSHの対話シェルには入れるのに、ssh m5@host id のようにコマンドを1つ実行したり、セッションを閉じたりした瞬間に、P4が完全に固まります。pingも返らずシリアル出力も止まり、120〜160秒後にウォッチドッグでリセットされる、という症状でした。
SSHを使ったときに起きるので、最初はSDIOやWi-Fi側を疑いました。C6側のバッファあふれ、SDIOホストコントローラーのタイムアウト、Dropbearが送るパケットの連続などです。SDIOの転送方式を変えたり、Dropbearの送信間隔を空けたりしましたが、どれも直りませんでした。SSHを安定させるまでに、2週間と膨大なトークンを使っています。
転機になったのは、Wi-Fiを使わずにP4の中だけで再現させたことです。
ifconfig lo 127.0.0.1 up
dbclient <ユーザー名>@127.0.0.1 id
ループバックだけでも同じように固まったので、SDIOとWi-Fiは原因から外れました。
固まるとシリアルに何も出ないので、リセットされても消えないRTCメモリに、例外発生時のレジスターを残す仕組み(クラッシュカプセル)を入れました。再起動後に読み出すと Load access fault が起きていて、addr2line で追うと、子プロセスの終了時に呼ばれる timerqueue_del() から rb_erase() の中でNULLを読んでいました。
ただ、rb_erase() 自体にバグがあったわけではありません。メモリ上のデータが壊れていたのが原因で、ESP32-P4向けの次の3つの修正で直りました。
| パッチ | 内容 |
|---|---|
0014 |
シグナルハンドラーから戻るときに cause レジスターに -1 を書くと、P4では割り込みの状態が壊れる。P4では 0 を書くようにした |
0015 |
命令キャッシュのフラッシュ処理が、命令とデータで共有のL2キャッシュを書き戻さずに無効化していた。そのため、まだPSRAMに書いていないデータが消えていた |
0016 |
52ビットのタイマー値を32ビットずつ読むときに、途中で下位が桁上がりすると値が飛んでいた。上位を2回読んで一致するまで読み直すようにした |
「ネットワーク操作のあとに固まる=ネットワークの問題」と決めつけないこと、がこの件の一番の教訓です。
2. MMUがないので、メモリが断片化する
MMUがないので、プログラムは連続した物理メモリに読み込む必要があります。動かしているうちにメモリが断片化して、SSHログインやコマンドの実行が nommu: Allocation of length … failed でよく失敗していました。
そこで、プログラムを読み込むための10MBの専用領域(6MB+4MBの2か所)を起動時に確保する方式に変えました(パッチ 0070)。普段使いではほぼ失敗しなくなっています。領域の使用状況は /sys/kernel/easystick/nommu_pool で見られるようにしました。
もう1つ効いたのがBusyBoxの分割です。MMUがない環境の実行形式(bFLT)はプログラムのコード部分を共有できないため、BusyBoxのプロセスは1つあたり約500KBを使います。常駐するデーモン(init、inetd、syslogd、udhcpd)だけを持つ小さなBusyBox(1つ192KB)を別に用意したところ、待機中の空きが約1MB増え、同時に張れるSSHセッションが1つ増えました。
3. Linux 7.2への移植
v0.3.0 でカーネルを 6.18.35 から 7.2.11 に上げました。ボード用のパッチはほぼそのまま移せましたが、MMUなしの環境は上流でテストされていないため、追加で4か所の修正が必要でした。
- プログラム用のメモリ領域の確保を、新しい予約メモリのAPIに対応させた(最初の7.2ビルドは起動途中で止まった)
- MMUなしでの
/dev/memのmmapが動かなくなっていたので直した - プリエンプションの設定を 6.18 と同じ
PREEMPT_NONEに戻した - Wi-Fiドライバーのワークキューに
WQ_PERCPUを指定した
4. デュアルコア(SMP)はまだ実験中
カーネルはSMPでビルドしていますが、出荷イメージは maxcpus=1 で1コアだけで起動しています。2コアで起動すると、2つ目のCPUがタイマーやプロセッサー間の割り込みを受け付けなくなり、システム全体がそれを待って止まることがあるためです。7.2.11 では10回中3回しかまともに起動しませんでした。
カーネルのコマンドラインに isolcpus=1 を付けると、17回中17回起動でき、568秒の連続動作も問題ありませんでした。ただしこの方法では、2つ目のCPUがほぼ使われません。ここが今の一番の課題です。
性能の目安
C6とのSDIOクロックを変えて、家のWi-Fi経由で測った転送速度です。
| SDIOクロック | 生のTCP | SSH |
|---|---|---|
| 5 MHz(初期値) | 300〜330 KB/s | 210〜220 KB/s |
| 40 MHz | 410〜440 KB/s | 約250 KB/s |
40 MHzでは、SSHの速度は360 MHzの1コアで動くDropbearの暗号処理で頭打ちになります。40 MHzは長時間の連続試験をまだしていないので、初期値は5 MHzのままにしています。
学んだこと
- AIは「次に何を確かめればいいか」を出すのがとにかく速い。仮説を出させて、実機で確かめて、結果を記録する、という流れが一番うまく回りました。
- 逆に、実機で何が起きたかは人が正確に伝えないと迷走します。ログや計測値をそのまま渡すのが一番確実でした。
- 確認結果を日付付きのmdに残し、毎回AIに読ませる運用は、長いプロジェクトほど効きます。
今後
次はSMPを進めて、2コアをちゃんと使えるようにします。RISC-VのSMPやMMUなしLinuxの経験がある方、ヒントをいただけるとうれしいです。
この記事のもとになったXのスレッドはこちらです。
参考
- m5stamp-p4-c6-linux(リポジトリ)
- SSH wedge の詳しい調査記録(英語)
- why2025-linux(ESP32-P4のNOMMU Linuxの先行実装)
- Espressif ESP-Hosted

