chakokuのブログ(rev4)

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

WSLにRustを入れる->素のWindows10でBluePillのLEDをLチカ

WSLにRustを入れる。普通にWSLに入れても途中でエラーになるので、逃げの手として、VMware上のUbuntuにRustを入れて、Rustが入ったディレクトリをtarで固めてWSL上のUbuntuにコピーする。
以下のコマンドは問題なく実行完了

rustup target add thumbv7em-none-eabi
rustup target add thumbv7m-none-eabi
cargo install cargo-binutils
rustup component add llvm-tools-preview

cargo-generateを入れる際にopensslがないと怒られるので対応(WSLで経験済み)。

$ cargo install cargo-generate

   Compiling regex-syntax v0.5.6
   Compiling miniz_oxide v0.3.6
error: failed to compile `cargo-generate v0.5.0`, intermediate artifacts can be found at `/tmp/cargo-install58HEg8`

Caused by:
  failed to run custom build command for `openssl-sys v0.9.55`

Caused by:
  process didn't exit successfully: `/tmp/cargo-install58HEg8/release/build/openssl-sys-f3f76be6d73ab789/build-script-main` (exit code: 101)
--- stdout
cargo:rustc-cfg=const_fn
cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_GNU_OPENSSL_LIB_DIR
X86_64_UNKNOWN_LINUX_GNU_OPENSSL_LIB_DIR unset
cargo:rerun-if-env-changed=OPENSSL_LIB_DIR
OPENSSL_LIB_DIR unset
cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_GNU_OPENSSL_INCLUDE_DIR
X86_64_UNKNOWN_LINUX_GNU_OPENSSL_INCLUDE_DIR unset
cargo:rerun-if-env-changed=OPENSSL_INCLUDE_DIR
OPENSSL_INCLUDE_DIR unset
cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_GNU_OPENSSL_DIR
X86_64_UNKNOWN_LINUX_GNU_OPENSSL_DIR unset
cargo:rerun-if-env-changed=OPENSSL_DIR
OPENSSL_DIR unset
run pkg_config fail: "Failed to run `\"pkg-config\" \"--libs\" \"--cflags\" \"openssl\"`: No such file or directory (os error 2)"

--- stderr
thread 'main' panicked at '

Could not find directory of OpenSSL installation, and this `-sys` crate cannot
proceed without this knowledge. If OpenSSL is installed and this crate had
trouble finding it,  you can set the `OPENSSL_DIR` environment variable for the
compilation process.

Make sure you also have the development packages of openssl installed.
For example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora.

If you're in a situation where you think the directory *should* be found
automatically, please open a bug at https://github.com/sfackler/rust-openssl
and include information about your system as well as this message.

$HOST = x86_64-unknown-linux-gnu
$TARGET = x86_64-unknown-linux-gnu
openssl-sys = 0.9.55


It looks like you're compiling on Linux and also targeting Linux. Currently this
requires the `pkg-config` utility to find OpenSSL but unfortunately `pkg-config`
could not be found. If you have OpenSSL installed you can likely fix this by
installing `pkg-config`.

', /home/xxxx/.cargo/registry/src/github.com-1ecc6299db9ec823/openssl-sys-0.9.55/build/find_normal.rs:155:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
$ pkg-config

Command 'pkg-config' not found, but can be installed with:

sudo apt install pkg-config
sudo apt install pkgconf

$ sudo apt install pkg-config

$ pkg-config --libs --cflags openssl
Package openssl was not found in the pkg-config search path.
Perhaps you should add the directory containing `openssl.pc'
to the PKG_CONFIG_PATH environment variable
No package 'openssl' found

opensslが見つからないと言ってるので、libssl-devをインストール

$ sudo apt-get install libssl-dev

$ pkg-config --libs --cflags openssl
-lssl -lcrypto

再度、cargo-generateをインストール、ビルドが正常に終了

cargo install cargo-generate

cortex-m-quickstartを落としてRustでビルドしてみる。。正常に終了

cd ~/lang/rust
cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart.git
cd cortex-m-quickstart/
cargo build --example hello

Rust版のBluePill用LチカをGitHubから落としてビルドしてみる

git clone   https://github.com/lupyuen/stm32-blue-pill-rust.git
cd stm32-blue-pill-rust.git
cargo build

panic関連でビルドエラー(これはWindows版でも出ていた)

$ cargo build
    Updating crates.io index
    Updating git repository `https://github.com/japaric/stm32f103xx`
    Updating git repository `https://github.com/japaric/stm32f103xx-hal`
  Downloaded void v1.0.2
  Downloaded embedded-hal v0.2.3
  Downloaded nb v0.1.2

   *略*

   Compiling cortex-m-rt v0.5.7
   Compiling panic-semihosting v0.3.0
