0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Rustでマイコン(QEMU編)

Posted at

OverView

Rustのマイコンを理解しようとしたこの記事でQEMUをinstallしていたけど触れていなかったので追記。

今回もRust公式Docsにそってやったことを述べていきます。

What is QEMU?

マイコンだとかコンピュータの挙動をソフトウェア的に再現できるみたいです。
エミュレーションとか呼ばれている気がします。(知識不足かも)

Environment

Ubuntu22.04で動かしました。Cargoはv1.70.0。
とりあえずのinstallだけ

sudo apt install qemu-system-arm gdb-multiarch

Usage

Create project

Cortex-M3のLM3S6965用にプログラムします。
とりまgenerate

cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart

プロジェクト名はappにしました。(gitとか他にも方法はあります)

About program

src/main.rs
#![no_std]
#![no_main]

// pick a panicking behavior
use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics
// use panic_abort as _; // requires nightly
// use panic_itm as _; // logs messages over ITM; requires ITM support
// use panic_semihosting as _; // logs messages to the host stderr; requires a debugger

use cortex_m::asm;
use cortex_m_rt::entry;

#[entry]
fn main() -> ! {
    asm::nop(); // To not have main optimize to abort in release mode, remove when you add code

    loop {
        // your code goes here
    }
}

#![no_std]
Rustの組み込み開発では標準crateであるstdではなくcoreというcrateにリンクするそうです

#![no_main]
先述した通りstdのない環境でmainインターフェースを扱うためにはnightlyというものが必要らしい。

panic_halt
プログラムにpanicが起こったときの挙動を定義しているらしい

#[entry]
標準のmainインターフェースを使用しないためエントリーポイントを示す必要があります。

プログラムを止めたくないからもろもろ書いてるぞ。(適当でごめんなさい)

Set config

ターゲットに合わせた設定をしていく

.cargo/config.toml
[build]
# Pick ONE of these default compilation targets
# target = "thumbv6m-none-eabi"        # Cortex-M0 and Cortex-M0+
target = "thumbv7m-none-eabi"        # Cortex-M3
# target = "thumbv7em-none-eabi"       # Cortex-M4 and Cortex-M7 (no FPU)
# target = "thumbv7em-none-eabihf"     # Cortex-M4F and Cortex-M7F (with FPU)
# target = "thumbv8m.base-none-eabi"   # Cortex-M23
# target = "thumbv8m.main-none-eabi"   # Cortex-M33 (no FPU)
# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU)

こちらを参考に...

Build

ターゲットに合わせて

cargo build --target thumbv7m-none-eabi

とするのですがどうやらこのターゲットはデフォルトになっているらしいので

cargo build

だけでもOK

Check

どうやらcargo-binutilsをつかえばネイティブじゃないバイナリを確認できそう

最適化されたバイナリを確認するために--releaseを入れる

cargo size --bin app --release -- -A

以下の表示を確認することができた

app  :
section              size        addr
.vector_table        1024         0x0
.text                 668       0x400
.rodata                 0       0x69c
.data                   0  0x20000000
.bss                    0  0x20000000
.uninit                 0  0x20000000
.debug_loc            335         0x0
.debug_abbrev        1442         0x0
.debug_info          9313         0x0
.debug_aranges        688         0x0
.debug_ranges        1504         0x0
.debug_str          13855         0x0
.debug_pubnames      4870         0x0
.debug_pubtypes      1635         0x0
.ARM.attributes        50         0x0
.debug_frame         1448         0x0
.debug_line          6519         0x0
.comment               19         0x0
Total               43370

なおdebug情報などメタデータは正確に反映されているわけではなさそうなので
常にcargo-sizeしてねとのこと

バイナリをディスアセンブルできます。(まんま)

cargo objdump -- --disassemble-all

Let's QEMU

hello exampleを使用します

cargo build --example hello

出力されたバイナリはtarget/thumbv7m-none-eabi/debug/examples/helloにあります

またQEMU上でバイナリを叩くには以下のコマンドを用います。

qemu-system-arm \
      -cpu cortex-m3 \
      -machine lm3s6965evb \
      -nographic \
      -semihosting-config enable=on,target=native \
      -kernel target/thumbv7m-none-eabi/debug/examples/hello

出力を確認できました。

Timer with period zero, disabling
Hello, world!

Debug

以下のコマンドでQEMUをdebugモードで起動することができます。

qemu-system-arm \
      -cpu cortex-m3 \
      -machine lm3s6965evb \
      -nographic \
      -semihosting-config enable=on,target=native \
      -gdb tcp::3333 \
      -S \
      -kernel target/thumbv7m-none-eabi/debug/examples/hello

先程から追加された2行について
-gdb tcp::3333
QEMUがTCPポート(3333番)でデバッガーの接続を待ちます
-S
デバッガーを起動する前にプログラムが終わってしまうことを防ぎます。実際「hello, world!」とでていませんね。

別のターミナルでGDBを起動します。

gdb-multiarch -q target/thumbv7m-none-eabi/debug/examples/hello

そして接続してみるとこのような表示がでるはず

(gdb)target remote:3333
Remote debugging using :3333
cortex_m_rt::Reset () at src/lib.rs:497
497	pub unsafe extern "C" fn Reset() -> ! {

どうやらプロセスは停止していてReset関数を指していますね
これは最終的にmain関数を呼び出すことができて以下のようにスキップします

(gdb) break main
Breakpoint 1 at 0x484: file examples/hello.rs, line 11.
(gdb) continue
Continuing.

Breakpoint 1, hello::__cortex_m_rt_main_trampoline () at examples/hello.rs:11
11	#[entry]

先に進んでいきます

(gdb) next
[Inferior 1 (process 1) exited normally]

「プロセスが正常に終了したよ」と表示されましたね
ここでもう一度QEMU側のターミナルを覗いてみると

Hello, world!

出力されてますね

それではGDBも停止させましょう

(gdb)quit //ただの'q'でもokです

おわりに

QEMUを使ってboardなしでdebugしてみました。家での作業が捗りそうです。
今後もRustでマイコンを学んでいく予定です。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?