Windows WSL2 の 1.0 版以降のカーネルでは、usbipd を経由することで Windows 側の USB 機器を IP 経由で参照することができます。
この動きを利用して、USB に接続した M5Stack(USB-UART) に WSL2 Ubuntu 上の esp-tools から書き込みする手順を記載してみます。数コマンド叩くだけで完了します。便利。
手順の例では WSL2 Ubuntu 上にセットアップした Linux 版の esp-idf 開発系から直接マイコンに書き込みを行っています。書き込み処理は Linux 側で動作しますので、Windows 側にUSB-UART ドライバーセットアップは不要です。
おそらく他のマイコンや PlatformIO 環境でも同じ手順で USB を認識させれば Linux 側から書き込みできるようになると思います。
この記事では esp-idf の idf.py
コマンドを使ったM5Stack Core2 への書き込み例をメインに、PlatformIO での Longan Nano 書き込み、openocd を使った M5Stamp C3 のデバッグ構成も合わせて記載しました。
環境
Windows WSL2 (Windows 10 の場合 1.0 以降)
> wsl --version
WSL バージョン: 1.0.3.0
カーネル バージョン: 5.15.79.1
WSLg バージョン: 1.0.47
MSRDC バージョン: 1.2.3575
Direct3D バージョン: 1.606.4
DXCore バージョン: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windowsバージョン: 10.0.22621.1105
WSL2 Ubuntu 22.04
$ uname -a
Linux minis-um690 5.15.79.1-microsoft-standard-WSL2 #1 SMP Wed Nov 23 01:01:46 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
Ubuntu 22.04 上の esp-idf。なお、esp-idf ツールチェインが必要とする Ubuntu の依存関係はこちらに記載されています。(追記: ESP-IDF v4.4.4 でも問題ないことを確認) PlatformIO を使う場合は自動導入されるので、この確認は不要です。
$ get_idf
$ echo ${IDF_PATH}
/home/hiromasa/devel/toolchain/esp-idf
$ idf.py --version
ESP-IDF v4.4.3
Windows に usbipd-win を導入
基本的に以下の Microsoft のガイドに従うと OK ですが、一部コマンドがカーネルバージョンに依存しているので、usbipd-win の手順も参照しています。
このガイドでは、USB/IP オープンソース プロジェクト usbipd-win を使用して、WSL 2 で実行されている Linux ディストリビューションに USB デバイスを接続するために必要な手順について説明します。
まずは Windows 側に usbipd-win を導入します。 PowerShell 窓より以下のコマンドにて。
> winget install --interactive --exact dorssel.usbipd-win
次に WSL2 Ubuntu 22.04 に apt で usbipd を導入します。
$ sudo apt update
$ sudo apt upgrade
$ sudo apt install linux-tools-virtual hwdata
$ sudo update-alternatives --install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20
なお、手順中の ls /usr/lib/linux-tools/*/usbip
ですがカーネルバージョンに合わせた usbip を登録しています。
ls /usr/lib/linux-tools/*/usbip | tail -n1
/usr/lib/linux-tools/5.15.0-70-generic/usbip
Ubuntu カーネル(tools の)バージョンが上がった場合に、後述の Windows 側からのバインドで以下のエラーとなった場合は再度上記の sudo update-alternatives --install
を実行してください。
❯ usbipd.exe wsl attach --busid 9-3
usbipd: error: WSL 'usbip' client not correctly installed. See https://github.com/dorssel/usbipd-win/wiki/WSL-support for the latest instructions.
linux-tools がアップデート(ここでは Kernel 5.15.0-70 から 5.15.0.-71)された後の update-alternatives
設定ログ:
$ sudo update-alternatives --install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20
update-alternatives: 警告: /usr/lib/linux-tools/5.15.0-70-generic/usbip の alternative (リンクグループ usbip のパート) が存在しません 。alternatives のリストから削除しています
update-alternatives: 警告: /etc/alternatives/usbip is dangling; it will be updated with best choice
update-alternatives: /usr/local/bin/usbip (usbip) を提供するために自動モードで /usr/lib/linux-tools/5.15.0-71-generic/usbip を使います
さて、この流れでついでに Ubuntu の udev を構成して、マイコンの USB 接続をユーザ権限から見れるようにしておきます。 PlatformIO の udev 定義を使うとほとんどのマイコンで使えて便利です。
$ curl -fsSL https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/system/99-platformio-udev.rules | sudo tee /etc/udev/rules.d/99-platformio-udev.rules
ここでいったん Windows ごと再起動します。
USB 機器のバインド
Windows 起動後、先に Ubuntu の usbipd を起動するために、WSL2 Ubuntu 窓を上げておきます。
WSL2 では udev サービスが自動起動しませんので、WSL2 起動後に以下のコマンドで起動します。(wsl.conf などで自動起動設定するのもいいかもしれません)
$ sudo service udev restart
次に Windows の PowerShell 窓を「管理者で起動」し、使いたい USB 機器を usbipdにアタッチします。
usbipd wsl list コマンドで USB 機器を表示。
> usbipd wsl list
BUSID VID:PID DEVICE STATE
3-1 17ef:6047 Lenovo USB Interface Device(HID), USB 入力デバイス Not attached
3-3 0e8d:0608 RZ608 Bluetooth(R) Adapter Not attached
7-1 0499:170d AG06/AG03, Line (AG06/AG03) Not attached
9-1 10c4:ea60 CP2104 USB to UART Bridge Controller Not attached
CP2104 USB to UART が M5Stack なので 9-1 をアタッチ。なお、初回のアタッチの操作のみ管理者権限が必要で次回からはユーザ権限でいけるようです。
> usbipd wsl attach --busid 9-1
なお、ユーザ権限がついたあとは、Ubuntu 側から次のコマンドでも操作可能です。(.exe を付けて明示的に Windows 側のコマンドを呼びます)
$ usbipd.exe wsl attach --busid 9-1
うまくいけば、upsipd wsl list コマンドのデバイス部分が Ubuntu になります。
> usbipd wsl list
BUSID VID:PID DEVICE STATE
9-1 10c4:ea60 CP2104 USB to UART Bridge Controller Attached - Ubuntu-22.04
できたら、WSL2 Ubuntu で lsusb してみて機器(CP210)が見えればOKです。
$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 10c4:ea60 Silicon Labs CP210x UART Bridge
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
PlatformIO からお借りした udev 定義が効いていれば /dev/ttyUSB0
あたりにユーザ権限の書き込み付きでブロックデバイスが見えます。rw-rw-rw
なら成功です。
$ ls -laF /dev/ttyUSB*
crw-rw-rw- 1 root dialout 188, 0 1月 28 17:17 /dev/ttyUSB0
マイコンが暴走して USB を抜き差しした後などで、usbipd.exe
で再アタッチするも udev が効かないケースがあるようです。その場合は面倒なので手動で chmod
するのもありかと思います。
$ sudo chmod 666 /dev/ttyUSB0
マイコンへの書き込み
/dev/ttyUSB0
宛てにそれぞれのマイコンの書き込みツールを設定すれば書けるはずです。esp-idf (esp-tools) は自動的にシリアルポートを探してくれますので、以下のいつものコマンドで書き込みからモニターまで動作します。
$ idf.py build flash monitor
Executing action: all (aliases: build)
Running ninja in directory /home/hiromasa/devel/esp32/m5stack-core2-wasm3-as/build
Executing "ninja all"...
[1/4] cd /home/hiromasa/devel/esp32/m5stack-core2-wasm3-as/b...asa/devel/esp32/m5stack-core2-wasm3-as/build/hello_world.bin
hello_world.bin binary size 0x124cb0 bytes. Smallest app partition is 0x200000 bytes. 0xdb350 bytes (43%) free.
[2/4] Performing build step for 'bootloader'
[1/1] cd /home/hiromasa/devel/esp32/m5stack-core2-wasm3-as/build/bootloader/esp-idf/esptool_py && /home/hiromasa/.espressif/python_env/idf4.4_py3.10_env/bin/python /home/hiromasa/devel/toolchain/esp-idf/components/partition_table/check_sizes.py --offset 0x8000 bootloader 0x1000 /home/hiromasa/devel/esp32/m5stack-core2-wasm3-as/build/bootloader/bootloader.bin
Bootloader binary size 0x6330 bytes. 0xcd0 bytes (11%) free.
Executing action: flash
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... Unsupported detection protocol, switching and trying again...
Connecting.....
Detecting chip type... ESP32
...以下略...