error[E0557]: feature has been removed
  --> /home/<UserName>/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-semihosting-0.3.0/src/lib.rs:59:12
   |
59 | #![feature(panic_implementation)]
   |            ^^^^^^^^^^^^^^^^^^^^ feature has been removed
   |
   = note: subsumed by `#[panic_handler]`

error: cannot find attribute `panic_implementation` in this scope
  --> /home/<UserName>/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-semihosting-0.3.0/src/lib.rs:71:3
   |
71 | #[panic_implementation]
   |   ^^^^^^^^^^^^^^^^^^^^

error[E0554]: `#![feature]` may not be used on the stable release channel
  --> /home/<UserName>/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-semihosting-0.3.0/src/lib.rs:59:1
   |
59 | #![feature(panic_implementation)]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0554, E0557.
For more information about an error, try `rustc --explain E0554`.
error: could not compile `panic-semihosting`.

To learn more, run the command again with --verbose.

エラーメッセージから解釈すると、なくなったfeatureを使い続けているためのエラーのようだ。

error[E0557]: feature has been removed

パッケージ?のビルドでエラーが出ているが、Rustのコマンド類は正常に動いていると判断して、、VMware環境のUbuntuで作ったRust用ツール一式をtarで固めて、Ubuntu on WSLにコピーした。

tar cvfz  rust.tgz  .rustup .cargo

VMWareからコピーしてきたRust環境(on WSL)でbulePill用サンプルをビルドしてみる
GitHub - lupyuen/stm32-blue-pill-rust: Rust for STM32 Blue Pill with Visual Studio Code

cargo clean
cargo check --release
cargo build --release

先日前に遭遇した、panic_implementationのエラーが発生(VMwareUbuntu上のRustでも発生)

    Checking panic-semihosting v0.3.0
error[E0557]: feature has been removed
  --> /home/<UserName>/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-semihosting-0.3.0/src/lib.rs:59:12
   |
59 | #![feature(panic_implementation)]
   |            ^^^^^^^^^^^^^^^^^^^^ feature has been removed
   |
   = note: subsumed by `#[panic_handler]`

error: cannot find attribute `panic_implementation` in this scope
  --> /home/<UserName>/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-semihosting-0.3.0/src/lib.rs:71:3
   |
71 | #[panic_implementation]
   |   ^^^^^^^^^^^^^^^^^^^^

error[E0554]: `#![feature]` may not be used on the stable release channel
  --> /home/<UserName>/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-semihosting-0.3.0/src/lib.rs:59:1
   |
59 | #![feature(panic_implementation)]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0554, E0557.
For more information about an error, try `rustc --explain E0554`.
error: could not compile `panic-semihosting`.

To learn more, run the command again with --verbose.
warning: build failed, waiting for other jobs to finish...
error: build failed

噴飯モノ回避策:

file:/home/<UserName>/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-semihosting-0.3.0/src/lib.rs

の内容を、
https://github.com/rust-embedded/panic-semihosting/blob/master/src/lib.rs
で置き換え

ちなみに、、panic semihostingってのは、バイナリ実行時にpanicが発生した場合、panic要因をデバッグ環境に出力する機能らしい。開発向けの補助機能なんが。。手こずる。

やっと本体のコンパイルに入り、過去に遭遇した、deprecatedが出る(過去、Rust on Windows環境と同じ症状、ワークアラウンドで回避ずみ)

error: use of deprecated item 'bluepill_hal::prelude::_embedded_hal_digital_OutputPin::set_high': Deprecated because the methods cannot return errors. Users should use the traits in digital::v2.
  --> src/main.rs:52:13
   |
