直近で書いた Zephyrをはじめました と Zephyrの一般的な使い方メモ(ボード非依存) の記事の後、とりあえずESP32からいきます。
前提
私はEspressifのESP32-WROVER-E というボードを使っています。 CPUはTensilica XtensaアーキテクチャのLX6というだいぶ古いものです。 Zephyrのboardページだとここにあるものに対応します。
以下、シリーズによってはあてはまらない情報があるかもしれませんが、御承知おきを。
ESP32のCANコントローラ(TWAI)を使いたい
可能です。
ただし、少なくとも v4.2.0-4096-g1c1598601b5c 時点では、disabledにされています。 具体的に言うと以下のあたり。(2025/11/02時点)
https://github.com/zephyrproject-rtos/zephyr/blob/main/dts/xtensa/espressif/esp32/esp32_common.dtsi#L438
431 twai: can@3ff6b000 {
432 compatible = "espressif,esp32-twai";
433 reg = <0x3ff6b000 DT_SIZE_K(4)>;
434 interrupts = <TWAI_INTR_SOURCE IRQ_DEFAULT_PRIORITY 0>;
435 interrupt-parent = <&intc>;
436 clocks = <&clock ESP32_TWAI_MODULE>;
437 status = "disabled"; # ★disabledになっている★
438 };
このため、overlayファイルを作ってオーバーライドしてあげる必要があります。 やり方は前の記事を参照してください。
ESP32でCAN通信をしたい
可能です。
ただし、ESP32はCANのコントローラしか内蔵していないので、CANトランシーバーを接続してあげる必要があります。
私は、MicrochipのCAN-FD対応のトランシーバーのMCP2562FDを使い、 この記事で紹介されている回路を組み、対向側としてRaspberry Pi Zero W + DSP SH-C31AおよびRenesas R-Car V4Hを搭載したSBCの Sparrow Hawk で動作確認しました。 MCP2562FDは秋月で200円(当時)でした。
2025/10/20に大阪で開催されたZephyr Project Meetup: Osaka, Japanで話した ネタ はこの話をしています。
会場で「普通はMicrochipのトランシーバを使うのか?」という質問を受けましたが、 CANは枯れた規格なので、基本的には何でも動くのではないかと思います。NXPのチップとか。動作電圧とかは注意ですが...
CANデバイスの状態を確認したい
微妙です。(...だと思います(4.2.0時点))
prj.confでCONFIG_CAN_SHELLを有効化(=y)すると使えるようになる
shellのCANサポート機能を使い、
uart:~$ can show DEVICE_ID
等とやるとトランシーバーの状態まで表示できます。
使えるDEVICE_IDは、省略して can show とやると一覧表示されます。
以下は can show DEVICE_IDしてみた時のログの例になりますが、 外付けのCAN transceiverの場合は、ESP32とは関係なく、もうひと手間加えてあげないと、 Zephyr側で認識してくれないように思います。
$ west espressif monitor
(snip)
[00:00:00.175,000] <dbg> can_sja1000: can_sja1000_init: initial sample point error: 0
*** Booting Zephyr OS build v4.2.0-4096-g1c1598601b5c ***
(snip)
いきなり余談ですが...
- ESP32の場合は westの拡張が入っていて
west espressif monitorとかできるので便利です - 上記をみるとESP32が内蔵するCANコントローラはNXPのSJA1000互換のIPを使っているものと想像できます。
以下、状態表示してみた結果。
uart:~$ can show can@3ff6b000
core clock: 40000000 Hz
max bitrate: 1000000 bps
max std filters: 5
max ext filters: 5
capabilities: normal loopback listen-only one-shot triple-sampling
mode: normal
state: error-active
ここのstate:はCANコントローラの状態です。error-というprefixが気になるのですが、コードを眺める限りは、これで正常に初期化できているということのようです。
rx errors: 0
tx errors: 0
timing: sjw 1..4, prop_seg 0..0, phase_seg1 1..16, phase_seg2 1..8, prescaler 1..64
transceiver: passive/none
次にここ。transceiver: が passive/none という状態になっていて、トランシーバの状態が取れない模様...うん?
statistics:
bit errors: 0
bit0 errors: 0
bit1 errors: 0
stuff errors: 0
crc errors: 0
form errors: 0
ack errors: 0
rx overruns: 0
しかし、このまま送信処理をしてみると、以下のように無事に送信処理が終わっている!?
uart:~$ can send can@3ff6b000 234 56
enqueuing CAN frame #0 with standard (11-bit) CAN ID 0x234, RTR 0, CAN FD 0, BRS 0, DLC 1
CAN frame #0 successfully sent
uart:~$
このログを採取した際、CANバスの対向側にRaspberry Pi Zero W+DSD SH-C31Aをつないでおり、実際にデータが流れていることを確認しています。
それで、上記transceiverの表示のところは、ソースの該当部分を眺めると、deviceに対応する管理構造体がない(=pointerがNULL)だとこういう表示になるようです。
と、いうことは...
- dtsで何かtransceiver用の記述をしてあげないといけない?
- 後述のCAN Busの状態をGPIOで制御したい場合と同様に、GPIO用のpin定義のついでに)deviceも書かないといけない?
...とか想像できますが、まだ裏がとれていません。
あとは、statistics: のところ、数字が入ってくれるのかどうか、まだ確認できていません。
うーん...
CAN Busの状態を制御したい(BUS Stopさせたり戻したりとか)
can_transceiver_enable() というAPIを使って可能(...なはず)です。
CANコントローラへの指示ではなく、トランシーバのSTBY(だったり、チップによってはSだったりしますが...)GPIOでピンの値を制御することになります。(はずです)
...とはいえ上記に書いたように、何かおまじないが必用...と思われます。
以下、参考。
- CAN transceiverまわりの説明
- https://docs.zephyrproject.org/latest/hardware/peripherals/can/transceiver.html
- CAN transceiver APIの説明
- https://docs.zephyrproject.org/latest/doxygen/html/group__can__transceiver.html
ESP32の複数コアを使いたい
可能です。
ESP32の場合は、普通のSMPではなく、
AMP(Asymmetric Multi-processing)
と呼ばれる使い方になるようです。
ビルドの際に、先頭のコア用のプログラムはprocpu、
2番目(以降?)のコアがappcpuという名前でターゲット指定することになります。
sysbuildでブートローダにmcubootを指定し、2番目のコア(前述のappcpu)用のプログラムは remote というディレクトリにわけて作ることになるようですが、識者によると、ここでも「黒魔術」っぽさがある模様...gkbr
複数コアの間の通信や同期には IPM: Inter-Processor Mailbox という仕組みが使えるようになっています。 IPMを使ったプログラミングの具体例は、zephyr公式のサンプルにも含まれています。ESP32用のものはここにあります。
なお、threadを使うだけでは1コアしか使われないことに注意が必要です。(たぶん)
TODO
以下のような確認を行いながら更新してく予定。
- multi-threadを使いたい
- ESP32のWiFiを使いたい
- ESP32でhttp_serverを動かしたい
- gdbでリモート(?)デバッグしたい
- ESP32にセンサ(I2CとかSPIとか)をつなぎたい
- ...