Rustの組み込み系のハンズオンのDiscoveryをやってみます
ひとまず、環境構築からLEDが光るくらいまでを目標にします
では、ドキュメントを読んでいきます
以下は、後で自分自身が振り返るときに便利なことを書いたメモです
不足や誤りなどありましたら、ご容赦ください
どの開発ボードを使うか
Read the newer book, using a micro:bit
と、あり、micro:bitが入手しやすかったため、micro:bitを使うことにしました
今回は以下から、『micro:bit(マイクロビット) v2.2』を購入しました
micro:bit用のドキュメントはこちらがスタートです
このハンズオンで勉強すること
このドキュメントを勉強することで、
まずは基本的な要素である、ボード向けのソースコードの書き方、ビルドの仕方、ボードへの書き込み方、デバッグの仕方がわかるようです
また、ボードの各機能であるデジタル入出力、PWM、ADC、Serial通信、I2C通信、SPI通信についてや、マルチタスクのコンセプトとかを学べるとかなんとか
準備するもの
開発ボードのmicro:bit v2.2と、開発ボードと開発環境のパソコンをつなぐUSBケーブルです
mircro:bitはUSBマイクロB端子です
最近は、USBマイクロB端子が淘汰されてきましたが、この手の開発ボードや安価なボードはいまだUSBマイクロB端子ですね
なんでだろう、安いのかな
各種ツール
rustc -V
でツールチェインのバージョンを確認しておきます
rustc 1.79.0 (129f3b996 2024-06-10)
とのことなので、ドキュメントの1.57.0
に比べると多少新しいため、もしかしたら、そのままいかないところもあるかもしれませんが、まあ気にせず進めます
そのほか、ドキュメントにあるとおり、あれこれインストールしました
実行したコマンドは以下のような感じです
$ rustup component add llvm-tools
$ cargo install cargo-binutils --vers 0.3.3
$ cargo size --version
そして、以下にしたがって、probe-rsもインストールします
それから、下記のコマンドです
$ cargo install probe-rs-tools --vers 0.24.0
$ cargo embed --version
また、ハンズオン用のソースコードがあるとのことなので、GitHubからコピーしてきました
基本的に、microbit
ディレクトリのソースコードを使うっぽいですね
開発環境がWindowsなので、以下も実行します
自分の環境にあったarm-none-eabi-gccをインストールします
これをインストールした後は、IDEを再起動しないとarm-none-eabi-gcc
コマンドが認識されませんでした
PuTTYも必要らしいので、インストールします
micro:bitに電源をつないでみる
パソコンとmicro:bitをつないでみました
なんか音が鳴って驚きました
後、めちゃくちゃ光ります
製造時に書かれていたプログラムがパリピだったようです
では、認識されているか確認するためにprobe-rs list
を実行します
$ probe-rs list
The following debug probes were found:
[0]: BBC micro:bit CMSIS-DAP -- 0d28:0204:9906360200052820AFF95D856A2782CB000000006E052820 (CMSIS-DAP)
[1]: CMSIS-DAP v1 -- 0d28:0204:9906360200052820aff95d856a2782cb000000006e052820 (CMSIS-DAP)
なぜか、2つ認識されていますが、いったん見なかったことにします
続いて、ソースコードをビルドしてみます
$ cargo embed --target thumbv7em-none-eabihf
を実行したところ、
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.07s
Config default
Target E:\github\rust_embedded\microbit\target\thumbv7em-none-eabihf\debug\rtt-check
Error The following devices were found:
[0]: BBC micro:bit CMSIS-DAP -- 0d28:0204:9906360200052820AFF95D856A2782CB000000006E052820 (CMSIS-DAP)
[1]: CMSIS-DAP v1 -- 0d28:0204:9906360200052820aff95d856a2782cb000000006e052820 (CMSIS-DAP)
Use '--probe VID:PID'
You can also set the [default.probe] config attribute (in your Embed.toml) to select which probe to use. For usage examples see https://github.com/probe-rs/probe-rs/blob/master/probe-rs-tools/src/bin/probe-rs/cmd/cargo_embed/config/default.toml .
と、怒られました
2つ認識されているため、どちらを使えばいいかわからないらしいですね
Use '--probe VID:PID'
と教えてくれているため、そうします
$ cargo embed --target thumbv7em-none-eabihf --probe
0d28:0204:9906360200052820AFF95D856A2782CB000000006E052820
どこかVID:PID
なのかがわからないため、ひとまずそれっぽいものをまるごとコピペして、実行です
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.06s
Config default
Terminal
Hello World
おなじみのHello Worldが出たので、よさそうです
開発ボードのMCUについて
micro:bit v2ではNordic nRF52833
を使うよと解説してくれています
ここで、今回のチップの基礎的な知識だけでなく、ARMとはなんぞや?みたいな話もしてくれているのは、さすが親切なドキュメントです
用語
以下のような用語が説明されています
- Peripheral Access Crate (PAC)
- The Hardware Abstraction Layer (HAL)
- The Board Support Crate (historically called Board Support Package, or BSP)
HALとBSPは知っていましたが、PACは始めて聞きました
LED Roulette
続いて、ビルド、フラッシュ、デバッグのやり方を実践です
前回と同じく、Embed.toml
のチップのアンコメントします
[default.general]
chip = "nrf52833_xxAA" # uncomment this line for micro:bit V2
# chip = "nrf51822_xxAA" # uncomment this line for micro:bit V1
[default.reset]
halt_afterwards = true
[default.rtt]
enabled = false
[default.gdb]
enabled = true
クロスコンパイルのターゲット用のライブラリをインストールしておきます
これは一度実行すればOK
# For micro:bit v2
$ rustup target add thumbv7em-none-eabihf
二度目以降は、アップデートの確認が走りました
(up to date
は最新という意味だと知った)
ビルドします
# make sure you are in the `src/05-led-roulette` directory
# For micro:bit v2
$ cargo build --features v2 --target thumbv7em-none-eabihf
書きこみます
# For micro:bit v2
$ cargo embed --features v2 --target thumbv7em-none-eabihf
エラーになりました
> cargo embed --features v2 --target thumbv7em-none-eabihf
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.10s
Config default
Target E:\github\discovery-master\microbit\target\thumbv7em-none-eabihf\debug\led-roulette
Error The following devices were found:
[0]: BBC micro:bit CMSIS-DAP -- 0d28:0204:9906360200052820AFF95D856A2782CB000000006E052820 (CMSIS-DAP)
[1]: CMSIS-DAP v1 -- 0d28:0204:9906360200052820aff95d856a2782cb000000006e052820 (CMSIS-DAP)
Use '--probe VID:PID'
You can also set the [default.probe] config attribute (in your Embed.toml) to select which probe to use. For usage examples see https://github.com/probe-rs/probe-rs/blob/master/probe-rs-tools/src/bin/probe-rs/cmd/cargo_embed/config/default.toml .
デバイスがふたつ認識されているから、困っていますね
--probe VID:PID
オプションをコマンドにつけるか、Embed.toml
に書いてくださいとありますが、今後も--probe
をつけるのがめんどうなので、Embed.toml
に書くことにします
Embed.toml
に書くのは以下の通りです
VID、PIDはフラッシュ時のエラー文章を参照しました
[default.probe]
usb_vid = "0d28"
usb_pid = "0204"
そして、実行すると、今度はこうなりました
> cargo embed --features v2 --target thumbv7em-none-eabihf
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.09s
Config default
Target E:\github\discovery-master\microbit\target\thumbv7em-none-eabihf\debug\led-roulette
Erasing ✔ [00:00:00] [####################################] 16.00 KiB/16.00 KiB @ 33.13 KiB/s (eta 0s )
Programming ✔ [00:00:00] [####################################] 16.00 KiB/16.00 KiB @ 17.30 KiB/s (eta 0s )
Finished in 1.444s
WARN probe_rs::util::rtt: No RTT header info was present in the ELF file. Does your firmware run RTT?
GDB stub listening at 127.0.0.1:1337
During the execution of GDB an error was encountered:
通常、各ソケット アドレスに対してプロトコル、ネットワーク アドレス、またはポートのどれか 1 つのみを使用できます。 (os error 10048)
Caused by:
通常、各ソケット アドレスに対してプロトコル、ネットワーク アドレス、またはポートのどれか 1 つのみを使用できます。 (os error 10048)
Done processing config default
127.0.0.1:1337
が既に使用済みか何かのようです
コマンドプロンプトで``netstat -a`を実行しみてみると、確かに使われていました
TCP 127.0.0.1:1337 myPC:0 LISTENING
こちらを参考にして、何が使っているか確かめてみました
$netstat -ano | find "1337"
TCP 127.0.0.1:1337 0.0.0.0:0 LISTENING 6808
PID6808が使っているらしいです
このままコマンドプロンプトを使っても調べられそうですが、めんどうくさいのでタスクマネージャーを開き、「詳細」タブから6808
を探します
Razer Chromaが使っているらしいです
Razerには心当たりがあるため、このプロセスをkillするのはやめて、ポート番号を変える方向にします
Embed.toml
のdefault.toml
にhost:portの設定がありました
[default.gdb]
# Whether or not a GDB server should be opened after flashing.
enabled = false
# The connection string in host:port format wher the GDB server will open a socket.
gdb_connection_string = "127.0.0.1:1337"
と、ありましたので、以下のようにしたいと思います
ポート番号は適当です
[default.gdb]
enabled = true
gdb_connection_string = "127.0.0.1:1338"
これでもう一度フラッシュコマンドを実行します
$ cargo embed --features v2 --target thumbv7em-none-eabihf
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.08s
Config default
Target E:\github\discovery-master\microbit\target\thumbv7em-none-eabihf\debug\led-roulette
Erasing ✔ [00:00:00] [####################################] 16.00 KiB/16.00 KiB @ 34.23 KiB/s (eta 0s )
Programming ✔ [00:00:00] [####################################] 16.00 KiB/16.00 KiB @ 19.40 KiB/s (eta 0s )
Finished in 1.332s
WARN probe_rs::util::rtt: No RTT header info was present in the ELF file. Does your firmware run RTT?
GDB stub listening at 127.0.0.1:1338
よさそうです
Debug
上記のフラッシュコマンドを実行した状態で、別ターミナルを開き、arm-none-eabi-gdb
をインストールしたので、以下のコマンドを実行します
# For micro:bit v2
$ arm-none-eabi-gdb target/thumbv7em-none-eabihf/debug/led-roulette
以下が出力されました
GNU gdb (Arm GNU Toolchain 13.3.Rel1 (Build arm-13.24)) 14.2.90.20240526-git
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=i686-w64-mingw32 --target=arm-none-eabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
--Type <RET> for more, q to quit, c to continue without paging--c
<https://bugs.linaro.org/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
target/thumbv7em-none-eabihf/debug/led-roulette: No such file or directory.
(gdb)
no such file or directoryと言われているため、以下のコマンドを実行し直します
(GDBを抜けるときは、quit
を入力します)
arm-none-eabi-gdb ../../target/thumbv7em-none-eabihf/debug/led-roulette
warningが出ていますが、それを無視すると、よさそうです
作業を進めます
> arm-none-eabi-gdb ../../target/thumbv7em-none-eabihf/debug/led-roulette
GNU gdb (Arm GNU Toolchain 13.3.Rel1 (Build arm-13.24)) 14.2.90.20240526-git
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=i686-w64-mingw32 --target=arm-none-eabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
--Type <RET> for more, q to quit, c to continue without paging--
<https://bugs.linaro.org/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ../../target/thumbv7em-none-eabihf/debug/led-roulette...
warning: could not convert 'main' from the host encoding (CP1252) to UTF-32.
This normally should not happen, please file a bug report.
(gdb)
ポート番号を変えたので、接続先のポート番号を変えて、コマンドを入力します
(gdb) target remote :1338
Remote debugging using :1338
0x00000100 in cortex_m::delay::Delay::delay_us (self=0x9e8280c9, us=4291676149)
at src/delay.rs:57
57 self.syst.clear_current();
(gdb)
続いて、break main
です
(gdb) break main
Breakpoint 1 at 0x15c: file src\05-led-roulette\src/main.rs, line 9.
Note: automatically using hardware breakpoints for read-only addresses.
そして、continue
をすると、
(gdb) c
Continuing.
Program received signal SIGINT, Interrupt.
led_roulette::__cortex_m_rt_main () at src\05-led-roulette\src/main.rs:11
11 fn main() -> ! {
よさそうですね
breakpointの一覧はinfo break
で表示され、delete <breakpoint-num>
で削除できます
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000015c in led_roulette::__cortex_m_rt_main_trampoline at src\05-led-roulette\src/main.rs:9
breakpoint already hit 1 time
(gdb) delete 1
(gdb) info break
No breakpoints or watchpoints.
次はlayout src
が出てきますが、Windows環境にはないため、飛ばします
break <ブレイクポイントを置きたい行数>
でブレイクポイントを貼ります
指示にあるとおり、main.rsの13行目にブレイクポイントを貼ろうとしましたが、どうもずれてしまいます
未使用変数だから、最適化されているのか?
disassemble /m
で確認してみると、下記のようになっていました
_y = x;
に対応するアセンブリが存在していないようです
最適化か……?
(gdb) disassemble /m
Dump of assembler code for function _ZN12led_roulette18__cortex_m_rt_main17h515d3c049099b5e4E:
10 fn main() -> ! {
=> 0x00000160 <+0>: sub sp, #8
0x00000162 <+2>: movs r0, #42 @ 0x2a
11 let _y;
12 let x = 42;
0x00000164 <+4>: str r0, [sp, #0]
0x00000166 <+6>: str r0, [sp, #4]
--Type <RET> for more, q to quit, c to continue without paging--
13 _y = x;
14
15 // infinite loop; just so we don't leave this stack frame
16 loop {}
0x00000168 <+8>: b.n 0x16a <_ZN12led_roulette18__cortex_m_rt_main17h515d3c049099b5e4E+10>
0x0000016a <+10>: b.n 0x16a <_ZN12led_roulette18__cortex_m_rt_main17h515d3c049099b5e4E+10>
--Type <RET> for more, q to quit, c to continue without paging--
でもビルドする際に、unoptimized
と出ています……?
で、よく見てみると、
11 let _y;
12 let x = 42;
0x00000164 <+4>: str r0, [sp, #0]
0x00000166 <+6>: str r0, [sp, #4]
とあって、どうもx
と_y
両方に値がストアされていそうですね
だから、13行目の_y = x;
に対応する直接的な処理がないみたい?
ということみたいなので、まあよしとしましょう
後は、stepi
やmonitor reset
などがありました
Light it up
では、実際にLEDを光らせてみます
main.rs
を書き換えて、実行したところ、LEDがひとつ光りました
まとめ
ということで、Rust DiscoveryのLEDがひとつ光るまでをやりました
環境構築はめんどうくさいし、つまずくと厄介な作業栄えある第一位だと思いますが、なんとかなってよかったです
もし似たようなところで、つまずいた方がいたら、ご参考になれば幸いです
この後の部分もちょいちょいとやっていきたいと思います
記事にしたほうがよさそうだったら、そうします
以上、ご清聴ありがとうございました