絶対座標で計算するから大変なんであって、XYZ軸の傾きを検知して、相対的にモータの回転数を±で補正する程度のアルゴリズムで、まずはドローンを飛ばしてみようと思う(変な方に飛んでいくかもしれないが)。ただ、このままMicroPython で試作を続けるとあまりに楽でRustに移行しなさそうなので、、ドローンが離陸*1するコードは絶対にRustで書こうと決めた。というわけで、、STM32に対応したRustをUbuntuに導入する。先人のブログを参考に手順は以下
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source $HOME/.cargo/env rustup target add thumbv7em-none-eabihf cargo install cargo-binutils rustup component add llvm-tools-preview cargo install cargo-generate
$ rustc --print target-list *略* thumbv6m-none-eabi thumbv7a-pc-windows-msvc thumbv7a-uwp-windows-msvc thumbv7em-none-eabi thumbv7em-none-eabihf thumbv7m-none-eabi thumbv7neon-linux-androideabi thumbv7neon-unknown-linux-gnueabihf thumbv7neon-unknown-linux-musleabihf
STM32用にビルドするには、マイコンのメモリマップに合ったリンカ設定やらスタートアップやらもろもろが必要になるのだが、そこを0から準備しているとどれほど時間がかかるか分からないので(問題に出くわして自力で解決できるかどうかも不明)、セットアップも先人に頼ることにした。
https://github.com/stm32-rs/stm32-rs
git clone git@github.com:stm32-rs/stm32f1xx-hal.git
example配下のblinky.rsに対してLEDのピンを修正してビルド
buildすると、thumbv7em-none-eabiが足りないと言われるので以下を再実行
rustup target add thumbv7em-none-eabi
cargo build --example blinky --release --features=stm32l4x6
/stm32l4xx-hal/target/thumbv7em-none-eabi/release/examples配下にblinkyが作られる。これを何も考えずに、Drag&DropでNUCLEOのボードに書き込み・・・動かない(動いているけどLEDが点滅しないのかも)
OpenOCDを使わないとだめなんだろうか。。
記事を参考にOpenOCD+gdbで試す。
OpenOCDでNucleoボードに接続
./bin-x64/openocd.exe -f ./scripts/interface/stlink-v2-1.cfg -f ./scripts/target/stm32l4x.cfg
gdbを起動
$ /usr/local/GNUToolsARMEmbedded/4.8_2013q4/bin/arm-none-eabi-gdb.exe target/thumbv7em-none-eabi/release/examples/blinky Reading symbols from C:\cygwin64\home\sumi\lang\rust\stm32\stm32l4xx-hal\target\thumbv7em-none-eabi\release\examples\blinky...done. (gdb) target remote localhost:3333 Remote debugging using localhost:3333 Reset () at /home/sumi/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.15/src/lib.rs:497 497 /home/sumi/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.15/src/lib.rs: No such file or directory. (gdb) monitor reset halt Unable to match requested speed 500 kHz, using 480 kHz Unable to match requested speed 500 kHz, using 480 kHz adapter speed: 480 kHz target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x08000400 msp: 0x20010000 (gdb) load Loading section .vector_table, size 0x400 lma 0x8000000 Loading section .text, size 0x2640 lma 0x8000400 Loading section .rodata, size 0xea0 lma 0x8002a40 Start address 0x8000400, load size 14560 Transfer rate: 12 KB/sec, 4853 bytes/write. (gdb) l 492 in /home/sumi/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.15/src/lib.rs (gdb) l main 20 use crate::rt::ExceptionFrame; 21 22 use crate::sh::hio; 23 use core::fmt::Write; 24 25 #[entry] 26 fn main() -> ! { 27 let mut hstdout = hio::hstdout().unwrap(); 28 29 writeln!(hstdout, "Hello, world!").unwrap(); (gdb) l 30 31 let cp = cortex_m::Peripherals::take().unwrap(); 32 let dp = hal::stm32::Peripherals::take().unwrap(); 33 34 let mut flash = dp.FLASH.constrain(); // .constrain(); 35 let mut rcc = dp.RCC.constrain(); 36 let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1); 37 38 // Try a different clock configuration 39 let clocks = rcc.cfgr.hclk(8.mhz()).freeze(&mut flash.acr, &mut pwr) ; (gdb) hbreak main Hardware assisted breakpoint 1 at 0x80005d0: file examples/blinky.rs, line 25. (gdb) i r r0 0x0 0 r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0x0 0 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 sp 0x20010000 0x20010000 lr 0xffffffff -1 pc 0x8000400 0x8000400 <Reset> xPSR 0x1000000 16777216 (gdb) cont Continuing. Breakpoint 1, main () at examples/blinky.rs:25 25 #[entry] (gdb) l 20 use crate::rt::ExceptionFrame; 21 22 use crate::sh::hio; 23 use core::fmt::Write; 24 25 #[entry] 26 fn main() -> ! { 27 let mut hstdout = hio::hstdout().unwrap(); 28 29 writeln!(hstdout, "Hello, world!").unwrap(); (gdb) n Note: automatically using hardware breakpoints for read-only addresses. Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002902 in __c_m_sh_syscall () at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/option.rs:388 388 /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/option.rs: No such file or directory. (gdb)
mainの次でハングしているのだろうか。スタックがおかしいのか?
スタックがおかしいのではないようだ。。なぜこんなところで止まるのか分からないが。
(gdb) where #0 0x08002902 in __c_m_sh_syscall () at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/option.rs:388 #1 0x080027e8 in syscall1 (_nr=5, _arg=536936268) at /home/sumi/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-semihosting-0.3.7/src/lib.rs:215 #2 syscall<[usize; 3]> (nr=5, arg=0x2000ff4c) at /home/sumi/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-semihosting-0.3.7/src/lib.rs:207 #3 write_all (fd=1, buffer=...) at /home/sumi/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-semihosting-0.3.7/src/hio.rs:69 #4 write_all (self=<optimized out>, buffer=...) at /home/sumi/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-semihosting-0.3.7/src/hio.rs:34 #5 write_str (self=<optimized out>, s=...) at /home/sumi/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-semihosting-0.3.7/src/hio.rs:40 #6 _$LT$$RF$mut$u20$W$u20$as$u20$core..fmt..Write$GT$::write_str::hb6fe49e168115967 (self=<optimized out>, s=...) at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/fmt/mod.rs:191 #7 0x08001e9e in core::fmt::write::hf86e9be5054282ca () at library/core/src/fmt/mod.rs:1131 #8 0x08000632 in blinky::__cortex_m_rt_main::h1a11350d26d59f31 () at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/fmt/mod.rs:184 #9 0x080005d4 in main () at examples/blinky.rs:25
mainのソースとしては以下の行
let mut hstdout = hio::hstdout().unwrap();
セミホスティングを使うための初期設定と思われるが、Lチカだけやりたいので、セミホスティング要らないので、ややこしい行はコメントにしてみる。
// let mut hstdout = hio::hstdout().unwrap(); // writeln!(hstdout, "Hello, world!").unwrap();
gdbを起動、mainでハードウエアブレーク設定して、contで実行
umbv7em-none-eabi/release/examples/blinkyq4/bin/arm-none-eabi-gdb.exe target/th Reading symbols from #######\lang\rust\stm32\stm32l4xx-hal\target\thumbv7em-none-eabi\release\examples\blinky...done. (gdb) target remote localhost:3333 Remote debugging using localhost:3333 0x08002902 in ?? () (gdb) monitor reset halt Unable to match requested speed 500 kHz, using 480 kHz Unable to match requested speed 500 kHz, using 480 kHz adapter speed: 480 kHz target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x08000400 msp: 0x20010000 (gdb) load Loading section .vector_table, size 0x400 lma 0x8000000 Loading section .text, size 0x2500 lma 0x8000400 Loading section .rodata, size 0xde8 lma 0x8002900 Start address 0x8000400, load size 14056 Transfer rate: 11 KB/sec, 4685 bytes/write. (gdb) hbreak main Hardware assisted breakpoint 1 at 0x800058e: file examples/blinky.rs, line 25. (gdb) cont Continuing. Breakpoint 1, main () at examples/blinky.rs:25 25 #[entry] (gdb) n Note: automatically using hardware breakpoints for read-only addresses. Program received signal SIGINT, Interrupt. blinky::__cortex_m_rt_main::h1a11350d26d59f31 () at src/delay.rs:72 72 while !self.syst.has_wrapped() {} (gdb)
LED2が点滅した。。 ゆえに、、セミホスティングは何か手当が必要、タイマとかGPIOは使える。
バイナリは動くバージョンになったということで、、Drag&Dropでファームに焼けるのかやってみた。
正常ファームの状態に正しいファームを上書きインストールしたことになり、正しく書けたかどうか、判断が難しいが、単純にDrag&DropでもLEDは点滅している。多分、デバッガなくてもこの方法で書き込めるのだろう。とはいえ、組み込みプログラムの開発においてシリアル等の通信手段がない場合、デバッガがないと非常に困るので、結局はOpenOCD+GDDBは必須だと思いますが。。
■追記
gdbでセミホスティングを有効にするコマンドがあって、これを打ち込んでいなかったのを思い出した。
monitor arm semihosting enable
上記を打ち込むとどういう挙動になるのか再度試す。
OpenOCD側のコンソールに以下が表示、LEDが点滅されるのを確認した。よって、gdb側からセミホスティングを有効にする操作をしていなかったのが原因。
semihosting is enabled Hello, world!
以上により、基本的なテストは行えたので、、今後はRust+STM32用ドライバを使って、USBシリアルと、GPIO/SPIがプログラムで制御できるようにして、センサデータをシリアルダンプしたり、簡単なモニタプログラムを作ってPC側からセンサデータを取得、モータ制御用テーブルを書き換えたり、そんなことができるように、Rustでドローン制御プログラムを組む予定。
■Rustのコードサイズ
$ size blinky text data bss dec hex filename 14560 0 4 14564 38e4 blinky
RustによるLチカのコードサイズは、バイナリ領域で14KB程度。STEVAL-DRONE01に乗っているSTM32F103CはFlash 256Kなので、十分に余裕がある。かなりややこしいコードを書いても大丈夫。。
■振り返り
RustでLチカサンプルをビルドして走らせた。先人の説明記事が明確だったのと、インストールツール類が枯れるレベルに仕上がっているので、Rust環境を作るのはほとんどトラブルなくできた。一方、サンプルソースを見てもC言語等とはかなり違っていて、ぱっと見た限り、コードの表記の意味が全然分からない。ライブラリとか自分で自由にプログラミングできるレベルまでは時間かけて勉強しないといけないと感じた。
■参考URL
Rustで組み込みプログラミングの第一歩、LチカとHello Worldを試してみた | DevelopersIO
https://nkon.github.io/Rust-embedded/
*1:1mmでも浮くような