52 |         led.set_high();
   |             ^^^^^^^^
   |
note: the lint level is defined here
  --> src/main.rs:4:9
   |
4  | #![deny(warnings)]  //  If the Rust compiler generates a warning, stop the compilation with an error.
   |         ^^^^^^^^
   = note: `#[deny(deprecated)]` implied by `#[deny(warnings)]`

error: use of deprecated item 'bluepill_hal::prelude::_embedded_hal_digital_OutputPin::set_low': Deprecated because the methods cannot return errors. Users should use the traits in digital::v2.
  --> src/main.rs:59:13
   |
59 |         led.set_low();
   |             ^^^^^^^

error: aborting due to 2 previous errors

error: could not compile `stm32-blue-pill-rust`.

To learn more, run the command again with --verbose.

src/main.rsの設定を変更(逃げの一手。。言語仕様に詳しければ正しい回避策を取るけど、仕様詳細わからないので、コンパイルを通すのを優先)

//#![deny(warnings)]  //  If the Rust compiler generates a warning, stop the compilation with an error.

再度ビルドをやり直すが、次のエラーに遭遇

 cargo build --release
    *略*
  = note: rust-lld: error: unknown argument '-nostartfiles'
          rust-lld: error: unknown argument '-Wl,-Tlink.x'

error: aborting due to previous error
error: could not compile `stm32-blue-pill-rust`.

このエラーもWindows版Rustで経験済み、file: .cargo/config の定義を修正

"-C", "link-arg=-Tlink.x", # CHANGED

最終的にBulePill版Lチカサンプルがビルドできた

$ ls -l target/thumbv7m-none-eabi/release/stm32-blue-pill-rust
-rwxrwxrwx 2 xxx xxx 173704 Apr 30 11:34 target/thumbv7m-none-eabi/release/stm32-blue-pill-rust*

$ file target/thumbv7m-none-eabi/release/stm32-blue-pill-rust
target/thumbv7m-none-eabi/release/stm32-blue-pill-rust: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped

これまでRustの開発環境は以下の3種類作った

  • Windows10でのRust
  • VMware上で走るUbuntuでのRust
  • WSL上で走るUbuntuでのRust(上記Ubuntuからバイナリをコピー)

Windows環境でRust開発環境を作った際も、素のUbuntuで作った際も同じようなエラーに出くわした。結果、Linuxだからといってパッケージの整合性が高いというわけではないと思った。(確かに、パッケージは非OS依存だから、当然といえば当然なのかも)

今後の取り組み・・
WSL環境でRustを構築するとすんなりビルドできるかと思ったが、Windows環境での構築とほとんど同じであった。ゆえにWSL環境ではRust使わず、普通のWindows10環境のRustを使うことにする。
これまで動かすことが最優先で、出くわす問題に対して場当たり的に対策を講じてきた。仕様のこととか、パッケージ?の管理とか、全く理解できていない。理解のためできるだけスクラッチで動かす。Interface誌でスタートアップ、リンカスクリプトもスクラッチで書く方法が解説されているので、それを打ち込みながら、自力でStartUp->ハード初期化->LEDチカのプログラムを組む予定。

memo
linker.ld抜粋

MEMORY
{
  FLASH : ORIGIN = 0x08000000, LENGTH = 64K
  RAM   : ORIGIN = 0x20000000, LENGTH = 20K
}

アセンブルした結果

cargo objdump --bin bluepill_blink --target thumbv7m-none-eabi --  -d  --no-show-raw-insn -print-imm-hex
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s

bluepill_blink: file format ELF32-arm-little


Disassembly of section .text:

