chakokuのブログ(rev4)

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

Dockerで組み込みRust 開発環境を作る(後半)

背景:LinuxのホストOSにRustビルド環境を入れたが、インストール手順が試行錯誤で、正しく入ったのかあやうい
取り組み:インストール手順をDockerファイルに定義してDocker内に組み込みRust開発環境を作る
進捗:イメージまではだいたいできた。コンテナ内で作業すればビルドはできる。一方、cargo build等、ホスト環境からコマンドを実行するようにDockerコンテナを起動してビルドするレベルまでは仕上がっていない。


詳細は以下:
前回はDockerを使ってコンテナ内に組み込みRust用ビルド環境を途中まで構築した
()
これからやるべきこと
The Rust on ESP Bookの、RISC-V targets only を参照

rustup toolchain install nightly --component rust-src    // 前回はここまで終わっている

LLVMを入れる (apt install clang)
std用開発環境を入れる ( python, git , ldproxy (cargo install ldproxy))

前回途中まで作ったDockerfileに対して、残りの、cargo-generateやespflash等を追加
file: Dockerfile

FROM debian:bullseye-slim
RUN apt-get update \
  && apt-get install --yes curl \
  && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rustup-init.sh \
  && chmod +x /tmp/rustup-init.sh \
  && /tmp/rustup-init.sh -y \
  && . "$HOME/.cargo/env" \
  && rm /tmp/rustup-init.sh
RUN apt-get install --yes clang  python3 python3-pip git pkg-config  libudev-dev libssl-dev \
  && python3 -m pip install pip --upgrade
RUN . "$HOME/.cargo/env" \
  && rustup toolchain install nightly-2023-02-28 --component rust-src \
  && cargo install ldproxy \
  && cargo install cargo-generate \
  && cargo install espflash \
  && cargo install cargo-espflash

イメージをビルドしてみる

sudo docker build -t rust_buld_rustup_cargogen:0.1 .

今回はイメージをビルドするのに20分近くかかった。

[+] Building 1177.1s (8/8) FINISHED   

コンテナに入って何かするような使い方は想定していないが、テストのために入ってビルドしてみる

sudo docker run -it rust_buld_rustup_cargogen:0.1 /bin/bash
root@176a8cc24824:/app# cargo generate --git https://github.com/esp-rs/esp-idf-template cargo
Error: could not determine the current user, please set $USER

root@176a8cc24824:/app# export USER=root

root@176a8cc24824:/app# cargo generate --git https://github.com/esp-rs/esp-idf-template cargo
 Project Name: hello
 Destination: /app/hello ...
 project-name: hello ...
 Generating template ...
✔  Which MCU to target? · esp32c3
✔  Configure advanced template options? · false
 Moving generated files into: `/app/hello`...
Initializing a fresh Git repository
 Done! New project created /app/hello

root@176a8cc24824:/app# cd hello/
root@176a8cc24824:/app/hello# cargo build

これは何だったか忘れたがビルドはできた

    Finished dev [optimized + debuginfo] target(s) in 6m 43s
root@176a8cc24824:/app/hello/target/riscv32imc-esp-espidf/debug# ls -ltrh
total 18M
drwxr-xr-x  2 root root 4.0K Jul  8 23:24 examples
drwxr-xr-x 16 root root 4.0K Jul  8 23:24 build
drwxr-xr-x  3 root root 4.0K Jul  8 23:31 incremental
-rwxr-xr-x  2 root root  18M Jul  8 23:31 hello
drwxr-xr-x  2 root root  12K Jul  8 23:31 deps
-rw-r--r--  1 root root   96 Jul  8 23:31 hello.d

素のhello worldであった

use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
use log::*;

fn main() {
    // It is necessary to call this function once. Otherwise some patches to the runtime
    // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
    esp_idf_sys::link_patches();
    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    info!("Hello, world!");
}

espflashを使ってFlashに焼いてみる

root@176a8cc24824:/app/hello# cargo run
    Finished dev [optimized + debuginfo] target(s) in 0.14s
     Running `espflash flash --monitor target/riscv32imc-esp-espidf/debug/hello`