以上です。
本環境設定と合わせて、プロジェクトディレクトリを VSCode の WSL Remote 拡張で開けば、ソースコードの編集からマイコンへの書き込みまで Linux 周りのツールで揃えることができるので便利なのではないかと思います。
以下は他のマイコンでの設定例です。
Longan Nano (GD32V) + VSCode + PlatformIO
Longan Nano dfu 用の udev 構成。
$ cat /etc/udev/rules.d/70-ttyusb.rules #ファイル追加
# Longan Nano
SUBSYSTEM=="usb", ATTRS{idVendor}=="28e9", ATTRS{idProduct}=="0189", MODE="0666"
SUBSYSTEM=="usb_device", ATTRS{idVendor}=="28e9", ATTRS{idProduct}=="0189", MODE="0666"
$ sudo service udev restart # udev restart
Longan Nano を BOOT + RESET 起動で dfu モードに入れて attach。
> usbipd wsl list
BUSID VID:PID DEVICE STATE
3-1 17ef:6047 Lenovo USB Interface Device(HID), USB 入力デバイス Not attached
3-3 0e8d:0608 RZ608 Bluetooth(R) Adapter Not attached
7-1 0499:170d AG06/AG03, Line (AG06/AG03) Not attached
9-1 28e9:0189 Not attached
先に管理者権限 PowerShell でアタッチした後、リセットするとアタッチが切れるので、再アタッチ。 WSL2 Ubuntu 側からも Windows の usbipd.exe
を呼べる動作を活用してアップロード操作前にアタッチコマンドを実行できるようにタスクを組むと便利。
$ usbipd.exe wsl attach --busid 9-1
$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 28e9:0189 GDMicroelectronics GD32 DFU Bootloader (Longan Nano)
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
あとは WSL2 側に入れた VSCode と PlatformIO 拡張から、いつも通り Upload を起動すれば書き込みできます。