08000008 reset:
 8000008:       sub     sp, #0xc
 800000a:       mov.w   r0, #0x518
 800000e:       str     r0, [sp, #0x8]
 8000010:       movs    r1, #0x8
 8000012:       str     r1, [sp]
 8000014:       movs    r1, #0x0
 8000016:       strb.w  r1, [sp, #0x4]
 800001a:       ldr     r1, [sp]
 800001c:       str     r1, [r0]
 800001e:       b       #-0x2 <reset+0x18>
 8000020:       b       #-0x4 <reset+0x18>

ビルドしたバイナリを逆アセンブル

$ /usr/local/GNUToolsARMEmbedded/4.8_2013q4/bin/arm-none-eabi-objdump.exe -d  bluepill_blink

bluepill_blink:     file format elf32-littlearm
Disassembly of section .text:

08000008 <reset>:
 8000008:       f44f 60a3       mov.w   r0, #1304       ; 0x518
 800000c:       2108            movs    r1, #8
 800000e:       6001            str     r1, [r0, #0]
 8000010:       e7fe            b.n     8000010 <reset+0x8>

$ /usr/local/GNUToolsARMEmbedded/4.8_2013q4/bin/arm-none-eabi-objcopy.exe -O binary bluepill_blink  bluepill_blink.bin

$ od -t x1 bluepill_blink.bin
0000000 00 50 00 20 09 00 00 08 4f f4 a3 60 08 21 01 60
0000020 fe e7

 stack:2000 5000 
Vector:0800 0009 
.text
   f44f  60a3  
   2108 
   6001 
   e7fe 

リセットベクターが08000008ではなくて、08000009と奇数になっているのだが、、これはこれでいいのか!?
OpenOCD + gdbデバッグしてみる

 (cd /usr/local/openocd-0.10.0/; ./bin-x64/openocd  -f ./scripts/interface/stlink-v2.cfg -f ./scripts/target/stm32f1x.cfg)

/usr/local/GNUToolsARMEmbedded/4.8_2013q4/bin/arm-none-eabi-gdb.exe  target/thumbv7m-none-eabi/debug/bluepill_blink
(gdb) target extended-remote:3333
(gdb) mon reset halt
(gdb) b reset
(gdb) load
(gdb) run

BluePill用のLチカプログラム(gdbで動かす分にはOKだが)

#![no_std]
#![no_main]

const GPIOC : usize = 0x40011000;
const GPIO_BSRR_OFFSET : usize = 0x10;
const GPIO_BRR_OFFSET : usize = 0x14;

const GPIOC_8: u32 = 8;
const GPIOC_13: u32 = 13;

const RCC_BASE : usize =  0x40021000;
const RCC_OFFSET: usize = 0x18;

const OUT10MH: u32 = 0x01 ;

const CNF13_GENPP: u32 = 0x00000000;
const MODE13_OUT10MH :u32 = OUT10MH << ((GPIOC_13 - GPIOC_8) *4);

#[link_section = ".vector_table.reset_vector"]
#[no_mangle]

pub static RESET_VECTOR: extern "C" fn() ->! = reset;

#[no_mangle]
pub extern "C" fn reset() -> ! {

    // Enable Clock
    let mut reg_ptr = (RCC_BASE + RCC_OFFSET) as *mut u32;
    unsafe { 
       *reg_ptr = 0x01 << 4  
    }

    // set GPIOC_13 as OUTPUT
    reg_ptr = (GPIOC + 0x04) as *mut u32;
    unsafe {
        *reg_ptr  = CNF13_GENPP | MODE13_OUT10MH;  
    }

    loop {
        reg_ptr = (GPIOC + GPIO_BRR_OFFSET) as *mut u32;
        unsafe {
            *reg_ptr = 1 << GPIOC_13;
        }
        wait();
        reg_ptr = (GPIOC + GPIO_BSRR_OFFSET) as *mut u32;
        unsafe {
             *reg_ptr = 1 << GPIOC_13;
        }
        wait();
    }
}

fn wait(){
    let mut counter = 0;
    let mut i;
    while counter < 100 {
         counter += 1;
         i = 0;
         while i < 1000 {
              i += 1;
         }
    }
}

use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

linker.ldの内容(Interfaceより引用)

MEMORY
{
  FLASH : ORIGIN = 0x08000000, LENGTH = 64K
  RAM   : ORIGIN = 0x20000000, LENGTH = 20K
}

ENTRY(reset);
EXTERN(RESET_VECTOR);

SECTIONS
{
 .vector_table ORIGIN(FLASH) :
 {
     LONG(ORIGIN(RAM) + LENGTH(RAM));
     KEEP(*(.vector_table.reset_vector));
 } > FLASH

 .text :
 {
    *(.text .text.*);
 }  > FLASH

 .rodata :
 {
    *(.rodata .rodata.*);
    *(.data.rel.ro);
 } > FLASH

  /DISCARD/ :
 {
    *(.ARM.exidx .ARM.exidx.*);
 }

}

release版をBulePillのFlashに焼いてみた

/usr/local/GNUToolsARMEmbedded/4.8_2013q4/bin/arm-none-eabi-objcopy.exe -O binary bluepill_blink  bluepill_blink.bin

cd ./target/thumbv7m-none-eabi/release

$ od -t x1 bluepill_blink.bin
0000000 00 50 00 20 09 00 00 08 41 f2 18 00 10 21 c4 f2
0000020 02 00 01 60 41 f2 04 00 c4 f2 01 00 4f f4 80 11
0000040 01 60 4f f4 00 51 c0 e9 03 11 fc e7


$ pwd
~/tech/arm/stm32/stlink

$ ./st-flash.exe write ~/lang/rust/bluepill_blink/target/thumbv7m-none-eabi/release/bluepill_blink.bin 0x08000000
st-flash 1.3.1
2020-04-30T19:28:39 INFO src/common.c: Loading device parameters....
2020-04-30T19:28:39 INFO src/common.c: Device connected is: F1 Medium-density device, id 0x20036410
2020-04-30T19:28:39 INFO src/common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes
2020-04-30T19:28:39 INFO src/common.c: Attempting to write 44 (0x2c) bytes to stm32 address: 134217728 (0x8000000)
Flash page at addr: 0x08000000 erased
2020-04-30T19:28:39 INFO src/common.c: Finished erasing 1 pages of 1024 (0x400) bytes
2020-04-30T19:28:39 INFO src/common.c: Starting Flash write for VL/F0/F3 core id
2020-04-30T19:28:39 INFO src/flash_loader.c: Successfully loaded flash loader in sram
  0/0 pages written
2020-04-30T19:28:39 INFO src/common.c: Starting verification of write complete
2020-04-30T19:28:39 INFO src/common.c: Flash written and verified! jolly good!

LEDが点灯はするが点滅はしない。。なぜか? 待ちループが最適化により削除された??
debug版を入れると点滅した。最適化の影響か、それとも、作り間違っているか。。
Release版のバイナリを逆アセンブルすると以下となっており、ウエイトの2重ループが無いような。。

$ /usr/local/GNUToolsARMEmbedded/4.8_2013q4/bin/arm-none-eabi-objdump.exe -d  bluepill_blink

bluepill_blink:     file format elf32-littlearm
Disassembly of section .text:
08000008 <reset>:
 8000008:       f241 0018       movw    r0, #4120        ; 0x1018
 800000c:       2110               movs     r1, #16
 800000e:       f2c4 0002       movt     r0, #16386       ; 0x4002
 8000012:       6001               str         r1, [r0, #0]
 8000014:       f241 0004       movw   r0, #4100          ; 0x1004
 8000018:       f2c4 0001       movt     r0, #16385        ; 0x4001
 800001c:       f44f 1180        mov.w   r1, #1048576    ; 0x100000
 8000020:       6001               str         r1, [r0, #0]
 8000022:       f44f 5100       mov.w   r1, #8192          ; 0x2000
 8000026:       e9c0 1103      strd       r1, r1, [r0, #12]
 800002a:       e7fc                b.n        8000026 <reset+0x1e>

■ご参考URL
RustでBluepillのLEDを点滅記事
Rust on STM32: Blinking an LED - Stackenbloggen
Home | Rustの日本語ドキュメント/Japanese Docs for Rust
まえがき - The Rust Programming Language
導入 - The Embedded Rust Book
ARM Cortex-M 32ビットマイコンでベアメタル "Safe" Rust - Qiita
rust で組み込み(Cortex-M3) – GitHub 出張所 – プログラム関係のブログはここに
ようこそ Japaric Park へ – GitHub 出張所 – プログラム関係のブログはここに