chakokuのブログ(rev4)

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

WSLに組み込みRust開発環境(no-std)を入れる

これまでに何度もやったのだが、、再度WSLに組み込みRustを入れる。今回はno-std開発用
もう時間もなく、じっくり資料読みながら作業する余裕もないので、RustBookをちらちらと呼んで必要そうなコマンドを実行

rustup toolchain install nightly --component rust-src
rustup target add riscv32imc-unknown-none-elf # For ESP32-C2 and ESP32-C3
sudo apt install pkg-config
cargo install cargo-generate
cargo install cargo-espflash

cargo run でビルド、書き込みまで行おうとするが、最後の書き込みのところで、esplfashが無いと怒られる

espflash flash --monitor target/riscv3(elfバイナリ)

さっき入ったのは、cargo-espflashなのであった。さらに、WSLの場合、Windows環境のUSBが手当てしないと見えない。WSLからWindows環境のUSBが扱えるように設定する

usbipd-win をWindows環境にインストールする
DLサイトは以下
Releases · dorssel/usbipd-win · GitHub
Ubuntuで以下を実行

sudo apt install linux-tools-generic hwdata
sudo update-alternatives --install /usr/local/bin/usbip usbip /usr/lib/linux-tools/*-generic/usbip 20

PowerShell で usbipd wsl list を実行

PS C:\Windows\system32> usbipd wsl list
BUSID  VID:PID    DEVICE                                                        STATE
2-2    303a:1001  USB シリアル デバイス (COM17), USB JTAG/serial debug unit     Not attached
2-3    046d:c058  USB 入力デバイス                                              Not attached
2-5    1199:90b1  Sierra Wireless EM7431 Qualcomm® Snapdragon™ X16 LTE-A, S...  Not attached
2-7    5986:118f  USB FHD Camera, IR Camera, Camera DFU Device                  Not attached
2-8    06cb:00c6  Synaptics UWP WBDI                                            Not attached
2-10   8087:0033  インテル(R) ワイヤレス Bluetooth(R)                           Not attached

PowerShellで以下を実行

usbipd wsl attach --busid <busid>

今回の場合、USBシリアルデバイスは、2-2なので、以下となる

PS C:\Windows\system32> usbipd wsl attach --busid 2-2

Ubuntuで確認

$ 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

$ ls /dev/ttyACM0
/dev/ttyACM0

ボードとは通信できているようなのだが・・

$ cargo espflash   board-info
[2023-11-05T08:18:59Z INFO ] Serial port: '/dev/ttyACM0'
[2023-11-05T08:18:59Z INFO ] Connecting...
[2023-11-05T08:18:59Z INFO ] Using flash stub
Chip type:         esp32c3 (revision v0.4)
Crystal frequency: 40MHz
Flash size:        4MB
Features:          WiFi, BLE
MAC address:       34:85:18:00:FF:FF

念のためFlashを消去

$ cargo espflash  erase-flash
[2023-11-05T08:20:38Z INFO ] Serial port: '/dev/ttyACM0'
[2023-11-05T08:20:38Z INFO ] Connecting...
[2023-11-05T08:20:38Z INFO ] Using flash stub
[2023-11-05T08:20:38Z INFO ] Erasing Flash...

焼いてみる。成功した(Flash削除せずにやったら失敗したのだが)

$ cargo espflash flash
[2023-11-05T08:25:26Z INFO ] Serial port: '/dev/ttyACM0'
[2023-11-05T08:25:26Z INFO ] Connecting...
[2023-11-05T08:25:26Z INFO ] Using flash stub
    Finished dev [unoptimized + debuginfo] target(s) in 3.82s
Chip type:         esp32c3 (revision v0.4)
Crystal frequency: 40MHz
Flash size:        4MB
Features:          WiFi, BLE
MAC address:       34:85:18:00:b3:ac
App/part. size:    225,472/4,128,768 bytes, 5.46%
[00:00:00] [========================================]      13/13      0x0
[00:00:00] [========================================]       1/1       0x8000
[00:00:02] [========================================]      73/73      0x10000
[2023-11-05T08:25:33Z INFO ] Flashing has completed!

espflashのmonitor機能でUSBから出力されているはずの文字列を読もうとするが読めない・・なぜだろうか。暴走している?

$ cargo espflash monitor
[2023-11-05T08:40:30Z INFO ] Serial port: '/dev/ttyACM0'
[2023-11-05T08:40:30Z INFO ] Connecting...
[2023-11-05T08:40:30Z INFO ] Using flash stub
Commands:
    CTRL+R    Reset chip
    CTRL+C    Exit

no_std版でLチカさせてみるがチカっとしない。やっぱり暴走しているのかstartupがうまくいっていないのか・・ open-ocdでデバッグ必要か!?

#![no_std]
#![no_main]

use esp_backtrace as _;
use esp_println::println;
use hal::{clock::ClockControl, gpio::IO, peripherals::Peripherals, prelude::*, Delay};

#[entry]
fn main() -> ! {
    let peripherals = Peripherals::take();
    let system = peripherals.SYSTEM.split();

    let clocks = ClockControl::max(system.clock_control).freeze();
    let mut delay = Delay::new(&clocks);

    let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
    //let mut led = io.pins.gpio8.into_push_pull_output();   // for xiao
    //let mut led = io.pins.gpio7.into_push_pull_output();     // for Eva Board
    let mut monitor = io.pins.gpio0.into_push_pull_output();     // GPIO0

    println!("Hello world!");
    loop {
        println!("Loop...");
        monitor.toggle().unwrap();
        delay.delay_ms(500u32);

    }
}

Rustのno-std bookがあるのでこれを読んで復習
Introduction - Embedded Rust (no_std) on Espressif

espflashツールは以下の通り2つ入れるべし

cargo install cargo-espflash espflash

各種ライブラリが必要(すでに入れたのもあるし、新たに入ったのもある)

sudo apt install llvm-dev libclang-dev clang

no_std版のトレーニング資料一式を落とす

git clone "https://github.com/esp-rs/no_std-training.git"
cd no_std-training

HelloWorldのビルドサンプルがあるので、チュートリアルに従ってビルドしてみる。
Hello World - Embedded Rust (no_std) on Espressif
ビルド自体はすんなり動いてモニタのところまでは進んだ。するとどうも内部でリセットが発生しているようであった。

     Running `espflash flash --monitor target/riscv32imc-unknown-none-elf/debug/hello_world`
[2023-11-05T09:15:35Z INFO ] Serial port: '/dev/ttyACM0'
[2023-11-05T09:15:35Z INFO ] Connecting...
[2023-11-05T09:15:36Z INFO ] Using flash stub
Chip type:         esp32c3 (revision v0.4)
Crystal frequency: 40MHz
Flash size:        4MB
Features:          WiFi, BLE
MAC address:       34:85:18:00:FF:FF
App/part. size:    194,304/4,128,768 bytes, 4.71%
[00:00:00] [========================================]      13/13      0x0
[00:00:00] [========================================]       1/1       0x8000
[00:00:01] [========================================]      61/61      0x10000
[2023-11-05T09:15:38Z INFO ] Flashing has completed!
Commands:
    CTRL+R    Reset chip
    CTRL+C    Exit

ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0x4 (DOWNLOAD(USB/UART0/1))
Saved PC:0x40380836
0x40380836 - esp_hal_common::interrupt::riscv::vectored::handle_interrupts
    at /home/<user_id>/.cargo/registry/src/index.crates.io-6f17d22bba15001f/esp-hal-common-0.12.0/src/interrupt/riscv.rs:214
waiting for download

起動のためのソフトリセットなのか、それとも何か問題が発生してExceptionが発生しているのか。。
該当ソースは以下の様であるが、、多分Exceptionが発生して飛んできたということだと推測

207     unsafe fn handle_interrupts(cpu_intr: CpuInterrupt, context: &mut TrapFrame) {
208         let status = get_status(crate::get_core());
209
210         // this has no effect on level interrupts, but the interrupt may be an edge one
211         // so we clear it anyway
212         clear(crate::get_core(), cpu_intr);
213
214         let configured_interrupts = get_configured_interrupts(crate::get_core(), status);

メッセージは異なるが、waiting for download でおかしくなるという書き込みがあったので内容を確認
ESP32-C3 Stuck waiting for download - ESP32 Forum
相談している人は起動モードを管理する、GPIO9 のレベルがおかしいのでは?という回答であった。

細かい理由は分からないが、一旦ボードをUSBケーブルから抜いて再度接続するとLEDが点滅した。だから、、起動オプションがダウンロードモードのままで固定されていたためと考える。USBで接続する時これまではBootボタンを押して接続していたのだがそれが原因だろうか。今だとダウンロードモードではなく、普通の実行モードなので、この状態でFlashに書き込めるか試してみる。

何がどういう理由でこういうことになるのか、詳細が分からないのだが、、普通に走っている状態で、WSLからUSBがアクセスできるようにする。その後、espflash monitorを実行すると、LEDの点滅が止まる。なぜ止まるのか? ダウンロードモードに遷移するからなのか?
ここで、Ctrl+Rでリセットを送信?すると、ボードは再起動されて、シリアル出力がなされた。

[2023-11-05T10:06:00Z INFO ] Using flash stub
Commands:
    CTRL+R    Reset chip
    CTRL+C    Exit

ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0xc (SPI_FAST_FLASH_BOOT)
Saved PC:0x40380836
SPIWP:0xee
mode:DIO, clock div:2
load:0x3fcd5820,len:0x171c
load:0x403cc710,len:0x968
load:0x403ce710,len:0x2f68
SHA-256 comparison failed:
Calculated: 1d06b938c0222bf626e0bdf46178b1b37ab24d03f0360fc8fcf7153c2571deaf
Expected: 68d7bdf643ba446b8ed7ae8423241d442fd052b2bc77091100ba06fd65dcf8d5
Attempting to boot anyway...
entry 0x403cc710
I (43) boot: ESP-IDF v5.1-beta1-378-gea5e0ff298-dirt 2nd stage bootloader
I (43) boot: compile time Jun  7 2023 07:59:10
I (44) boot: chip revision: v0.4
I (48) boot.esp32c3: SPI Speed      : 40MHz
I (53) boot.esp32c3: SPI Mode       : DIO
I (57) boot.esp32c3: SPI Flash Size : 4MB
I (62) boot: Enabling RNG early entropy source...
I (68) boot: Partition Table:
I (71) boot: ## Label            Usage          Type ST Offset   Length
I (78) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (86) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (93) boot:  2 factory          factory app      00 00 00010000 003f0000
I (101) boot: End of partition table
I (105) esp_image: segment 0: paddr=00010020 vaddr=3c030020 size=05cb4h ( 23732) map
I (119) esp_image: segment 1: paddr=00015cdc vaddr=40380000 size=00fa0h (  4000) load
I (123) esp_image: segment 2: paddr=00016c84 vaddr=00000000 size=09394h ( 37780)
I (138) esp_image: segment 3: paddr=00020020 vaddr=42000020 size=21128h (135464) map
I (169) boot: Loaded app from partition at offset 0x10000
I (169) boot: Disabling RNG early entropy source...
Hello world!

ソースを微修正して走らせると、今回はいったん割り込みが発生したものの、どうにかしてリブートしたようである

cargo run --example blinky

    *略*

[2023-11-05T10:10:42Z INFO ] Using flash stub
Chip type:         esp32c3 (revision v0.4)
Crystal frequency: 40MHz
Flash size:        4MB
Features:          WiFi, BLE
MAC address:       34:85:18:00:b3:ac
App/part. size:    201,120/4,128,768 bytes, 4.87%
[00:00:00] [========================================]      13/13      0x0
[00:00:00] [========================================]       1/1       0x8000
[00:00:01] [========================================]      64/64      0x10000
[2023-11-05T10:10:45Z INFO ] Flashing has completed!
Commands:
    CTRL+R    Reset chip
    CTRL+C    Exit

ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0xc (SPI_FAST_FLASH_BOOT)
Saved PC:0x40380836
0x40380836 - esp_hal_common::interrupt::riscv::vectored::handle_interrupts
    at /home/sumi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/esp-hal-common-0.12.0/src/interrupt/riscv.rs:214
SPIWP:0xee
mode:DIO, clock div:2
load:0x3fcd5820,len:0x171c
0x3fcd5820 - _stack_start
    at ??:??
load:0x403cc710,len:0x968
0x403cc710 -
    at ??:??
load:0x403ce710,len:0x2f68
0x403ce710 -
    at ??:??
SHA-256 comparison failed:
Calculated: 1d06b938c0222bf626e0bdf46178b1b37ab24d03f0360fc8fcf7153c2571deaf
Expected: 68d7bdf643ba446b8ed7ae8423241d442fd052b2bc77091100ba06fd65dcf8d5
Attempting to boot anyway...
entry 0x403cc710
0x403cc710 -
    at ??:??
I (43) boot: ESP-IDF v5.1-beta1-378-gea5e0ff298-dirt 2nd stage bootloader
I (43) boot: compile time Jun  7 2023 07:59:10
I (44) boot: chip revision: v0.4
I (48) boot.esp32c3: SPI Speed      : 40MHz
I (53) boot.esp32c3: SPI Mode       : DIO
I (57) boot.esp32c3: SPI Flash Size : 4MB
I (62) boot: Enabling RNG early entropy source...
I (68) boot: Partition Table:
I (71) boot: ## Label            Usage          Type ST Offset   Length
I (78) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (86) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (93) boot:  2 factory          factory app      00 00 00010000 003f0000
I (101) boot: End of partition table
I (105) esp_image: segment 0: paddr=00010020 vaddr=3c030020 size=05cc4h ( 23748) map
I (119) esp_image: segment 1: paddr=00015cec vaddr=40380000 size=00fa0h (  4000) load
I (123) esp_image: segment 2: paddr=00016c94 vaddr=00000000 size=09384h ( 37764)
I (138) esp_image: segment 3: paddr=00020020 vaddr=42000020 size=2115ch (135516) map
I (169) boot: Loaded app from partition at offset 0x10000
I (169) boot: Disabling RNG early entropy source...
Hello world!
z..
z..
z..
z..
z..
z..

GPIOのL/Hが動いたということで、waitを外してどれぐらいの性能が出るのかを試した。結果、L/Hをループするのに9.2usで周波数で言うと、108.7KHz。これはさすがに遅すぎないか?システムクロックが落とされているから?
SystemClockが何MHzなのか知りたいところだが、、指定できるのはデフォルト40MHz固定らしい(ここから逓倍しているのか?)。ちょっとよく分からず。SystemClockは仕様通りと期待して、最適化オプションを期待してビルドしてみる。以下でビルド

cargo build --release 

target/riscv32imc-unknown-none-elf/release配下にblinkのバイナリが生成されるのでこれを焼いてみる。ループの周期を計測すると、580nsで周波数で言うと、1.72MHzであった。40MHzで動いていたとしたら1/40なのでまぁそんなものですか・・・という感じだが、最高速の120MHzで動いていたらかなり遅い。オーバーヘッドがでかすぎる。まぁそんなに速度を求めるならハードでLHしろよとか、周辺I/Oレジスタを直接叩いたらええやんと言われそうですが・・ コンパイル型言語ならではの速度が出ていて欲しかったという希望なのでした。
元々は、MEMS マイクのPDMの出力を取りこぼさずに全部受け取るというためだったので、、1.72MHzでも仕様範囲内ではある。
■参考URL
USB デバイスを接続する | Microsoft Learn
ClockControl in esp32h2_hal::clock - Rust