6502tinymachines

どの ESP32 がどの仕事をするか

2026-09-24、pad-ble の C6 が書き込みを受け付けずにいた最中に出た問い: 引き出しに Bluetooth をやる別の部品はあるか、そして、アダプタを電波ではなく電話への USB-C ケーブルにできる部品はあるか。

書いてから。 P4 モジュールはその日のうちに書き込めた。BLE は 2026-09-25 にその上でクラッシュした(ホストのスタックがモジュールの C6 にバージョンを尋ね、C6 は一度も答えない)。組んだのは P4 のフルスピードのコントローラでの USB だ(pad-usb-protocol.md)。そして「まず測る」の項目 4 は 2026-09-27 に、3.3 V の純正パッドと、Linux のホストに届くすべてのキーで閉じた。下の表はベンダのヘッダで、いまも成り立つ。状況を述べた文は、古くなった所に日付を付けてある。

この文書は、記憶ではなくベンダ自身のヘッダからこの問いに答える。一度だけ記憶からこの問いに答えたとき、その答えは別のチップのピン配置だったからだ。

表、測ったもの

Espressif のどの部品も、その能力を soc_caps.h のマクロとして定義している。ターゲットごとに一つのヘッダで、Arduino のコアはそのすべてを同梱する。このワークステーションで、esp32 arduino core 3.3.11 に対して測った:

cd ~/.arduino15/packages/esp32/tools
grep -E '^#define SOC_(USB_OTG|USB_SERIAL_JTAG|BT|BLE|BT_CLASSIC|WIFI)_SUPPORTED' \
    <target>-libs/3.3.11/include/soc/<target>/include/soc/soc_caps.h

空欄はマクロが無いということで、これらのヘッダはそうやって「無い」と言う。能力を定義するのは、シリコンにそれがあるときだけだ。

target     OTG      SER_JTAG BT     BLE    BT_CLASS WIFI
esp32                   1     (1)    (1)      1       1
esp32s2      1                                        1
esp32s3      1          1      1     (1)              1
esp32c3                 1      1     (1)              1
esp32c6                 1      1     (1)              1
esp32h2                 1      1     (1)
esp32c5                 1      1     (1)              1
esp32p4      1          1

部品表として読むと:

チップBLE HIDUSB HID デバイス備考
ESP32 classicはい、Bluetooth Classic もいいえ、USB のブロックがそもそも無いUART ブリッジのみ
ESP32-S2Bluetooth はどの種類も無いはい無線は Wi-Fi だけ
ESP32-S3はいはい両方をやる唯一の部品
ESP32-C3はいいいえシリアル/JTAG のみ
ESP32-C6(手元にある)はいいいえシリアル/JTAG のみ
ESP32-H2はいいいえWi-Fi も無い: BLE と 802.15.4
ESP32-C5はいいいえシリアル/JTAG のみ
ESP32-P4シリコンに無線が無い、下を参照はい、OTG が二つこのベンチのモジュールは無線として C6 を載せている。USB は 2026-09-27 に実証、BLE は初期化でクラッシュする(pad-ble-build.md)

このベンチの基板は P4 モジュールで、それがこの行を変える

2026-09-24、基板自身のシルクから同定した:

ESP32-P4-Module
SoC: ESP32-P4NRW32
WiFi: 802.11 b/g/n/ax
Flash: 16MB

上の表は P4 に無線が無いと言い、ダイについてはそれが正しい。soc_caps.h は P4 に SOC_BLE_SUPPORTED も SOC_WIFI_SUPPORTED も定義しない。モジュールはダイではない。 あのシルクの行が手がかりで、ax がそれを明かす一語だ。Wi-Fi 6 ということは、缶の中にもう一つ Espressif の部品があるということで、コアはその名を挙げている。

同じコア 3.3.11 の tools/esp32p4-libs/3.3.11 で測った:

lib/libbt.a                          NimBLE のホスト、P4 向けにビルドされたもの
lib/libespressif__esp_hosted.a       コプロセッサへのリンク

sdkconfig:
  CONFIG_BT_ENABLED=y
  CONFIG_BT_NIMBLE_ENABLED=y
  CONFIG_BT_CONTROLLER_DISABLED=y     ローカルのコントローラは無い、正しい
  CONFIG_ESP_HOSTED_ENABLED=y
  CONFIG_ESP_HOSTED_CP_TARGET_ESP32C6=y
  CONFIG_ESP_HOSTED_IDF_SLAVE_TARGET="esp32c6"
  CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE=y
  CONFIG_ESP_HOSTED_NIMBLE_HCI_VHCI=y
  CONFIG_ESP_HOSTED_SDIO_HOST_INTERFACE=y

