Share
Embed
Transcript
40 slides
-
今日の免責事項 OS / CPU / メモリ等はある程度知識がある前提で進めます。 それらに関する用語が普通に登場します。 今日はエミュレータの上でのみ動かします。 私は組み込み開発も残念ながらプロダクション経験があるわけではありません。 今日の内容は『実践
Rust プログラミング入門』に詳しく書いてあります。まるっきり同 じです。 2 -
ベアメタルとは OS の機能を一切利用せずに、直接ハードウェア上にプログラムを走らせる手法のこと。 今回はハイパーバイザを使用するパターンは含みません。 OS はハードウェアを抽象化し、プロセスという単位でプログラムの実行を分離する。 が、その恩恵を一切受けないことを指す。 メモリ管理は自分でやる必要がある。malloc は使えない。スタックメモリは 1
から 実装する必要がある。 ハードウェアへの初期化、アクセスも自分でやる必要がある。 8 -
コード #![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 -
#![no_std] no_std アトリビュートをつけると、macOS や Windows OS のような通常の OS では動 作しないプログラムを記述する、ということを宣言できる。
Rust は標準ライブラリが std, alloc, core の 3 階層になっているが、no_std を付与する とこのうちの core を使用するようになる。 std と alloc は使用できなくなる。 たとえば Vec や println! などは使用できなくなる。 それ用に実装されたクレートから読み込む必要がある。 17 -
no_std 環境においては下記のコードはコンパイルエラーに… #![no_std] #![no_main] #[entry] fn main() -> ! {
println!("Hello, World!"); loop {} } 18 -
#![no_main] no_main アトリビュートをつけると、Rust 標準の main 関数を使用しないことを宣言で きる。 main 関数を呼び出すと、Rust コンパイラが自動で付与するコードや
std に関するコード が入ってしまうが、この処理には OS の機能が必要になる。 ベアメタル環境ではこれが使えない。 19 -
! 発散型と呼ぶ。他の言語では never 型や bottom 型という名前で表現されていることが ある。 loop 式などがこの型を返す。 値を一切返さないことを示す。
組み込みでは、main 関数が値を返したとしても返る先がなく、返ったあとに何が起きる かわからない。ので、絶対に値は返さない。 Rust の ! (ビックリマーク、エクスクラメーションマーク、感嘆符、never) 型: https://blog-dry.com/entry/2020/11/02/000313 21 -
L チカ マイコンで言うところの Hello, World に当たる。 実物では LED をチカチカさせることができる。 今回は
QEMU 上でチカチカさせる。 23 -
LED の操作について コロナじゃなければ実物を触りながらやりたかったが… 今回使用する基板では LED は GPIO に接続されている。 そのうちの PD15
という端子に青色の LED が接続されている。 そこと対応したメモリアドレスに対して適切な値を書くと、電圧が供給されて LED が光 るという仕組み。 今回のプログラムではそうしたペリフェラルにプログラム側からアクセスが可能。 24 -
Memory Mapped I/O 特定のメモリ番地はペリフェラルとマッピングされている。 その特定のメモリ番地に対して値を書くと、ペリフェラルを制御できる。 ペリフェラルとメモリ空間がマッピングされている方式を Memory Mapped I/O と呼
ぶ。 今回使用するのは、そうしたメモリへの直接のアクセスを抽象化してくれているクレー トになる。 27 -
クレートの説明 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 -
クレートの説明 stm32f4xx-hal: 今回使用する評価基板向けの HAL 。 cortex-m4-rt: Cortex-M4 向けのランタイムを提供するクレートで、たとえばこれによ り #[entry]
が使える。 cortex-m-semihosting: Cortex-M シリーズ向けのデバッグ機能を提供するクレート で、 hprintln! などに使った。 panic-halt: いわゆるパニックハンドラを定義できる。 30 -
ペリフェラルの有効化 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 -
ペリフェラルの有効化 take でベリフェラルを取り出す。 RCC は Recent and clock control の略で、このインスタンスを通じてクロックを供給し
て回路を有効にする。 48 MHz のクロックを供給して回路を有効化した。 constrain で操作用のインスタンスを取り出すことができる。 constrain はたとえば 2 回呼び出すことはできないようになっている。Rust の所有権シ ステムがリソース管理を行ういい例になっている。 33 -
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 -
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 -
LED の操作をする set_high をすると LED を点灯させる。 set_low をすると LED を消灯させる。
delay はウェイトを入れることで LED の on/off を確認できるようにしている。 36