書き込んでみよう
フラッシュとは、プログラムをマイクロコントローラーの(永続的な)メモリに書き込む処理のことです。いったんフラッシュされると、マイクロコントローラーは電源が入るたびに、その書き込まれたプログラムを実行します。
この場合、led-roulette プログラムがマイクロコントローラーのメモリ内で 唯一の プログラムになります。
つまり、マイクロコントローラー上ではほかに何も動いていません。OS も「daemon」も何もありません。led-roulette がデバイスを完全に制御します。
では、実際にフラッシュしていきましょう。最初に行う必要があるのは OpenOCD の起動です。これは前のセクションでも行いましたが、今回は一時ディレクトリ(*nix では /tmp、Windows では %TEMP%)の中でコマンドを実行します。
F3 がコンピューターに接続されていることを確認し、新しいターミナルで次のコマンドを実行してください。
*nix & MacOS の場合:
cd /tmp
openocd -f interface/stlink-v2-1.cfg -f target/stm32f3x.cfg
Windows の場合 注: 実際の OpenOCD のパスに合わせて C: を置き換えてください:
cd %TEMP%
openocd -s C:\share\scripts -f interface/stlink-v2-1.cfg -f target/stm32f3x.cfg
NOTE ボードの古いリビジョンでは、
openocdに少し異なる引数を渡す必要があります。詳細は this section を確認してください。
このプログラムはそこで待機状態になるので、そのターミナルは開いたままにしておいてください。
ここで、openocd コマンドが実際には何をしているのかを説明するのにちょうどよいタイミングです。
前にも触れたように、STM32F3DISCOVERY(別名 F3)には実際には 2 つのマイクロコントローラーがあります。そのうちの 1 つはプログラマ/デバッガとして使われます。プログラマとして使われるボード上の部分は ST-LINK と呼ばれます(STMicroelectronics がそう名付けました)。この ST-LINK は、Serial Wire Debug(SWD)インターフェースを使ってターゲットのマイクロコントローラーに接続されています(このインターフェースは ARM の標準なので、ほかの Cortex-M ベースのマイクロコントローラーを扱うときにも目にすることになります)。この SWD インターフェースは、マイクロコントローラーのフラッシュやデバッグに利用できます。ST-LINK は「USB ST-LINK」ポートに接続されており、F3 をコンピューターに接続すると USB デバイスとして認識されます。
OpenOCD はというと、SWD や JTAG のようなデバッグプロトコルを公開する USB デバイスの上で、GDB サーバー などのサービスを提供するソフトウェアです。
では、実際のコマンドを見てみましょう。使用しているこれらの .cfg ファイルは、ST-LINK の USB デバイス(interface/stlink-v2-1.cfg)を探し、その ST-LINK に STM32F3XX マイクロコントローラー(target/stm32f3x.cfg)が接続されていることを想定するよう OpenOCD に指示しています。
OpenOCD の出力は次のようになります。
$ openocd -f interface/stlink-v2-1.cfg -f target/stm32f3x.cfg
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
none separate
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v37 API v2 SWIM v26 VID 0x0483 PID 0x374B
Info : using stlink api v2
Info : Target voltage: 2.888183
Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
「6 breakpoints, 4 watchpoints」という部分は、そのプロセッサーが利用可能なデバッグ機能を示しています。
その openocd プロセスは動かしたままにし、先ほどのターミナル、または新しいターミナルで、
プロジェクトの src/05-led-roulette/ ディレクトリの中にいることを確認してください。
OpenOCD は GDB サーバーを提供すると説明しましたので、さっそくそこに接続してみましょう。
GDB を実行する
まず、ARM バイナリをデバッグできる gdb のどのバージョンが手元にあるかを確認する必要があります。
以下のいずれかのコマンドが使えるはずなので、順に試してみてください。
arm-none-eabi-gdb -q -ex "target remote :3333" target/thumbv7em-none-eabihf/debug/led-roulette
gdb-multiarch -q -ex "target remote :3333" target/thumbv7em-none-eabihf/debug/led-roulette
gdb -q -ex "target remote :3333" target/thumbv7em-none-eabihf/debug/led-roulette
NOTE:
target/thumbv7em-none-eabihf/debug/led-roulette: No such file or directoryというエラーが出る場合は、ファイルパスの先頭に../../を追加してみてください。たとえば次のようになります。$ gdb -q -ex "target remote :3333" ../../target/thumbv7em-none-eabihf/debug/led-rouletteこれは、各サンプルプロジェクトが本全体を含む
workspace内にあり、workspace ではtargetディレクトリが 1 つだけだからです。詳しくは [Workspaces chapter in Rust Book] を参照してください。
失敗するケース
Remote debugging using :3333 の行のあとに warning または error が表示される場合は、失敗しているケースだと判断できます。
$ gdb -q -ex "target remote :3333" target/thumbv7em-none-eabihf/debug/led-roulette
Reading symbols from target/thumbv7em-none-eabihf/debug/led-roulette...
Remote debugging using :3333
warning: Architecture rejected target-supplied description
Truncated register 16 in remote 'g' packet
(gdb)
成功するケース
成功例 1:
$ arm-none-eabi-gdb -q -ex "target remote :3333" target/thumbv7em-none-eabihf/debug/led-roulette
Reading symbols from target/thumbv7em-none-eabihf/debug/led-roulette...
Remote debugging using :3333
cortex_m_rt::Reset () at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:497
497 pub unsafe extern "C" fn Reset() -> ! {
(gdb)
成功例 2:
~/embedded-discovery/src/05-led-roulette (master)
$ arm-none-eabi-gdb -q -ex "target remote :3333" target/thumbv7em-none-eabihf/debug/led-roulette
Reading symbols from target/thumbv7em-none-eabihf/debug/led-roulette...
Remote debugging using :3333
0x00000000 in ?? ()
(gdb)
失敗するケースでも成功するケースでも、OpenOCD のターミナルに次のような新しい出力が表示されるはずです。
Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
+Info : accepting 'gdb' connection on tcp/3333
+Info : device id = 0x10036422
+Info : flash size = 256kbytes
NOTE
undefined debug reason 7 - target needs resetのようなエラーが出る場合は、こちら にある説明のようにmonitor reset haltを実行してみてください。
デフォルトでは、OpenOCD の GDB サーバーは TCP ポート 3333(localhost)で待ち受けます。このコマンドはそのポートに接続しています。
../.cargo/config.toml を更新する
使用する必要のあるデバッガを無事に特定できたので、次は cargo run コマンドが成功するように ../.cargo/config.toml を変更する必要があります。
NOTE
cargoは Rust のパッケージマネージャーで、こちら で読むことができます。
ターミナルプロンプトに戻って、`../.cargo/config.toml` を確認してください:
``` console
~/embedded-discovery/src/05-led-roulette
$ cat ../.cargo/config.toml
# デフォルトの runner は GDB セッションを開始します。これには OpenOCD が
# 実行されている必要があります。たとえば:
## openocd -f interface/stlink.cfg -f target/stm32f3x.cfg
# ローカルの GDB に応じて、次のいずれかを選んでください
[target.thumbv7em-none-eabihf]
runner = "arm-none-eabi-gdb -q -x ../openocd.gdb"
# runner = "gdb-multiarch -q -x ../openocd.gdb"
# runner = "gdb -q -x ../openocd.gdb"
rustflags = [
"-C", "link-arg=-Tlink.x",
]
[build]
target = "thumbv7em-none-eabihf"
好みのエディターを使って ../.cargo/config.toml を編集し、
runner の行にそのデバッガーの正しい名前が入るようにしてください:
nano ../.cargo/config.toml
たとえば、デバッガーが gdb-multiarch だった場合、編集後の git diff は
次のようになるはずです:
$ git diff ../.cargo/config.toml
diff --git a/f3discovery/src/.cargo/config.toml b/f3discovery/src/.cargo/config.toml
index 2f38f6b..95860a0 100644
--- a/f3discovery/src/.cargo/config.toml
+++ b/f3discovery/src/.cargo/config.toml
@@ -3,8 +3,8 @@
## openocd -f interface/stlink.cfg -f target/stm32f3x.cfg
# ローカルの GDB に応じて、次のいずれかを選んでください
[target.thumbv7em-none-eabihf]
-runner = "arm-none-eabi-gdb -q -x ../openocd.gdb"
-# runner = "gdb-multiarch -q -x ../openocd.gdb"
+# runner = "arm-none-eabi-gdb -q -x ../openocd.gdb"
+runner = "gdb-multiarch -q -x ../openocd.gdb"
# runner = "gdb -q -x ../openocd.gdb"
rustflags = [
"-C", "link-arg=-Tlink.x",
これで ../.cargo/config.toml の設定ができたので、cargo run を使って
デバッグセッションを開始し、動作確認してみましょう。
NOTE
--target thumbv7em-none-eabihfは、どのアーキテクチャ向けに ビルドして実行するかを定義します。../.cargo/config.tomlファイルにはtarget = "thumbv7em-none-eabihf"があるため、実際には--targetを 指定する必要はありません。ここで指定しているのは、コマンドライン上の パラメーターも利用でき、それらがconfig.tomlファイル内の設定を 上書きすることを知ってもらうためです。
cargo run --target thumbv7em-none-eabihf
結果は次のようになります:
~/embedded-discovery/src/05-led-roulette
$ cargo run --target thumbv7em-none-eabihf
Finished dev [unoptimized + debuginfo] target(s) in 0.14s
Running `gdb-multiarch -q -x ../openocd.gdb /home/adam/vc/rust-training/discovery/f3discovery/target/thumbv7em-none-eabihf/debug/led-roulette`
Reading symbols from /home/adam/vc/rust-training/discovery/f3discovery/target/thumbv7em-none-eabihf/debug/led-roulette...
0x08000230 in core::fmt::Arguments::new_v1 (pieces=..., args=...)
at /rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/core/src/fmt/mod.rs:394
394 /rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/core/src/fmt/mod.rs: No such file or directory.
Loading section .vector_table, size 0x194 lma 0x8000000
Loading section .text, size 0x1ad8 lma 0x8000194
Loading section .rodata, size 0x5a4 lma 0x8001c6c
Start address 0x08000194, load size 8720
Transfer rate: 12 KB/sec, 2906 bytes/write.
Breakpoint 1 at 0x80001e8: file src/05-led-roulette/src/main.rs, line 7.
Note: automatically using hardware breakpoints for read-only addresses.
Breakpoint 2 at 0x800020a: file src/lib.rs, line 570.
Breakpoint 3 at 0x8001c5a: file src/lib.rs, line 560.
Breakpoint 1, led_roulette::__cortex_m_rt_main_trampoline () at src/05-led-roulette/src/main.rs:7
7 #[entry]
halted: PC: 0x080001ee
led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:10
10 let x = 42;
すばらしいです。今後も ../.cargo/config.toml を変更していきます。ただし、
このファイルはすべての章で共有されているため、その点を踏まえて変更を
行う必要があります。特定の章だけに関係する変更をしたい、あるいは必要な
場合は、その章のディレクトリにローカルな .cargo/config.toml を作成して
ください。
デバイスにフラッシュする
GDB が実行中であることを前提とします。もし実行していなければ、前の セクションで説明したとおりに起動してください。
NOTE
gdbに対する-x ../openocd.gdb引数は、デバイスへの フラッシュが行われるようにすでに設定されています。そのため、通常は 単にcargo runを実行するだけで、プロジェクトのコードをデバイスに 明示的に書き込む処理まで行われます。openocd の設定スクリプトについては、 次のセクションで扱います。
それでは、gdb の load コマンドを使って、実際にプログラムをデバイスへ
フラッシュしましょう:
(gdb) load
Loading section .vector_table, size 0x194 lma 0x8000000
Loading section .text, size 0x20ec lma 0x8000194
Loading section .rodata, size 0x514 lma 0x8002280
Start address 0x08000194, load size 10132
Transfer rate: 17 KB/sec, 3377 bytes/write.
OpenOCD のターミナルにも、新しい出力が表示されます。たとえば次のような ものです:
Info : flash size = 256kbytes
+Info : Unable to match requested speed 1000 kHz, using 950 kHz
+Info : Unable to match requested speed 1000 kHz, using 950 kHz
+adapter speed: 950 kHz
+target halted due to debug-request, current mode: Thread
+xPSR: 0x01000000 pc: 0x08000194 msp: 0x2000a000
+Info : Unable to match requested speed 8000 kHz, using 4000 kHz
+Info : Unable to match requested speed 8000 kHz, using 4000 kHz
+adapter speed: 4000 kHz
+target halted due to breakpoint, current mode: Thread
+xPSR: 0x61000000 pc: 0x2000003a msp: 0x2000a000
+Info : Unable to match requested speed 1000 kHz, using 950 kHz
+Info : Unable to match requested speed 1000 kHz, using 950 kHz
+adapter speed: 950 kHz
+target halted due to debug-request, current mode: Thread
+xPSR: 0x01000000 pc: 0x08000194 msp: 0x2000a000
プログラムがロードされました。さっそくデバッグしてみましょう!