つまり配置はこうだ: Bluetooth のホストスタックは P4 で走り、無線は SDIO 越しに届く ESP32-C6 だ。 ローカルには制御するものが無いのでコントローラはローカルでは無効になっていて、HCI は代わりにホステッドのリンクへ出て行く。

Arduino の BLE クラスが自身の門でそう言っている

これは「動くかもしれない」という推測ではない。コアの BLE ヘッダは二本の腕を持つ条件を掲げていて、二本目の腕がまさにこの場合だ:

libraries/BLE/src/BLEDevice.h:36     #if defined(SOC_BLE_SUPPORTED) || defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE)
libraries/BLE/src/BLEHIDDevice.h:36  #if defined(SOC_BLE_SUPPORTED) || defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE)
libraries/BLE/src/BLESecurity.h:34   #if defined(SOC_BLE_SUPPORTED) || defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE)

この三つのヘッダが、このプロジェクトのファームウェアが取り込む三つだ。

pad-ble は手を入れずに P4 向けにコンパイルできる

決着をつけた試験、2026-09-24 実施:

arduino-cli compile --fqbn esp32:esp32:esp32p4 firmware/pad-ble

Sketch uses 791942 bytes (60%) of program storage space.
Global variables use 26564 bytes (8%) of dynamic memory.

pad-ble.ino も keymap.h も一行も変えていない。同じスケッチが C6 のフラッシュの 56%、P4 のパーティションの 60% だ。

コンパイルは実行ではない。 これが証明するのは、このターゲットにクラスが存在しリンクできることだ。無線については何も証明しない。無線は二つ目のチップで、このワークステーションは一度もそれと話していないからだ。

ピンはぶつからない、これは自明ではなかった

ホステッドのリンクはただではない。P4 側の実際の GPIO を占め、それはモジュールの配線で固定されていて、選べない。

SDIO、C6 へ          GPIO 14、15、16、17、18、19
C6 のリセット        GPIO 54
ブートのストラップ   GPIO 35 (BOOT_MODE)、GPIO 36 (BOOT_MODE2、プルアップ)
コンソール UART      GPIO 37 (TX)、GPIO 38 (RX)

pad-ble が使うのは GPIO 2、3、6、10、11。どれも上には現れないので、パッドの配置はそのまま持ち越せる。C6 のストラップピンを避けるように選んだときと同じだ。これは設計ではなく運で、配線の前に基板自身の露出したヘッダに対して確かめ直す価値がある。

まだ分かっていないこと

  • 上の SDIO のピン配置はコアの既定値で、Espressif 自身の P4 基板向けに書かれたものだ。別のモジュールは二つの部品を別の配線でつないでいるかもしれない。BLE が初期化してコントローラを見つけられなければ、これが最初の容疑者で、配線の不具合ではなくビルド時の設定だ。
  • C6 は対応する esp-hosted のスレーブファームウェアを走らせていなければならない。 ベンダの基板は書き込み済みで出荷される。ホストとスレーブのバージョン違いは、知られた、しかも紛らわしい故障で、ハードウェアの問題ではない。
  • これを書いた時点で、この基板には何も書き込まれていなかった(同じ日のうちに書き込め、それ以来 pad-usb がその上で走っている)。

問われた二つのことにとって何を意味するか

どちらも、すでに部屋にある一枚の基板が「はい」と答える:

電話への BLE キーボード原理上は、ホストが P4、無線が基板上の C6。実際には、C6 のスレーブファームウェアが答えるまで、この基板では BLE の初期化がクラッシュする(2026-09-25)
電話への USB-C キーボードはい。SOC_USB_OTG_PERIPH_NUM は 2 で UTMI の PHY があるので、片方はハイスピードだ。組んだのはフルスピードの方と、USB と記された Type-C ソケットで(pad-usb-protocol.md、層 4)、ハイスピードのコントローラが届くのは USB-A のスタックだけだ。電話はまだ試していない

この仕事には S3 の方が単純な部品のままだ。チップ一つ、無線一つ、コプロセッサも、壊れうるホステッドのリンクも無い。P4 モジュールはすでにベンチにある、より能力の高い部品で、何も買わずに両方のモードを試せる、ここにある唯一の部品でもある。

なぜ SOC_USB_OTG_SUPPORTED が肝心の一線なのか

これは文書の注記ではない。Arduino のコアが USB HID クラス全体を包んでいる、プリプロセッサの条件だ:

