Wio Terminal で probe-run / defmt
はじめに
『基礎から学ぶ 組込みRust』では追加機材が不要な cargo hf2 を使ってファームウェアを書き込み、UART で文字を出力しました。 組込み Rust ではその他にも便利なツールがあります。 今回はそのうちの、probe-run と defmt を Wio Terminal で使ってみます (両方 knurling-rs の成果物です) 。
Runs embedded programs just like native ones
defmt ("de format", short for "deferred formatting") is a highly efficient logging framework that targets resource-constrained devices, like microcontrollers.
注意
本記事の内容を試すには、JLink か DAPLink かのデバッグアダプタを Wio Terminal に接続している必要があります。 Seeeduino XIAO を用いた DAPLink デバッグアダプタの環境構築は、基礎から学ぶ 組込みRust のサポートサイトに手順を掲載しています。
サンプルプロジェクトと実行方法
下に Wio Terminal で probe-run / defmt を試すためのサンプルプロジェクトを用意しました。
事前準備
probe-run をインストールします。
$ cargo install probe-run
Linux の場合は、libudev と libusb もインストールします。
sudo apt install libudev libusb
実行方法
Wio Terminal をデバッグアダプタと接続している状態で、プロジェクトを clone して、cargo run するだけです。
$ git clone https://github.com/tomoyuki-nakabayashi/wio-terminal-probe-run.git $ cd wio-terminal-probe-run $ cargo run
実行結果は次のようになります。
Running `probe-run --chip ATSAMD51P19A --speed 100 target/thumbv7em-none-eabihf/debug/wio-terminal-probe-run` (HOST) INFO flashing program (12.92 KiB) (HOST) INFO success! ──────────────────────────────────────────────────────────────────────────────── 0 INFO Hello, world! └─ wio_terminal_probe_run::__cortex_m_rt_main @ src/main.rs:11 (HOST) WARN program has used at least 195528 bytes of stack space, data segments may be corrupted due to stack overflow stack backtrace: 0: lib::inline::__bkpt at ./asm/inline.rs:13 1: __bkpt at ./asm/lib.rs:49 2: wio_terminal_probe_run::exit at src/lib.rs:29 3: wio_terminal_probe_run::__cortex_m_rt_main at src/main.rs:12 4: main at src/main.rs:10 5: ResetTrampoline at $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:547 6: Reset at $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:550 7: __DEFMT_MARKER_TIMESTAMP_WAS_DEFINED 8: Reset at $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:497 error: the stack appears to be corrupted beyond this point
実行時のログは、タイムスタンプ (サンプル実装は1ずつインクリメントされるただのカウンタ)、ログレベル、ソースコード上の位置付きで出力されます。
0 INFO Hello, world! └─ wio_terminal_probe_run::__cortex_m_rt_main @ src/main.rs:11
bkpt 命令を呼び出したり、プログラムが panic するとバックトレースを出力します。
stack backtrace: 0: lib::inline::__bkpt at ./asm/inline.rs:13 1: __bkpt at ./asm/lib.rs:49 2: wio_terminal_probe_run::exit at src/lib.rs:29 3: wio_terminal_probe_run::__cortex_m_rt_main at src/main.rs:12 4: main at src/main.rs:10 5: ResetTrampoline at $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:547 6: Reset at $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:550 7: __DEFMT_MARKER_TIMESTAMP_WAS_DEFINED 8: Reset at $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:497 error: the stack appears to be corrupted beyond this point
少し解説
Cargo.toml
panic 時に probe-run 経由でバックトレースを出力する panic-probe
を使うことができます。
panic-probe = "0.2.0"
defmt は、Cargo.toml
に次の設定を追加します。features はこういうものだ、と思って下さい。
defmt = "0.2.0" defmt-rtt = "0.2.0" [features] default = [ "defmt-default", ] defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = []
.cargo/config
probe-run と defmt を使うためにリンクオプションを2つ追加します。
[target.thumbv7em-none-eabihf] rustflags = [ "-C", "link-arg=-Tlink.x", "-C", "link-arg=--nmagic", # 追加 "-C", "link-arg=-Tdefmt.x", # 追加 ] # runner を probe run に runner = "probe-run --chip ATSAMD51P19A --speed 100"
src/lib.rs
アプリケーションから使えるように、lib.rs
に部品をまとめておきます。
#![no_std] use core::sync::atomic::{AtomicUsize, Ordering}; use defmt_rtt as _; // global logger use panic_probe as _; use wio_terminal as _; use panic_probe as _; // same panicking *behavior* as `panic-probe` but doesn't print a panic message // this prevents the panic message being printed *twice* when `defmt::panic` is invoked #[defmt::panic_handler] fn panic() -> ! { cortex_m::asm::udf() } // defmt のタイムスタンプを実装します // タイマを使えば、起動からの時間を表示したりできます static COUNT: AtomicUsize = AtomicUsize::new(0); defmt::timestamp!("{=usize}", { // NOTE(no-CAS) `timestamps` runs with interrupts disabled let n = COUNT.load(Ordering::Relaxed); COUNT.store(n + 1, Ordering::Relaxed); n }); /// Terminates the application and makes `probe-run` exit with exit-code = 0 pub fn exit() -> ! { loop { cortex_m::asm::bkpt(); } }
src/main.rs
後は使うだけです。
#![no_std] #![no_main] use wio_terminal_probe_run; use wio_terminal as wio; use wio::entry; #[entry] fn main() -> ! { defmt::info!("Hello, world!"); wio_terminal_probe_run::exit() }
制限
次の issue に挙げられている通り、現在は speed を 100 khz にしないとうまく動きません。 そのため、少し動作が遅く感じます。
おまけ
probe-run は probe-rs を活かして実装されています。 probe-rs ではオプションの機能として、FTDI のデバッグアダプタをプローブする機能が実装されています。 そのうち、probe-run でも使えるようになるかもしれませんね。