Slide 1

Slide 1 text

Rust ハンズオン第 6 回 ベアメタル Rust 編 1

Slide 2

Slide 2 text

今日の免責事項 OS / CPU / メモリ等はある程度知識がある前提で進めます。 それらに関する用語が普通に登場します。 今日はエミュレータの上でのみ動かします。 私は組み込み開発も残念ながらプロダクション経験があるわけではありません。 今日の内容は『実践 Rust プログラミング入門』に詳しく書いてあります。まるっきり同 じです。 2

Slide 3

Slide 3 text

組み込み開発とは 3

Slide 4

Slide 4 text

組み込み開発とは 家電、車載システム、産業機器、その他マイコンなど で使用するソフトウェア。 Web サービスのようにリソースが潤沢ということはない。 組み込み開発の場合はかなりリソースが絞られる。 4

Slide 5

Slide 5 text

組み込み開発 リソースが絞られる場面 = Rust 向き。 5

Slide 6

Slide 6 text

他の言語 C / C++ TinyGo mruby ...など。 6

Slide 7

Slide 7 text

ベアメタルとは 7

Slide 8

Slide 8 text

ベアメタルとは OS の機能を一切利用せずに、直接ハードウェア上にプログラムを走らせる手法のこと。 今回はハイパーバイザを使用するパターンは含みません。 OS はハードウェアを抽象化し、プロセスという単位でプログラムの実行を分離する。 が、その恩恵を一切受けないことを指す。 メモリ管理は自分でやる必要がある。malloc は使えない。スタックメモリは 1 から 実装する必要がある。 ハードウェアへの初期化、アクセスも自分でやる必要がある。 8

Slide 9

Slide 9 text

準備 今回は Docker を使用するので、Docker for Mac 等をインストールしておいてくださ い。 下記リポジトリをクローンします。 https://github.com/yuk1ty/embeded-rust-handson 9

Slide 10

Slide 10 text

準備 今回使用するビルドターゲットを README.md にしたがって順に上から追加していきま しょう。 10

Slide 11

Slide 11 text

準備 Docker 上で今回使用するコードが実行できれば完了です。 うまく実行できれば、 Hello, World と出るはず。 11

Slide 12

Slide 12 text

QEMU エミュレータ。さまざまな CPU をターゲットにエミュレートできる。 OS 作ったりするときとかによく使う。 12

Slide 13

Slide 13 text

今回使用するプラットフォーム STM32F4DISCOVERY という評価基板を使用する。 コロナじゃなければ予算を組んで配りたかったです…! もし興味があれば、買ってみて試してみて欲しい。 13

Slide 14

Slide 14 text

Hello, World のコードを眺めてみる 14

Slide 15

Slide 15 text

コード #![no_std] #![no_main] extern crate panic_halt; use cortex_m_rt::entry; use cortex_m_semihosting::{debug, hprintln}; #[entry] fn main() -> ! { let _ = hprintln!("Hello, World!"); debug::exit(debug::EXIT_SUCCESS); loop {} } 15

Slide 16

Slide 16 text

見慣れないものリスト #![no_std] #![no_main] #[entry] ! 16

Slide 17

Slide 17 text

#![no_std] no_std アトリビュートをつけると、macOS や Windows OS のような通常の OS では動 作しないプログラムを記述する、ということを宣言できる。 Rust は標準ライブラリが std, alloc, core の 3 階層になっているが、no_std を付与する とこのうちの core を使用するようになる。 std と alloc は使用できなくなる。 たとえば Vec や println! などは使用できなくなる。 それ用に実装されたクレートから読み込む必要がある。 17

Slide 18

Slide 18 text

no_std 環境においては下記のコードはコンパイルエラーに… #![no_std] #![no_main] #[entry] fn main() -> ! { println!("Hello, World!"); loop {} } 18

Slide 19

Slide 19 text

#![no_main] no_main アトリビュートをつけると、Rust 標準の main 関数を使用しないことを宣言で きる。 main 関数を呼び出すと、Rust コンパイラが自動で付与するコードや std に関するコード が入ってしまうが、この処理には OS の機能が必要になる。 ベアメタル環境ではこれが使えない。 19

Slide 20

Slide 20 text

#[entry] main 関数は使えないので、代わりにエントリポイントがここであることをコンパイラに 伝える。 これ自体は今回使用している cortex-m-rt クレートの機能にあたる。 20

Slide 21

Slide 21 text

! 発散型と呼ぶ。他の言語では never 型や bottom 型という名前で表現されていることが ある。 loop 式などがこの型を返す。 値を一切返さないことを示す。 組み込みでは、main 関数が値を返したとしても返る先がなく、返ったあとに何が起きる かわからない。ので、絶対に値は返さない。 Rust の ! (ビックリマーク、エクスクラメーションマーク、感嘆符、never) 型: https://blog-dry.com/entry/2020/11/02/000313 21

Slide 22

Slide 22 text

L チカ 22

Slide 23

Slide 23 text

L チカ マイコンで言うところの Hello, World に当たる。 実物では LED をチカチカさせることができる。 今回は QEMU 上でチカチカさせる。 23

Slide 24

Slide 24 text