libraries/USB/src/USBHID.h:18          #if SOC_USB_OTG_SUPPORTED
libraries/USB/src/USBHIDKeyboard.h:25  #if SOC_USB_OTG_SUPPORTED

C6 ではこれらのヘッダは何も無いものにコンパイルされる。USBHIDKeyboard はライブラリが足りないのではなく空のファイルなので、スケッチは、理由を指すものではなく、存在しない型で失敗する。

SOC_USB_SERIAL_JTAG_SUPPORTED は代わりにならず、これが罠の全部だ。 C6 にはホストで列挙される USB-C のソケットがあるので、部品は USB を持っているように見える。そのポートは ROM の中の固定機能の CDC シリアルと JTAG のユニットだ。キーボードにもゲームパッドにも他の何にも宣言し直せない。宣言するためのデバイスコントローラが、その後ろに無いからだ。

S3 が両方を定義していることにも注意。だから同じ基板をネイティブのポートから書き込み、そのままキーボードとして名乗らせられる。

引き出しに実際にあるもの

2026-09-24 の朝、docs/parts.md は一つを挙げていた: ESP32-C6-DevKitC-1 v1.2。pad-ble のどのシートもその部品を中心に描かれていて、上の表によれば、この一族の中でこの仕事の USB 版を決してやれない、その一つの部品だ。(parts.md はいま pad-ble-p4 の節を持ち、TM-NESB-003 のシート 5 から 7 が P4 だ。)

ワークステーションの USB バスには ESP の形をしたものは無かった(lsusb、2026-09-24 朝)。話に出た、Pi の形の 40 ピンヘッダを持つ大きい方の基板が、上で同定した P4 モジュールだ。

素性の知れない基板を見分ける

手間の順、安い方から:

  1. 金属の缶を読む。 モジュール名がそのまま印字されている: ESP32-S3-WROOM-1、ESP32-WROOM-32、ESP32-C6-WROOM-1。pad-ble の基板はこうして同定した。
  2. RGB LED のシルクを読む。 C6 の devkit は RGB@IO8、S3 の devkit は RGB@IO48 と印字する。pad-ble-build.md に記録がある。
  3. lsusb。 Espressif の 303a:* なら、チップ自身の USB が列挙されている。10c4:ea60 や 1a86:7523 はブリッジチップで、その後ろの部品については何も言わない。
  4. esptool chip-id。 一族の名を印字する。ダウンロードモードが要り、それが C6 で失敗していたことそのものなので、最後だ。

電話への USB-C、部品が S3 なら

  • iPhone 15 以降と、USB-C のすべての iPad: アダプタもアプリも無しで、素の USB HID キーボードをホストする。C to C のケーブルで、電話が VBUS を供給する。
  • Lightning の iPhone: カメラアダプタが要り、それが電源で揉める。
  • OTG のある Android: 文句無しに USB キーボードを受け取る。

これは USB HID クラスが汎用であることから書いたもので、ここで測ったものではない。このベンチでは電話はまだ何にもつないでいない。

いま S3 が面白い二つ目の理由

pad-ble の C6 は一度も口をきいていない。どの書き込みの試みも devkit の CP2102N ブリッジとその自動リセットのトランジスタ対を通り、ブリッジ、ケーブル、ポート、配線、ModemManager はそれぞれ試験で除外されたが、沈黙はそのすべてを生き延びた。

S3 ではネイティブの USB ポートが書き込みのポートでもあり、HID のポートでもある。ブリッジチップも、自動リセットの回路も、ModemManager が探りに来る窓も無い。ROM 自身が USB を話すからだ。いま疑いのかかっている部品はどれも、その経路には無い。

C6 にも同じネイティブのポートがあり、UART と記された方の隣に USB と記されている。それが 303a:* として列挙されるかどうかは二度問われ、一度も確かめられていない。その試験はただで、部品を買う前にやるべきだ。

この文書が主張しないこと

書かれた 2026-09-24 の時点では、ここにあるものは何も組まれていなかった。pad-ble の回路は図面(TM-NESB-003 rev D)で、どのファームウェアにもパッドは配線されておらず、どのホストも何ともペアリングしておらず、「まず測る」の項目 4、純正パッドの 4021 が 3.3 V でボタンに従うことは、2026-09-07 から開いたままだった。別の部品はそのどれが易しいかを変えるだろうが、どれも閉じはしない。上の P4 のコンパイルもどれも閉じなかった。閉じたのは三日後のベンチだ: 配線、3.3 V のパッド、すべてのキーを受け取る Linux のホスト(pad-usb-protocol.md)。まだ済んでいないもの: 電話。