WSL2でESP32の開発環境を整える

TechESP32, WSL2

仕事環境もWSL2をメインにしているので、ESP32の開発環境もWSL2にしたい。

WSL2の制約の一つにUSBデバイスに対応していない、という点があります。そこをなんとかしたいということで調べてやってみた。

USBデバイスを直接認識させずにIP通信経由で仮想的に認識させる方法が行けるようです。

ESP-IDF自体のインストールはUbuntuを使っていれば、Linux用の手順で問題ないと思います。

いくつかのパッケージのインストールも忘れずに

  • python、pip、cmake

環境

Windows10で、Ubuntu20.04を使用しています。Ubuntu18.04でも大丈夫なのかな?

やったこと

  • Linuxカーネルを最新版にする(PowerShell)
    • 必要な修正が入っている5.10.60.1 以降であることが必須であるそうです。
      wsl --updatewsl --shutdown
  • usbip-winのインストール
    • うまく行けばPowerShell(admin)で usbipd.exe list を実行するとUSBデバイスが見える
  • linux-tools、hwdata のインストール(こちらを参考に)
vi install_linux_tools_generic.sh
chmod +x install_linux_tools_generic.sh
sudo ./install_linux_tools_generic.sh
sudo apt install hwdatasudo update-alternatives --install /usr/local/bin/usbip usbip /usr/lib/linux-tools/<your version>-generic/usbip 20

install_linux_tools_generic.shの内容

#!/usr/bin/env bash

