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でビルドからやったらいいのか。。))
■追記(2024/6/22)
かなり時間が経って、適当なサンプルソースでcargo buildを実行したらエラーになった。エラーメッセージとしては、espidf.constraints.v5.1.txt doesn't exist. で、 forgotten to run the install scripts ではないか?と指摘されている。。

  Using managed esp-idf repository: RemoteSdk { repo_url: None, git_ref: Tag("v5.1.1") }
  Using esp-idf v5.1.1 at '/mnt/c/cygwin64/home/<foo>/lang/rust/esp32-c3/aq-sensor/.embuild/espressif/esp-idf/v5.1.1'
  ERROR: /mnt/c/cygwin64/home/<foo>/lang/rust/esp32-c3/aq-sensor/.embuild/espressif/espidf.constraints.v5.1.txt doesn't exist. Perhaps you've forgotten to run the install scripts. Please check the installation guide for more information.
  CMake Error at /mnt/c/cygwin64/home/<foo>/lang/rust/esp32-c3/aq-sensor/.embuild/espressif/esp-idf/v5.1.1/tools/cmake/build.cmake:363 (message):

素のプロジェクト(?)を作るところからやってみる

~/lang/rust/esp32-c3$ cargo generate esp-rs/esp-idf-template cargo
⚠️   Favorite `esp-rs/esp-idf-template` not found in config, using it as a git repository: https://github.com/esp-rs/esp-idf-template.git
🤷   Project Name: test_20240622
⚠️   Renaming project called `test_20240622` to `test-20240622`...               # アンダースコアはだめですと・・
~/lang/rust/esp32-c3/test-20240622$ cargo build

上記コマンドは以下のドキュメントに基づく(std版のプロジェクトの作り方より)
Generating Projects from Templates - The Rust on ESP Book

その後、めちゃくちゃ時間がかかったものの、素から作ったProjectはmain関数実質空だがビルドは終わった。

   Compiling test-20240622 v0.1.0 (/mnt/c/cygwin64/home/sumi/lang/rust/esp32-c3/test-20240622)
   Compiling enumset v1.1.3
   Compiling embedded-svc v0.27.1
    Finished `dev` profile [optimized + debuginfo] target(s) in 42m 01s
~/lang/rust/esp32-c3/test-20240622$

WSL環境でUSB-Serialを使うべく、いつものUSB透過作業を行う。そして、、またエラー

$ 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 シリアル デバイス (COM18), USB JTAG/serial debug unit             Shared
2-7    5986:118f  USB FHD Camera, IR Camera, Camera DFU Device
Not shared
2-8    06cb:00c6  Synaptics UWP WBDI
Not shared
2-10   8087:0033  インテル(R) ワイヤレス Bluetooth(R)
         Not shared

Persisted:
GUID                                  DEVICE
53xxxx94-cb46-448b-890b-6bxxxxxxx6fc  Silicon Labs CP210x USB to UART Bridge (COM15)
b2xxxxee-275b-44bd-905e-387xxxxxxc5  USB シリアル デバイス (COM17), USB JTAG/serial debug unit

usbipd: warning: The VBoxUsbMon driver is not correctly installed; a repair or re-install of this software should fix that.

$ usbipd attach --wsl --busid=2-6
usbipd: error: The VBoxUsbMon driver is not correctly installed; a repair or re-install of this software should fix that.

少し調べると、同じエラーに出くわしている人がいて、再インストールしたら解消するらしい

 I had to uninstall, then install again and now i don't get the VboxUsbMon missing error.

この方法が正しいのか分からないが、Cygwin環境から以下を実行

$ winget install --interactive --exact dorssel.usbipd-win
$ usbipd --version
4.2.0+54.Branch.master.Sha.5b36605535dd52bc3d8a8e4bbaee7f4d480c86ad

更新前のバージョン(エラー発生したバージョン)は以下であった。だから、4.1.0 -> 4.2.0に上がった。

$ usbipd --version
4.1.0+52.Branch.master.Sha.b0b7589d2dc4481b1af481787d6d773f46d0758a

今度はエラーなく動作した

$ 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.

Ubuntu側からUSB-Serialが見えたと思われる

ubuFV4$ ls -l /dev/ttyACM0
crw-rw---- 1 root dialout 166, 0 Jun 22 19:54 /dev/ttyACM0

コマンドがダブっているような気もするが、過去の記録に従ってflashを焼いてみる。。。焼けた

ubuFV4$ cargo espflash flash
           *略*
Chip type:         esp32c3 (revision v0.3)
Crystal frequency: 40 MHz
Flash size:        4MB
Features:          WiFi, BLE
MAC address:       58:cf:79:f3:6a:24
App/part. size:    497,008/4,128,768 bytes, 12.04%
[00:00:00] [========================================]      13/13      0x0
[2024-06-22T11:03:29Z INFO ] Segment at address '0x8000' has not changed, skipping write
[00:00:04] [========================================]     245/245     0x10000
[2024-06-22T11:03:35Z INFO ] Flashing has completed!

main関数にはLチカ等コードを追加していないので何も変化がない・・・次はLチカをしてみることに。
下記のソースでLチカまではできた。

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();

    log::info!("Hello, world!");

    let peripherals = Peripherals::take().unwrap();
    let mut p0 = PinDriver::output(peripherals.pins.gpio2)?;

    loop{
        print!("-----ok??----------\n");
        p0.set_high()?;
        sleep(Duration::from_millis(100));
        print!("-----zzz----------\n");
        p0.set_low()?;
        sleep(Duration::from_millis(100));
    }
}

次はSoft-I2Cドライバを入れて、気圧センサの値を読み取る *4

サンプルコードを作るたびにプロジェクトを作っているので、毎回esp-idf-sysのビルドが走る。esp-idf-sysのビルドがめちゃくちゃ時間かかる。できればesp-idf-sysは使いまわししたい。そこで、、一つのプロジェクト内に複数の実行ファイルを作る方法で試作を量産すればよい。そうすればビルドに時間のかかるesp-idf-sysは使いまわせる。
参考記事:
複数の実行ファイル - Rust | nju33


■参考URL
std - Rust
Inter-Integrated Circuit (I2C) - ESP32-C3 - — ESP-IDF Programming Guide v5.2.2 documentation

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

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

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

*4: ESP32C3には周辺IOのI2Cは一つしか入っていないので、2つ目のセンサはソフトウエアでI2Cバスを作り出す予定(I2Cは複数のデバイスを接続できるでしょう?と言われそうですが・・)