chakokuのブログ(rev4)

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

改めて組み込み用Rustを入れる

課題:ずっと放置していた空気質観測プログラムに気圧計測を加えたい。久しぶりにRustでビルドするとエラーになった
対策:ビルド環境を作り直す(std用)*1
参考資料:Introduction - The Rust on ESP Book
結論:評価ボード(ESP32-C3-Devkit-RUST-1)を使ったLチカまでは確認できた(環境構築と動作確認に半日かかってしまった)
詳細:

途中ちょっと記録が曖昧になったがおおよそ以下
(1)rustupを入れる

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

rustup.rs - The Rust toolchain installer
(2)toolchainを入れる

rustup toolchain install nightly --component rust-src

RISC-V targets only - The Rust on ESP Book
(3)その他ツール類を入れる(自分の環境にはすでに入ってるのでスキップ)*2

cargo install ldproxy

std Development Requirements - The Rust on ESP Book
ldproxy以外にも種々ツールが必要(スキップ)

sudo apt-get install git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0

(4)cargo-generateを入れる

cargo install cargo-generate

Generating Projects from Templates - The Rust on ESP Book
(5)cargo-generateを使ってtemplate(esp-idf-template)をベースにしたプロジェクトを作成

cargo generate esp-rs/esp-idf-template cargo

(6)ビルドしてみる

cargo build

hello worldをprintするだけのソースだが、ビルドは通った。

調子にのってcago runしたら怒られた(WSLなのでUSBが透過に設定していないのでエラーになるのは想定していたが、、epsflashが無いと)

cargo run
   Compiling esp-idf-hal v0.43.1
   Compiling esp-idf-svc v0.48.1
   Compiling template-test-20240420 v0.1.0 (/mnt/c/cygwin64/home/sumi/lang/rust/esp32-c3/template-test-20240420)
    Finished `dev` profile [optimized + debuginfo] target(s) in 5m 28s
     Running `espflash flash --monitor target/riscv32imc-esp-espidf/debug/template-test-20240420`
error: could not execute process `espflash flash --monitor target/riscv32imc-esp-espidf/debug/template-test-20240420` (never executed)

Caused by:
  No such file or directory (os error 2)

cargo配下で動くespflashを入れる*3

cargo install cargo-espflash

espflash - The Rust on ESP Book

cargo runではespflashが正しく起動できないので手で起動してみた

$ cargo espflash flash
Error: espflash::no_serial

  × No serial ports could be detected
  help: Make sure you have connected a device to the host system. If the device is connected but not listed, try
        using the `--list-all-ports` flag.

USBを透過させていないのと、port指定もしていないのでエラーになった。残る作業としては、評価ボードを接続して、USBを透過させて、/dev/ttyXXXと指定したらflash焼けるのではと期待

WSLからUSBが見えるようにWindows側で作業、エラーになる

$  usbipd wsl attach --busid 2-6
usbipd: error: WSL 'usbip' client not correctly installed. See https://github.com/dorssel/usbipd-win/wiki/WSL-support for the latest instructions.

ちょっと検索すると、以下の記述あり

Ubuntu 側で sudo update-alternatives --install を実行してください。

https://another.maple4ever.net/archives/3221/

attachでエラーになったのはusbipdのバージョンが古いせいであった。最新版に上げてテストすると正常にattachできた。

$ usbipd --version
4.1.0+52.Branch.master.Sha.b0b7589d2dc4481b1af481787d6d773f46d0758a
$ usbipd list
Connected:
BUSID  VID:PID    DEVICE                                                        STATE
2-2    046d:c058  USB 入力デバイス                                              Not shared
2-5    1199:90b1  Sierra Wireless EM7431 Qualcomm® Snapdragon™ X16 LTE-A, S...  Not shared
2-6    303a:1001  USB シリアル デバイス (COM17), USB JTAG/serial debug unit     Shared

Persisted:
GUID                                  DEVICE
530a5594-cb46-448b-890b-xxxx  Silicon Labs CP210x USB to UART Bridge (COM15)
6b9e6ec4-1707-401f-8d5d-xxxx  USB シリアル デバイス (COM18), USB JTAG/serial debug unit

$ usbipd attach --wsl --busid=2-6
usbipd: info: Using WSL distribution 'Ubuntu' to attach; the device will be available in all WSL 2 distributions.
usbipd: info: Using IP address 172.17.96.1 to reach the host.

特にデバイス名等指定せずに、cargo-espflashを実行してみるー>/dev/ttyACM0を見つけて接続して正常に焼けた

$ cargo espflash flash
[2024-04-20T10:15:34Z INFO ] Serial port: '/dev/ttyACM0'
[2024-04-20T10:15:34Z INFO ] Connecting...
[2024-04-20T10:15:34Z INFO ] Using flash stub
    Finished `dev` profile [optimized + debuginfo] target(s) in 5.58s