✔ Use serial port '/dev/ttyACM0'? · yes
[2023-07-08T23:47:57Z INFO ] Serial port: '/dev/ttyACM0'
[2023-07-08T23:47:57Z INFO ] Connecting...
Error: espflash::connection_failed

  x Failed to open serial port /dev/ttyACM0
  |-> Failed to open serial port /dev/ttyACM0
  |-> Error while connecting to device
  `-> Serial port not found
  help: Ensure that the device is connected and your host recognizes the serial adapter

エラーになった。これは、コンテナ側から、/dev/ttyACM0が見えてないせいと思われる。

先人の記事より、docker起動時に以下を指定するらしい(感謝:XPT60様)

--device=/dev/<port_on_host>:/dev/<port_on_container> 

だいたいこれで作ったイメージはビルドに使えそうだということで、、ストレージ外だし化に取り組む。
マウントポイント?用に/appを加える(これがDocker的に標準作法なのかどうかわからず)

FROM debian:bullseye-slim
RUN apt-get update \
  && apt-get install --yes curl \
  && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rustup-init.sh \
  && chmod +x /tmp/rustup-init.sh \
  && /tmp/rustup-init.sh -y \
  && . "$HOME/.cargo/env" \
  && rm /tmp/rustup-init.sh
RUN apt-get install --yes clang  python3 python3-pip git pkg-config  libudev-dev libssl-dev \
  && python3 -m pip install pip --upgrade
RUN . "$HOME/.cargo/env" \
  && rustup toolchain install nightly-2023-02-28 --component rust-src \
  && cargo install ldproxy \
  && cargo install cargo-generate \
  && cargo install espflash \
  && cargo install cargo-espflash
RUN mkdir /app
sudo docker run --volume /home/rustbld00/lang/rust:/app   --device=/dev/ttyACM0:/dev/ttyACM0  -it rust_buld_rustup_cargogen_app:0.1 /bin/bash

まだ起動ー>自動でビルドまで到達できていないので(最終形態とは異なりながら)コンテナに入って作業してみる

cd  /app
export USER=root
cargo generate --git https://github.com/esp-rs/esp-idf-template cargo
cd hello-world/
cargo run

cargo runでは設定が足りないのか焼き終わる所まで自動で進まなかったので、flash writeを手で起動

root@6862ab193237:/app/hello-world# espflash flash target/riscv32imc-esp-espidf/debug/hello-world
✔ Use serial port '/dev/ttyACM0'? · yes
[2023-07-09T00:18:40Z INFO ] Serial port: '/dev/ttyACM0'
[2023-07-09T00:18:40Z INFO ] Connecting...
[2023-07-09T00:18:40Z 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:xx
App/part. size:    484,864/4,128,768 bytes, 11.74%
[00:00:00] [========================================]      13/13      0x0                                                                                                       [00:00:00] [========================================]       1/1       0x8000                                                                                                    [00:00:04] [========================================]     241/241     0x10000                                                                                                   [2023-07-09T00:18:45Z INFO ] Flashing has completed!
root@6862ab193237:/app/hello-world# espflash monitor
✔ Use serial port '/dev/ttyACM0'? · yes
[2023-07-09T00:20:35Z INFO ] Serial port: '/dev/ttyACM0'
[2023-07-09T00:20:35Z INFO ] Connecting...
[2023-07-09T00:20:35Z INFO ] Using flash stub
Commands:
    CTRL+R    Reset chip
    CTRL+C    Exit

もうすでに起動が終わってるからメッセージもなし?
ストレージを外部に置いているので、コンテナが終了してもビルドしたファイル一式はホスト側に残っている。

rustbld00@MBP01:~/lang/rust/hello-world$ pwd
/home/rustbld00/lang/rust/hello-world
rustbld00@MBP01:~/lang/rust/hello-world$ ls
build.rs  Cargo.lock  Cargo.toml  rust-toolchain.toml  sdkconfig.defaults  src target

シリアル出力が取得できず、動ているのかどうかわからないのでLEDを点滅させてみた

root@6862ab193237:/app/hello-world# cat src/main.rs
// If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
use esp_idf_sys as _;
use log::*;
use esp_idf_hal::delay::FreeRtos;
use esp_idf_hal::gpio::*;
use esp_idf_hal::peripherals::Peripherals;
use anyhow::Result;


fn main() -> Result<()> {
    esp_idf_sys::link_patches();
    esp_idf_svc::log::EspLogger::initialize_default();

    info!("Hello, world!");
    println!("##### blink test ###");

    let peripherals = Peripherals::take().unwrap();
    let mut led = PinDriver::output(peripherals.pins.gpio7)?;
    let mut counter = 0;


    loop{
       counter += 1;
       println!("zzz...\n");
       FreeRtos::delay_ms(1000);
       info!("Hello, world!\n");
       println!("blink...\n");
       if counter %2 == 0 {
            led.set_high()?;
       } else {
            led.set_low()?;
       }
   }
}

LED点滅はできたが、シリアルコンソールに確認文字列が表示されない


Windows上で動作するTereTermから接続すると以下と表示された。プログラムとボードは正常に動作していて、受信側の問題と分かった。デバイス指定等がおかしいのかも

I (26384) hello_world: Hello, world!

blink...

zzz...

I (27384) hello_world: Hello, world!

blink...

zzz...

Ubuntu側で再度テスト、ホストOS側で、espflash serial-monitor を実行すると正しくシリアルデータを受信できた。
ただ、このバージョンは古くなってると思われる。(コマンドオプションも変わっているし・・)

rustbld00@MBP01:~$  espflash  serial-monitor /dev/ttyACM0
New version of espflash is available: v2.0.0

Serial port: /dev/ttyACM0
Connecting...

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:0x4004c51e
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=3c060020 size=20708h (132872) map
I (143) esp_image: segment 1: paddr=00030730 vaddr=3fc8a000 size=00d08h (  3336) load
I (144) esp_image: segment 2: paddr=00031440 vaddr=40380000 size=09ef0h ( 40688) load
I (158) esp_image: segment 3: paddr=0003b338 vaddr=00000000 size=04ce0h ( 19680)
I (163) esp_image: segment 4: paddr=00040020 vaddr=42000020 size=50048h (327752) map
I (240) boot: Loaded app from partition at offset 0x10000
I (240) boot: Disabling RNG early entropy source...
I (251) cpu_start: Pro cpu up.
I (260) cpu_start: Pro cpu start user code
I (261) cpu_start: cpu freq: 160000000
I (261) cpu_start: Application information:
I (263) cpu_start: Project name:     libespidf
I (268) cpu_start: App version:      1
I (273) cpu_start: Compile time:     Jul  9 2023 00:12:46
I (279) cpu_start: ELF file SHA256:  0000000000000000...
I (285) cpu_start: ESP-IDF:          8b94183-dirty
I (290) cpu_start: Min chip rev:     v0.3
I (295) cpu_start: Max chip rev:     v0.99
I (300) cpu_start: Chip rev:         v0.4
I (305) heap_init: Initializing. RAM available for dynamic allocation:
I (312) heap_init: At 3FC8BCC0 len 00050A50 (322 KiB): DRAM
I (318) heap_init: At 3FCDC710 len 00002950 (10 KiB): STACK/DRAM
I (325) heap_init: At 50000020 len 00001FE0 (7 KiB): RTCRAM
I (332) spi_flash: detected chip: generic
I (336) spi_flash: flash io: dio
I (341) sleep: Configure to isolate all GPIO pins in sleep state
I (346) sleep: Enable automatic switching of GPIO sleep configuration
I (354) cpu_start: Starting scheduler.
I (360) hello_world: Hello, world!
##### blink test ###
I (360) gpio: GPIO[7]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
zzz...
I (1370) hello_world: Hello, world!

blink...
zzz...
I (2370) hello_world: Hello, world!

blink...
zzz...

ホスト側のバージョンは、1.7.0で最新は2.0.0と表示されている

rustbld00@MBP01:~$ espflash --version
New version of espflash is available: v2.0.0

espflash 1.7.0

Setting Up a Development Environment - The Rust on ESP Book
Setting Up a Development Environment - The Rust on ESP Book
Rust開発環境 on Docker で Cargo new で "could not determine the current user, please set $USER" エラー - tyamaguc07's hatenablog
【docker】シリアルポートからデータを読む (u-blox 受信機) - Qiita