Hello, world!
注意 ユーザーマニュアル(page 21)ではんだ付けしなければならないと書いてあるにも関わらず、 STM32F3DISCOVERY上のSB10「はんだブリッジ」(ボードの裏を見て下さい)がはんだ付けされていない、と複数の読者が報告しています。 これは、後ほど出てくるITMと
iprint!
マクロを使うために必要です。
TL;DR 2つの選択肢があります。SB10はんだブリッジをはんだ付けするか、下記写真の通りSW0とPB3の間をワイヤで接続するか、です。
低レベルのことを始める前に、もう少しだけ役立つ魔法を学んで下さい。
LEDを点滅させることは、組込みの世界の「Hello, world」です。
しかし、このセクションでは、ラップトップのコンソールに出力するちゃんとした「Hello, world」プログラムを実行します。
06-hello-world
ディレクトリに移動して下さい。その中にスターターコードがあります。
#![deny(unsafe_code)] #![no_main] #![no_std] #[allow(unused_imports)] use aux6::{entry, iprint, iprintln}; #[entry] fn main() -> ! { let mut itm = aux6::init(); iprintln!(&mut itm.stim[0], "Hello, world!"); loop {} }
iprintln
マクロは、メッセージを整え、マイクロコントローラのITMに出力します。ITMは、Instrumentation Trace Macrocellの略であり、
SWD(Serial Wire Debug)の上で通信するプロトコルです。これは、マイクロコントローラからデバッグしているホストにメッセージを送るために使います。
この通信は、一方向だけです。デバッグしているホストは、マイクロコントローラにデータを送ることができません。
OpenOCDは、デバッグセッションを管理し、ITMチャネルを通して送信されたデータを受信し、ファイルにリダイレクトします。
ITMプロトコルは、フレーム(イーサネットフレートのようなものだと考えて下さい)で動作します。各フレームは、ヘッダと可変長のペイロードを持ちます。
OpenOCDは、フレームを受信し、フレームを解析せずに、直接ファイルに書き込みます。
マイクロコントローラが、iprintln
マクロを使用して「Hello, world!」という文字列を送信した場合、
OpenOCDの出力ファイルは、その文字列をそのまま含んでいるわけではありません。
元の文字列を復元するために、OpenOCDの出力ファイルを解析しなければなりません。
届いた新しいデータの解析を行うために、itmdump
プログラムを使用します。
既にitmdump
プログラムをインストールの章でインストールしているはずです。
*nix OSを使っている場合、新しい端末の/tmp
ディレクトリ下で、Windowsを使っている場合、%TEMP%
ディレクトリ下で、
次のコマンドを実行して下さい。これはOpenOCDを実行しているのと、同じディレクトリである必要があります。
注記
itmdump
とopenocd
との両方が、同じディレクトリで実行していることが、非常に重要です。
$ # itmdumpする端末
$ # *nix
$ cd /tmp && touch itm.txt
$ # Windows
$ cd %TEMP% && type nul >> itm.txt
$ # 両方
$ itmdump -F -f itm.txt
このコマンドは、itmdump
がitm.txt
を監視している間、ブロックします。この端末は開いたままにしておきます。
では、スターターコードをビルドして、マイクロコントローラのFlashに書き込みましょう。
--target thumbv7em-none-eabihf
フラグをCargo呼び出しごとに渡さなくて済むように、.cargo/configにデフォルトターゲットを設定できます。
[target.thumbv7em-none-eabihf]
runner = "arm-none-eabi-gdb -q -x openocd.gdb"
rustflags = [
"-C", "link-arg=-Tlink.x",
]
+[build]
+target = "thumbv7em-none-eabihf"
これで、--target
が指定されない場合、Cargoは、ターゲットがthumbv7em-none-eabihf
だと想定しましす。
$ cargo run
Reading symbols from target/thumbv7em-none-eabihf/debug/hello-world...done.
(..)
Loading section .vector_table, size 0x400 lma 0x8000000
Loading section .text, size 0x27c4 lma 0x8000400
Loading section .rodata, size 0x744 lma 0x8002be0
Start address 0x8002980, load size 13064
Transfer rate: 18 KB/sec, 4354 bytes/write.
Breakpoint 1 at 0x8000402: file src/06-hello-world/src/main.rs, line 10.
Note: automatically using hardware breakpoints for read-only addresses.
Breakpoint 1, main () at src/06-hello-world/src/main.rs:10
10 let mut itm = aux6::init();
Cargoプロジェクトのルートディレクトリに.gdbinit
があることに留意して下さい。
これは、前のセクションで使ったものと非常によく似ています。
iprintln!
ステートメントを実行する前に、itmdump
が監視しているファイルと同じファイルに対して、OpenOCDがITM出力をリダイレクトするように指示しなければなりません。
(gdb) # ITMをグローバルに有効化し、itm.txtに全ての出力をリダイレクトします
(gdb) monitor tpiu config internal itm.txt uart off 8000000
(gdb) # ITMポート0を有効にします
(gdb) monitor itm port 0 on
全ての準備が整ったはずです!では、iprintln
ステートメントを実行します。
(gdb) next
12 iprintln!(&mut itm.stim[0], "Hello, world!");
(gdb) next
14 loop {}
itmdump
端末に、何らかの出力が見られるはずです。
$ itmdump -F -f itm.txt
(..)
Hello, world!
素晴らしい、そう思いませんか?以降のセクションでiprintln
をロギングツールとして、自由に活用して下さい。
次:これで全てではありません!ITMを使うのは、iprint!
マクロはだけではありません。:-)