chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

評価Boardが届いたので、Embedded Rust Tutorialをやってみる

取り組み:ESP32-C3のRust用評価ボードを入手できたので、TutorialをやってRustを理解する
課題:WSL上のUbuntuからRust用評価ボードへのUSB経由接続がうまくいかない
対応:Ubuntuからの書き込み不可問題を回避するため、ターゲットボードをM5 Stamp C3に変更、書き込みが成功、デモのWiFi接続+LチカまではOK
詳細:

輸出管理をクリアして、ESP32C3が搭載されたRust用評価ボード(ESP32-C3-DevKit-RUST)が届いた。

Espressifが提供しているEmbedded Rust Tutorialをやってみる。

参照している資料:Embedded Rust on Espressif / Checking the hardware
https://espressif-trainings.ferrous-systems.com/02_1_hardware.html

前回Rustの環境をWSL上で構築した。Tutorialに従うと、次はボードの接続確認である。WSL上のUbuntu からボードが見えるようにしたいのでmoutする必要あり。(この手順を書いてくれている記事があるのでそれを参照)。PowerShellで以下を実行してデバイス一覧を取得

> usbipd wsl list
BUSID  VID:PID    DEVICE                                                        STATE
3-2    8087:07da  インテル(R) ワイヤレス Bluetooth(R)                           Not attached
4-1    303a:1001  USB シリアル デバイス (COM17), USB JTAG/serial debug unit     Not attached
4-3    046d:c058  USB 入力デバイス                                              Not attached

評価ボードのBUSIDは 4-1と分かる。attachコマンドでWSLにマウントさせるが、権限不足で怒られる

> usbipd wsl attach --busid 4-1
usbipd: error: Access denied; this operation requires administrator privileges.
usbipd: info: The first time attaching a device to WSL requires elevated privileges; subsequent attaches will succeed with standard user privileges.

PowerShellを管理者権限で立ち上げてコマンド実行。権限エラーは出ないが、warningが出ている。

> usbipd wsl attach --busid 4-1
usbipd: warning: USB filter 'USBPcap' is known to be incompatible with this software; 'bind --force' will be required.

Ubuntu側でlsusbを実行してマウント?されたかを確認

$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 303a:1001 Espressif USB JTAG/serial debug unit     # 追加された行
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

ボードは見えたと判断して、サンプルコードを動かしてみる。
Tutorialに従って、Git上のサンプルコード一式をローカルPCに複製する

git clone "https://github.com/ferrous-systems/espressif-trainings.git"

Hello boardをやってみる
参照資料:Embedded Rust on Espressif / Hello, board!

cd intro/hardware-check
cp cfg.toml.example  cfg.toml
vi cfg.toml
cargo build

以下のエラーになった

error: "/home/<user_id>/.rustup/toolchains/nightly-2022-03-10-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/Cargo.lock" does not exist, unable to build with the standard library, try:
        rustup component add rust-src --toolchain nightly-2022-03-10-x86_64-unknown-linux-gnu

エラー文言を読むと、不足するコンポーネントを加えろよと言ってる感じがする
前回開発環境を入れたつもりだったが、必要なモジュール?が入っていなかったのか?と解釈して再度インストール
Embedded Rust on Espressif / Software を見ながら再度入れる

rustup install nightly-2022-03-10
rustup component add rust-src --toolchain nightly-2022-03-10
cargo install cargo-espflash ldproxy
sudo apt install llvm-dev libclang-dev clang

再度ビルドしてみる

$cargo build

ビルドは開始された。自分のPCが非力なせいか、めちゃくちゃ遅い(仮想環境上のUbuntuを使っているせいもあるがあまりにも遅すぎる)。コンパイル型言語なので実行は早いだろうけど、バイナリが生成されるまでにめちゃくちゃ時間がかかる。これでTry&Errorはかなり辛い。Rustを使いたかったら高性能なPCが必要ということか。

しかもビルドでエラーになった。Tutorialの通りにやってるのに。。unstableなライブラリを使おうとしているということ??

   Compiling ignore v0.4.20
error[E0658]: use of unstable library feature 'scoped_threads'
    --> /home/xxxx/.cargo/registry/src/github.com-1ecc6299db9ec823/ignore-0.4.20/src/walk.rs:1285:9
     |