openocd デバッグを行う場合
M5Stamp C3 の USB JTAG デバッグを行う設定です。
M5Stamp C3 は 「M5Stamp C3 用の開発向けボードを製作」のように USB JTAG を引き出すことができます。また、M5Stamp C3U では付属の USB ポートでいけると思います。
openocd の依存となる libusb の導入(esp-idf の依存で導入されているかもですが念の為。どちらかでだけでもいいかものと、-dev を入れているのは癖なので外しても OK です)
$ sudo apt install libusb-dev libusb-1.0-0-dev
openocd の依存となる libpython2.7 導入
$ sudo apt install libpython2.7
USB ポートに M5Stamp C3 の JTAG USB 側(?) を引き出して接続、Windows 側でアタッチ後 Linux で USB 認識確認
$ lsusb | grep JTAG
Bus 001 Device 007: ID 303a:1001 Espressif USB JTAG/serial debug unit
udev 構成追加( 303a の 追加)
$ cat /etc/udev/rules.d/99-platformio-udev.rules | grep 303a
# 以下を追加
ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
udev restart
$ sudo service udev restart
接続確認
いったん USB を抜き差しして、Windows 側で再アタッチなどして、接続確認します。
$ ls -laF /dev/ttyACM*
crw-rw-rw- 1 root dialout 166, 0 1月 28 19:46 /dev/ttyACM0
openocd 起動
$ which openocd
/home/hiromasa/.espressif/tools/openocd-esp32/v0.11.0-esp32-20221026/openocd-esp32/bin/openocd
$ openocd -f board/esp32c3-builtin.cfg
Open On-Chip Debugger v0.11.0-esp32-20220706 (2022-07-06-15:48)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'jtag'
Info : esp_usb_jtag: VID set to 0x303a and PID to 0x1001
Info : esp_usb_jtag: capabilities descriptor set to 0x2000
Warn : Transport "jtag" was already selected
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : esp_usb_jtag: serial (34:B4:72:12:94:14)
Info : esp_usb_jtag: Device found. Base speed 40000KHz, div range 1 to 255
Info : clock speed 40000 kHz
Info : JTAG tap: esp32c3.cpu tap/device found: 0x00005c25 (mfg: 0x612 (Espressif Systems), part: 0x0005, ver: 0x0)
Info : datacount=2 progbufsize=16
Info : Examined RISC-V core; found 1 harts
Info : hart 0: XLEN=32, misa=0x40101104
Info : starting gdb server for esp32c3 on 3333
Info : Listening on port 3333 for gdb connections
VSCode などから接続(設定例)
おそらく openocd 接続後初回の Debug Launch は(マイコンの状態により)失敗するので、2回 Debug Launch するとブレイクすると思います。(WSL2 ではない Ubuntu でも再現するので自分の setupCommands
が悪いのかもしれません)