rel="$(uname -r)"
rel="${rel%%-*}"
rel=(${rel//./ })

function latest_linux_tools {
    apt-cache search linux-tools |
    awk -v cur_ver="${rel[*]}" '
    /^linux-tools([-\.][0-9]+)+-generic\>/ {
        ltg_package=$1
        gsub(/[^0-9]+/," ",$1);
        gsub(/^\s*/,"",$1);
        split($1,ltg_ver,/\s*/);
        split(cur_ver,cmp_ver,/\s*/)
        if (ltg_ver[1]<=cmp_ver[1] && ltg_ver[2]<=cmp_ver[2] && ltg_ver[3]<=cmp_ver[3]) {
            print ltg_package;
        }
    }' | sort -nr | head -n 1
}

# optional ...
apt-get install "$@" "$(latest_linux_tools)"
  •  USBデバイスをアタッチする
    • usbipd wsl list でリストを表示して、対象のデバイスのBUSIDをチェックして usbipd wsl attach -b <BUSID> を実行
    • 一度WSLを再起動しておいた方がよいかも

“usbipd: error: The specified WSL distribution is not running”と表示される場合

自分の場合は、接続を試みるディストリビューションが期待する対象と合っていなかった。

どうやらDockerDesktopに接続しようとしていた模様。wsl --set-defaultで指定してあげるとうまくいった。

PS C:\WINDOWS\system32> usbipd wsl attach -b 4-2
usbipd: error: The specified WSL distribution is not running.

PS C:\WINDOWS\system32> wsl --list
Linux 用 Windows サブシステム ディストリビューション:
docker-desktop-data (既定)
Ubuntu-18.04
Ubuntu-20.04
docker-desktop

PS C:\WINDOWS\system32> wsl --set-default Ubuntu-20.04

PS C:\WINDOWS\system32> wsl --list
Linux 用 Windows サブシステム ディストリビューション:
Ubuntu-20.04 (既定)
docker-desktop-data
Ubuntu-18.04
docker-desktop

書き込みでエラーになる場合

serial.serialutil.SerialException: [Errno 13] could not open port /dev/ttyUSB0: [Errno 13] Permission denied: '/dev/ttyUSB0'

Ubuntu側で認識されたデバイスがrootしかR/Wできない場合は、udev ruleを書いてあげる。

$ ls /dev
...
crw------- 1 root root 188, 0 Jan 30 16:36 ttyUSB0
...

$ echo 'SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", MODE="0666"' | sudo tee /etc/udev/rules.d/50-usb-serial.rules
$ sudo service udev restart
(ここで、PowerShellで、detach&attachを行う)
$ ls -all /dev
...
crw-rw-rw- 1 root dialout 188, 0 Jan 30 16:43 ttyUSB0
...

動作確認

Attach後、Ubuntu上で確認するとUSBデバイスが認識されていることが分かる

kishima@WinDesk:~$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 0403:6015 Future Technology Devices International, Ltd Bridge(I2C/SPI/UART/FIFO)
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

書き込みとmonitorもOK

kishima@WinDesk:~/esp/hello_world$ idf.py -p /dev/ttyUSB0 flash monitor
Executing action: flash
Running make in directory /home/kishima/esp/hello_world/build
Executing "make -j 10 flash"...
[  1%] Built target partition_table_bin
[  0%] Built target custom_bundle
[  0%] Built target memory_ld
[  2%] Built target _project_elf_src
[  2%] Performing build step for 'bootloader'
[  2%] Built target __idf_ulp
[  2%] Built target __idf_esp_serial_slave_link
[  2%] Built target _project_elf_src
[  5%] Built target __idf_log
[  3%] Built target __idf_sdmmc
[ 11%] Built target __idf_esp_rom
[  3%] Built target __idf_esp_https_ota
[ 13%] Built target __idf_esp_common
[  4%] Built target __idf_esp_http_server
[ 16%] Built target __idf_xtensa
[  5%] Built target __idf_esp_http_client
[ 27%] Built target __idf_esp_hw_support
[ 29%] Built target __idf_esp_system
[  6%] Built target __idf_tcp_transport
[ 38%] Built target __idf_efuse
[  6%] Built target __idf_esp-tls
[ 62%] Built target __idf_bootloader_support
[  8%] Built target __idf_nghttp
[ 64%] Built target __idf_spi_flash
[  8%] Built target __idf_app_trace
[ 67%] Built target __idf_micro-ecc
[  8%] Built target __idf_cxx
[ 89%] Built target __idf_soc
[ 10%] Built target __idf_newlib
[ 93%] Built target __idf_hal
[ 12%] Built target __idf_freertos
[ 95%] Built target __idf_main
[ 12%] Built target __idf_esp_timer
[ 98%] Built target bootloader.elf
[100%] Built target gen_project_binary
[ 12%] Built target __idf_esp_common
[ 12%] Built target __idf_xtensa
Bootloader binary size 0x62b0 bytes. 0xd50 bytes (12%) free.
[100%] Built target bootloader_check_size
[ 14%] Built target __idf_esp_hw_support
[100%] Built target app
[ 16%] Built target __idf_soc
[ 16%] No install step for 'bootloader'
[ 17%] Built target __idf_heap
[ 17%] Completed 'bootloader'
[ 18%] Built target __idf_log
[ 18%] Built target bootloader
[ 26%] Built target __idf_lwip
[ 27%] Built target __idf_console
[ 28%] Built target __idf_esp_wifi
[ 35%] Built target __idf_wpa_supplicant
[ 35%] Built target __idf_esp_event
[ 36%] Built target __idf_esp_netif
[ 36%] Built target __idf_tcpip_adapter
[ 37%] Built target __idf_esp_eth
[ 38%] Built target __idf_vfs
[ 42%] Built target __idf_hal
[ 43%] Built target __idf_esp_rom
[ 46%] Built target __idf_esp_system
[ 46%] Built target __idf_esp_phy
[ 46%] Built target __idf_espcoredump
[ 47%] Built target __idf_esp_gdbstub
[ 47%] Built target __idf_pthread
[ 48%] Built target __idf_nvs_flash
[ 50%] Built target __idf_spi_flash
[ 52%] Built target __idf_bootloader_support
[ 52%] Built target __idf_app_update
[ 59%] Built target mbedcrypto
[ 60%] Built target mbedx509
[ 61%] Built target mbedtls
[ 61%] Built target __idf_mbedtls
[ 62%] Built target __idf_esp_pm
[ 65%] Built target __idf_driver
[ 66%] Built target __idf_esp_ipc
[ 67%] Built target __idf_efuse
[ 67%] Built target __idf_esp_ringbuf
[ 67%] Built target __idf_json
[ 67%] Built target __idf_mdns
[ 67%] Built target __idf_protobuf-c
[ 67%] Built target __idf_unity
[ 68%] Built target __idf_esp_adc_cal
[ 68%] Built target __idf_asio
[ 69%] Built target __idf_cbor
[ 70%] Built target __idf_esp_hid
[ 70%] Built target __idf_esp_lcd
[ 73%] Built target __idf_coap
[ 75%] Built target __idf_wear_levelling
[ 75%] Built target __idf_expat
[ 76%] Built target __idf_esp_websocket_client
[ 77%] Built target __idf_openssl
[ 77%] Built target __idf_jsmn
[ 88%] Built target __idf_libsodium
[ 89%] Built target __idf_mqtt
[ 90%] Built target __idf_perfmon
[ 91%] Built target __idf_spiffs
[ 91%] Built target __idf_cmock
[ 92%] Built target __idf_protocomm
[ 96%] Built target __idf_freemodbus
[ 97%] Built target __idf_fatfs
[ 97%] Built target __idf_esp_local_ctrl
[ 98%] Built target __idf_wifi_provisioning
[ 99%] Built target __idf_main
[ 99%] Built target __ldgen_output_sections.ld
[100%] Built target hello_world.elf
[100%] Built target gen_project_binary
hello_world.bin binary size 0x29700 bytes. Smallest app partition is 0x100000 bytes. 0xd6900 bytes (84%) free.
[100%] Built target app_check_size
[100%] Built target app
esptool.py esp32 -p /dev/ttyUSB0 -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 2MB 0x1000 bootloader/bootloader.bin 0x10000 hello_world.bin 0x8000 partition_table/partition-table.bin
esptool.py v3.2-dev
Serial port /dev/ttyUSB0
Connecting.........
Chip is ESP32-D0WD (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: c8:2b:96:85:e6:20
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Flash will be erased from 0x00001000 to 0x00007fff...
Flash will be erased from 0x00010000 to 0x00039fff...
Flash will be erased from 0x00008000 to 0x00008fff...
Compressed 25264 bytes to 15781...
Writing at 0x00001000... (100 %)
Wrote 25264 bytes (15781 compressed) at 0x00001000 in 0.7 seconds (effective 287.1 kbit/s)...
Hash of data verified.
Compressed 169728 bytes to 89595...
Writing at 0x00010000... (16 %)
Writing at 0x0001afef... (33 %)
Writing at 0x00020754... (50 %)
Writing at 0x00025f9f... (66 %)
Writing at 0x0002e5b4... (83 %)
Writing at 0x0003693e... (100 %)
Wrote 169728 bytes (89595 compressed) at 0x00010000 in 2.4 seconds (effective 569.6 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 103...
Writing at 0x00008000... (100 %)
Wrote 3072 bytes (103 compressed) at 0x00008000 in 0.1 seconds (effective 385.0 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...
[100%] Built target flash
Executing action: monitor
Running idf_monitor in directory /home/kishima/esp/hello_world
Executing "/home/kishima/.espressif/python_env/idf4.4_py3.8_env/bin/python /home/kishima/esp/esp-idf/tools/idf_monitor.py -p /dev/ttyUSB0 -b 115200 --toolchain-prefix xtensa-esp32-elf- --target esp32 --revision 0 /home/kishima/esp/hello_world/build/hello_world.elf -m '/home/kishima/.espressif/python_env/idf4.4_py3.8_env/bin/python' '/home/kishima/esp/esp-idf/tools/idf.py' '-p' '/dev/ttyUSB0'"...
--- idf_monitor on /dev/ttyUSB0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:6604
ho 0 tail 12 room 4
load:0x40078000,len:14780
load:0x40080400,len:3792
0x40080400: _init at ??:?

entry 0x40080694
I (29) boot: ESP-IDF v4.4 2nd stage bootloader
I (29) boot: compile time 16:30:20
I (29) boot: chip revision: 1
I (31) boot_comm: chip revision: 1, min. bootloader chip revision: 0
I (39) boot.esp32: SPI Speed      : 40MHz
I (43) boot.esp32: SPI Mode       : DIO
I (48) boot.esp32: SPI Flash Size : 2MB
I (52) boot: Enabling RNG early entropy source...
I (58) boot: Partition Table:
I (61) boot: ## Label            Usage          Type ST Offset   Length
I (69) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (76) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (83) boot:  2 factory          factory app      00 00 00010000 00100000
I (91) boot: End of partition table
I (95) boot_comm: chip revision: 1, min. application chip revision: 0
I (102) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=0775ch ( 30556) map
I (122) esp_image: segment 1: paddr=00017784 vaddr=3ffb0000 size=02340h (  9024) load
I (126) esp_image: segment 2: paddr=00019acc vaddr=40080000 size=0654ch ( 25932) load
I (141) esp_image: segment 3: paddr=00020020 vaddr=400d0020 size=14a40h ( 84544) map
I (171) esp_image: segment 4: paddr=00034a68 vaddr=4008654c size=04c5ch ( 19548) load
I (180) esp_image: segment 5: paddr=000396cc vaddr=50000000 size=00010h (    16) load
I (186) boot: Loaded app from partition at offset 0x10000
I (186) boot: Disabling RNG early entropy source...
I (200) cpu_start: Pro cpu up.
I (200) cpu_start: Starting app cpu, entry point is 0x40080fe8
0x40080fe8: call_start_cpu1 at /home/kishima/esp/esp-idf/components/esp_system/port/cpu_start.c:156

I (0) cpu_start: App cpu up.
I (214) cpu_start: Pro cpu start user code
I (214) cpu_start: cpu freq: 160000000
I (214) cpu_start: Application information:
I (219) cpu_start: Project name:     hello_world
I (224) cpu_start: App version:      1
I (229) cpu_start: Compile time:     Jan 30 2022 16:30:28
I (235) cpu_start: ELF file SHA256:  a6f2e830ed882286...
I (241) cpu_start: ESP-IDF:          v4.4
I (246) heap_init: Initializing. RAM available for dynamic allocation:
I (253) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (259) heap_init: At 3FFB2C28 len 0002D3D8 (180 KiB): DRAM
I (265) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (271) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (278) heap_init: At 4008B1A8 len 00014E58 (83 KiB): IRAM
I (285) spi_flash: detected chip: gd
I (288) spi_flash: flash io: dio
W (292) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (306) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
Hello world!
This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, silicon revision 1, 2MB external flash
Minimum free heap size: 293268 bytes
Restarting in 10 seconds...

CP210xを使用している場合

自作基板はFTDIを使用しているので特に問題はなかったが、CP210xを使用している基板の場合はカーネルのビルドが必要になるっぽい。

https://qiita.com/isseikz/items/344a20570e23310cac8d

参考

Connecting USB devices to WSL

https://www.giters.com/MicrosoftDocs/WSL/issues/1380

https://lowreal.net/2021/11/16/1

https://contentsviewer.work/Master/WSL/Tips/WSL2-USB/WSL2-USB

https://gitmemory.cn/repo/dorssel/usbipd-win/issues/126

http://mech.u-fukui.ac.jp/~Kawa-Lab/ros/usb_serial.html

TechESP32, WSL2

Posted by kishima