1285 |         std::thread::scope(|s| {
     |         ^^^^^^^^^^^^^^^^^^
     |
     = note: see issue #93203 <https://github.com/rust-lang/rust/issues/93203> for more information
     = help: add `#![feature(scoped_threads)]` to the crate attributes to enable

error[E0658]: use of unstable library feature 'scoped_threads'
    --> /home/xxxxx/.cargo/registry/src/github.com-1ecc6299db9ec823/ignore-0.4.20/src/walk.rs:1299:32
     |
1299 |                 handles.push(s.spawn(|| worker.run()));
     |                                ^^^^^
     |
     = note: see issue #93203 <https://github.com/rust-lang/rust/issues/93203> for more information
     = help: add `#![feature(scoped_threads)]` to the crate attributes to enable

error[E0658]: use of unstable library feature 'scoped_threads'
    --> /home/xxxxx/.cargo/registry/src/github.com-1ecc6299db9ec823/ignore-0.4.20/src/walk.rs:1302:24
     |
1302 |                 handle.join().unwrap();
     |                        ^^^^
     |
     = note: see issue #93203 <https://github.com/rust-lang/rust/issues/93203> for more information
     = help: add `#![feature(scoped_threads)]` to the crate attributes to enable

For more information about this error, try `rustc --explain E0658`.
error: could not compile `ignore` due to 3 previous errors
warning: build failed, waiting for other jobs to finish...
error: build failed

nightly versionを使っているなら、冒頭に#![feature(hoge)]と追加しろと。。

If you're using a nightly version of rustc, just add the corresponding feature
to be able to use it:

```
#![feature(repr128)]

Issueが発行されていて、それによると、workaroundで対応しろと
[bug] use of unstable library feature 'scoped_threads' in `ignore` crate · Issue #6050 · tauri-apps/tauri · GitHub

cargo update -p ignore --precise 0.4.18

ignoreコンポーネント(?)は、0.4.18を指定するという意味か?
再度ビルド。。。ここから進まない。

 Building [======================>  ] 224/239: esp-idf-svc(build.rs), esp-idf-hal(build.rs), esp-idf-sys(build.r...

一晩放置したが、Ubuntu 環境自体がちょっとおかしくなった。SWAPしまくったせいか? 再度Ubuntuを立ち上げてビルドしてなんとかバイナリはできた。次は書き込みということで、すでにマウントしているので、以下で書き込む

$  cargo espflash --release --monitor /dev/ttyACM0
New version of cargo-espflash is available: v2.0.0-rc.3

Serial port: /dev/ttyACM0
Connecting...

Error: espflash::serial_error

  × Failed to open serial port /dev/ttyACM0
  ├─▶ Error while connecting to device
  ├─▶ IO error while using serial port: Permission denied
  ╰─▶ Permission denied

/dev/ttyACM0のパーミッションエラーが出ている。sudoで権限を切り替えるか、/dev/ttyACM0に書き込み権限を与えるか・・・ sudoして実行パスとか変わるのを避けたいので、/dev/ttyACM0を誰でも書ける権限に変更

sudo chmod og+rw /dev/ttyACM0

再度実行、権限の問題は解消したが、ずっと待ち状態である。ボードをBOOTモードにしないといけない?

$ cargo espflash --release --monitor /dev/ttyACM0
New version of cargo-espflash is available: v2.0.0-rc.3

Serial port: /dev/ttyACM0
Connecting...

Matched SerialPortType::Unknown

書き込もうとして文鎮になったという記事あり・・・ うーん。。
Cargo run bricks ESP32-C3 - Embedded - The Rust Programming Language Forum

espflashのサブコマンドで、board-infoというのがあり、それをやってみるがやはり無応答になる。Unknownと返してくるのが何かパラメータ解釈できないということなのか。。ソースを見ないと原因が分からん。書き込みだけだったら、Windowsの素の環境でもいいのではと思えるが、buildのcontextとか怒られるとまたややこしそうだ

SUBCOMMANDS:
    board-info         Display information about the connected board and exit without flashing
    help               Print this message or the help of the given subcommand(s)
    partition-table    Operations for partitions tables
    save-image         Save the image to disk instead of flashing to device
    serial-monitor     Open the serial monitor without flashing

$ cargo-espflash espflash /dev/ttyACM0  board-info
New version of cargo-espflash is available: v2.0.0-rc.3

✔ Use serial port '/dev/ttyACM0'? · yes
Serial port: /dev/ttyACM0
Connecting...

Matched SerialPortType::Unknown

詳しくは調べられていないけど、WSLからUSB Serialを扱いたい場合はカーネルをビルドしろという記事もある。。うーんどうしたものか。素のWindowsでやるか、Macに環境を作るか。そもそもなんでUbuntuなんだったっけ・・・環境構築がLinuxで標準的だからトラブルも少なかろうと選んだ記憶が・・

CP210Xとは何なのか(ドライバ?)分かっていないが、CP210Xを有効にするためにカーネルビルドしろとあったが、自分の場合、CP210Xはすでに有効である。だから、USB Serialは使えるはずなのだが。。 USB Serialのドライバが正しく機能していないのだろうか。

$ gzip -dc /proc/config.gz | grep CONFIG_USB_SERIAL_CP210X
CONFIG_USB_SERIAL_CP210X=y

少なくとも書き込みコマンドを実行すると評価ボードのLEDが一旦消えるのでUbuntuからはUSB経由で制御できていると思われるのだが。
CP210xとは、 USB - UART ブリッジのデバイスであった。今使ってる評価ボードにCP201Xが使われていないとこれは意味がないので、回路図で、USB-UARTブリッジがどうなっているのか確認が必要だ。ボードの実装パーツみてもブリッジ用のLSIは不在で、USBの変換は、ESP32本体でやっているような印象なのだが。

TeraTermによる属性表示は以下

Device Friendly Name: USB シリアル デバイス (COM17)
Device Instance ID: USB\VID_303A&PID_1001&MI_00\7&11EFCA92&0&0000
Device Manufacturer: Microsoft
Provider Name: Microsoft
Driver Date: 6-21-2006
Driver Version: 10.0.19041.2130

/dev/ttyXXXのパラメータを確認する方法

# stty -a < /dev/ttyUSB0

USB-SerialのICを介さず、ESP32C3がUSBの信号を直接受ける回路がまずいのかと思い、同じESP32C3を搭載している、M5Stamp C3に繋いでみた。C3はUSB-Serial変換用IC; CH9102を介してマイコンと接続されている。結果、M5 Stamp C3にはファームを焼くことができた。

$ cargo espflash --release --monitor /dev/ttyACM0
New version of cargo-espflash is available: v2.0.0-rc.3

Serial port: /dev/ttyACM0
Connecting...

Matched SerialPortType::Unknown
    Finished release [optimized] target(s) in 22.19s
Chip type:         ESP32-C3 (revision 3)
Crystal frequency: 40MHz
Flash size:        4MB
Features:          WiFi
MAC address:       7c:df:a1:a2:bb:d8
App/part. size:    670000/1048576 bytes, 63.90%
[00:00:01] ########################################      12/12      segment 0x0                                         [00:00:00] ########################################       1/1       segment 0x8000                                      [00:00:42] ########################################     391/391     segment 0x10000
Flashing has completed!
Commands:
    CTRL+R    Reset chip
    CTRL+C    Exit

ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0x1 (POWERON),boot:0xc (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd6100,len:0x16b4
load:0x403ce000,len:0x930
0x403ce000 - _iram_end
    at ??:??
load:0x403d0000,len:0x2d28
0x403d0000 - _iram_end
    at ??:??
SHA-256 comparison failed:
Calculated: 975a71a5818324ff5de2ef93a833fdae997b5d9528ed55e78c9c569b491ea994
Expected: f3cfb3504e9d254ef83d279dbe0bbcc8ce640d9caa06ce39a148ace3335de6ed
Attempting to boot anyway...
entry 0x403ce000
0x403ce000 - _iram_end
    at ??:??

結構進んだものの、WiFi接続でエラーになる。
5G帯だとNGで、2.4Gだと接続できた*1。ボードが違ってるけど、LEDの接続は同じだったようで、テストプログラムを実行するとNetPixel風のLEDが緑・青と点灯する。

初めて使うボード、コンパイル環境だったので結構手間がかかったけど、main 関数を確認すると、WiFiの接続とLEDの点灯、デバッグ文字列出力だけのシンプルなコードだった。これだけのコードに、あれだけのファイルのビルドをやったというのはどうしたなのか??なぜあんなに大量のライブラリが必要だったのか??  Espressif では標準ライブラリをサポートできているので、、使う使わないに関わらず関連ライブラリはすべてビルドするということなのか??

fn main() -> anyhow::Result<()> {
    use bsc::led::RGB8;

    esp_idf_sys::link_patches();
    esp_idf_svc::log::EspLogger::initialize_default();

    info!("Hello, world!");

    // Start the LED off yellow
    let mut led = bsc::led::WS2812RMT::new()?;
    led.set_pixel(RGB8::new(50, 50, 0))?;

    // The constant `CONFIG` is auto-generated by `toml_config`.
    let app_config = CONFIG;

    // Connect to the Wi-Fi network
    let _wifi = match bsc::wifi::wifi(app_config.wifi_ssid, app_config.wifi_psk) {
        Ok(inner) => inner,
        Err(err) => {
            // Red!
            led.set_pixel(RGB8::new(50, 0, 0))?;
            anyhow::bail!("could not connect to Wi-Fi network: {:?}", err)
        }
    };

    loop {
        // Blue!
        led.set_pixel(RGB8::new(0, 0, 50))?;
        // Wait...
        std::thread::sleep(std::time::Duration::from_secs(1));
        info!("Hello, world!");

        // Green!
        led.set_pixel(RGB8::new(0, 50, 0))?;
        // Wait...
        std::thread::sleep(std::time::Duration::from_secs(1));
    }
}


■メモ
WSL上のUbuntu で最低限確認できたら、MacBook上でビルド環境を構築したい。MacのOSの仕組みがよくわかっておらず、オリジナルの環境を汚したくないのでDockerでコンテナ化したい。
■追記
MacのDocker上にUbuntuを入れてRust開発環境を構築した。さすがにCPUの性能差によるものか、バイナリまではサクサクと動いた。が、VMはUSBがパススルーされていないらしく、Docker環境からはファームを評価ボードに書き込めないようであった。Flash書き込みまでコマンド一発で実行できないため、これはなかり面倒だ。しょうがないので、コンテナではなく、Macの素の環境に入れるしかないか。。

■参考記事
WSLにUSBデバイスをマウントさせる方法
https://zenn.dev/nozo/scraps/5ad75a77d88470

WSL2環境からUSBシリアルデバイスを使う - Qiita
GitHub - esp-rs/esp-rust-board: Open Hardware with ESP32-C3 compatible with Feather specification designed in KiCad

*1:Tutorialを読み直すと、「5GはNGで、2.4Gに接続しろ」とあった