LED の操作について コロナじゃなければ実物を触りながらやりたかったが… 今回使用する基板では LED は GPIO に接続されている。 そのうちの PD15 という端子に青色の LED が接続されている。 そこと対応したメモリアドレスに対して適切な値を書くと、電圧が供給されて LED が光 るという仕組み。 今回のプログラムではそうしたペリフェラルにプログラム側からアクセスが可能。 24

Slide 25

Slide 25 text

ペリフェラル CPU コアとメモリ以外の周辺機器を指す。 ディスプレイとかハードディスクとか。 25

Slide 26

Slide 26 text

GPIO General Purpose Input/Output。汎用 I/O ポート。 集積回路やボードの上にあるピンのことをいう。 26

Slide 27

Slide 27 text

Memory Mapped I/O 特定のメモリ番地はペリフェラルとマッピングされている。 その特定のメモリ番地に対して値を書くと、ペリフェラルを制御できる。 ペリフェラルとメモリ空間がマッピングされている方式を Memory Mapped I/O と呼 ぶ。 今回使用するのは、そうしたメモリへの直接のアクセスを抽象化してくれているクレー トになる。 27

Slide 28

Slide 28 text

クレートの説明 Cargo.toml の設定は下記のようになっている。 [dependencies] cortex-m-rt = "0.6.2" cortex-m-semihosting = "0.3.5" embedded-hal = "0.2.3" panic-halt = "0.2.0" stm32f4xx-hal = {version="0.7.0", features=["stm32f407"] 28

Slide 29

Slide 29 text

クレートの説明 embeded-hal ファームウェア開発において、マイコンごとにドライバが違うとコードを書いても再利 用が難しくなる。 ハードウェア間の違いを吸収するために「ハードウェア抽象化レイヤ(HAL)」がある と便利。 組み込み開発において有用なトレイトを集めたクレートになっている。 29

Slide 30

Slide 30 text

クレートの説明 stm32f4xx-hal: 今回使用する評価基板向けの HAL 。 cortex-m4-rt: Cortex-M4 向けのランタイムを提供するクレートで、たとえばこれによ り #[entry] が使える。 cortex-m-semihosting: Cortex-M シリーズ向けのデバッグ機能を提供するクレート で、 hprintln! などに使った。 panic-halt: いわゆるパニックハンドラを定義できる。 30

Slide 31

Slide 31 text

コード 31

Slide 32

Slide 32 text

ペリフェラルの有効化 use cortex_m_rt::entry; use cortex_m_semihosting::debug; use stm32f4xx_hal::{prelude::*, stm32}; #[entry] fn main() -> ! { if let (Some(dp), Some(cp)) = (stm32::Peripherals::take(), stm32::CorePeripherals::take()) { let rcc = dp.RCC.constrain(); let clocks = rcc.cfgr.sysclk(48.mhz()).freeze(); } debug::exit(debug::EXIT_SUCCESS); loop {} } 32

Slide 33

Slide 33 text

ペリフェラルの有効化 take でベリフェラルを取り出す。 RCC は Recent and clock control の略で、このインスタンスを通じてクロックを供給し て回路を有効にする。 48 MHz のクロックを供給して回路を有効化した。 constrain で操作用のインスタンスを取り出すことができる。 constrain はたとえば 2 回呼び出すことはできないようになっている。Rust の所有権シ ステムがリソース管理を行ういい例になっている。 33

Slide 34

Slide 34 text

GPIO の取得 use cortex_m_rt::entry; use cortex_m_semihosting::debug; use stm32f4xx_hal::{prelude::*, stm32}; #[entry] fn main() -> ! { if let (Some(dp), Some(cp)) = (stm32::Peripherals::take(), stm32::CorePeripherals::take()) { let rcc = dp.RCC.constrain(); let clocks = rcc.cfgr.sysclk(48.mhz()).freeze(); let gpiod = dp.GPIOD.split(); let mut led = gpiod.pd15.into_push_pull_output(); } debug::exit(debug::EXIT_SUCCESS); loop {} } 34

Slide 35

Slide 35 text

LED の制御をする前準備をしている。 split は同様に操作用のインスタンスを取り出す。 -- LED の操作をする use cortex_m_rt::entry; use cortex_m_semihosting::debug; use stm32f4xx_hal::{delay::Delay, prelude::*, stm32}; #[entry] fn main() -> ! { if let (Some(dp), Some(cp)) = (stm32::Peripherals::take(), stm32::CorePeripherals::take()) { let rcc = dp.RCC.constrain(); let clocks = rcc.cfgr.sysclk(48.mhz()).freeze(); let gpiod = dp.GPIOD.split(); let mut led = gpiod.pd15.into_push_pull_output(); let mut delay = Delay::new(cp.SYST, clocks); for _ in 0..5 { led.set_high().unwrap(); delay.delay_ms(100u32); led.set_low().unwrap(); delay.delay_ms(100u32); } } 35

Slide 36

Slide 36 text

LED の操作をする set_high をすると LED を点灯させる。 set_low をすると LED を消灯させる。 delay はウェイトを入れることで LED の on/off を確認できるようにしている。 36

Slide 37

Slide 37 text

動かす cargo run 37

Slide 38

Slide 38 text

動かす 38

Slide 39

Slide 39 text

動かす ちょっとコンソールだと味気ないですが…! LED が on/off されていることがわかる。 実機上で動かすと動くよ! 39

Slide 40

Slide 40 text

40