Chip type:         esp32c3 (revision v0.4)
Crystal frequency: 40 MHz
Flash size:        4MB
Features:          WiFi, BLE
MAC address:       34:85:18:00:b3:ac
App/part. size:    497,104/4,128,768 bytes, 12.04%
[00:00:00] [========================================]      13/13      0x0
[00:00:00] [========================================]       1/1       0x8000
[00:00:05] [========================================]     245/245     0x10000
[2024-04-20T10:15:47Z INFO ] Flashing has completed!

cargo-espflashはmonitor機能があり、デバッグ出力を表示させることができる。何も表示されないのは起動時に一回しかlog出力していないためと思われる。

$ cargo espflash monitor
[2024-04-20T10:19:04Z INFO ] Serial port: '/dev/ttyACM0'
[2024-04-20T10:19:04Z INFO ] Connecting...
[2024-04-20T10:19:05Z INFO ] Using flash stub
Commands:
    CTRL+R    Reset chip
    CTRL+C    Exit

サンプルソースに手を加えてLチカとログ出力まではできたので今後の再確認用にソース貼り付け
file: Cargo.toml

[package]
name = "template-test-20240420"
version = "0.1.0"
authors = [foobarbazfred]
edition = "2021"
resolver = "2"
rust-version = "1.71"

[profile.release]
opt-level = "s"

[profile.dev]
debug = true    # Symbols are nice and they don't increase the size on Flash
opt-level = "z"

[features]
default = ["std", "embassy", "esp-idf-svc/native"]

pio = ["esp-idf-svc/pio"]
std = ["alloc", "esp-idf-svc/binstart", "esp-idf-svc/std"]
alloc = ["esp-idf-svc/alloc"]
nightly = ["esp-idf-svc/nightly"]
experimental = ["esp-idf-svc/experimental"]
embassy = ["esp-idf-svc/embassy-sync", "esp-idf-svc/critical-section", "esp-idf-svc/embassy-time-driver"]

[dependencies]
log = { version = "0.4", default-features = false }
esp-idf-svc = { version = "0.48", default-features = false }
anyhow = "1.0.79"

[build-dependencies]
embuild = "0.31.3"

file: src/main.rs

use anyhow::Result;
use std::{thread::sleep, time::Duration};
use esp_idf_svc::hal::gpio::PinDriver;
use esp_idf_svc::hal::peripherals::Peripherals;

fn main() -> Result<()> {

    esp_idf_svc::sys::link_patches();
    esp_idf_svc::log::EspLogger::initialize_default();
    let peripherals = Peripherals::take().unwrap();
    let mut led = PinDriver::output(peripherals.pins.gpio7)?;

    loop{
        log::info!("Hello, world!");
        led.set_high()?;
        sleep(Duration::from_secs(2));
        led.set_low()?;
        sleep(Duration::from_secs(2));
    }
}

espflashのモニタ機能でデバッグ出力を表示

$ cargo espflash monitor
//     Ctrl+Rで一度リセットをかける
I (371) template_test_20240420: Hello, world!
I (4381) template_test_20240420: Hello, world!
I (8381) template_test_20240420: Hello, world!
I (12381) template_test_20240420: Hello, world!
I (16381) template_test_20240420: Hello, world!
I (20381) template_test_20240420: Hello, world!
I (24381) template_test_20240420: Hello, world!

■補足

error: linker `ldproxy` not found
  |
  = note: No such file or directory (os error 2)

error: could not compile `template-test-20240420` (bin "template-test-20240420") due to 1 previous error

あるはずと思って入れなかったldproxyが無いと怒られた。
インストール後、場所を確認、.cargoの下に置かれていた(ディレクトリごと消したので無くなっていた)

$ whereis ldproxy
ldproxy: /home/<uid>/.cargo/bin/ldproxy

WSL(Ubuntu)側で確認すると下記の通り、/dev/ttyACM0が利用可能になっている

$ ls -l /dev/ttyACM0
crw-rw---- 1 root dialout 166, 0 Apr 20 19:10 /dev/ttyACM0

■補足
前回Docker環境で作ったはずなのだが、どこに作ったのか失念(ブログを読み返すと書いてるだろうけど、、そこまでやる気力がない)。Dockerってイマイチ使いこなせてなくて、ベストプラクティスがよく分からん(原因は勉強不足なのだが (コンテナ用にビルドした結果から新しいコンテナ用イメージを作って新イメージを使うべきなのか、イメージを作らなくても毎回dockefileでビルドからやったらいいのか。。))

■参考URL
std - Rust

*1:これまでに何回ビルド環境を構築したことだろうか・・・

*2:スキップしたらビルド時にエラーになったのでインストールした

*3:espflashってflash writeのようなものと理解していますが、espflashをビルドするのに489パッケージ必要とは・・大げさすぎないか?