Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

Yuki Toyoda
May 29, 2021
340

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

Yuki Toyoda

May 29, 2021
Tweet

Transcript

  1. コード #![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
  2. #![no_std] no_std アトリビュートをつけると、macOS や Windows OS のような通常の OS では動 作しないプログラムを記述する、ということを宣言できる。

    Rust は標準ライブラリが std, alloc, core の 3 階層になっているが、no_std を付与する とこのうちの core を使用するようになる。 std と alloc は使用できなくなる。 たとえば Vec や println! などは使用できなくなる。 それ用に実装されたクレートから読み込む必要がある。 17
  3. #![no_main] no_main アトリビュートをつけると、Rust 標準の main 関数を使用しないことを宣言で きる。 main 関数を呼び出すと、Rust コンパイラが自動で付与するコードや

    std に関するコード が入ってしまうが、この処理には OS の機能が必要になる。 ベアメタル環境ではこれが使えない。 19
  4. ! 発散型と呼ぶ。他の言語では never 型や bottom 型という名前で表現されていることが ある。 loop 式などがこの型を返す。 値を一切返さないことを示す。

    組み込みでは、main 関数が値を返したとしても返る先がなく、返ったあとに何が起きる かわからない。ので、絶対に値は返さない。 Rust の ! (ビックリマーク、エクスクラメーションマーク、感嘆符、never) 型: https://blog-dry.com/entry/2020/11/02/000313 21
  5. LED の操作について コロナじゃなければ実物を触りながらやりたかったが… 今回使用する基板では LED は GPIO に接続されている。 そのうちの PD15

    という端子に青色の LED が接続されている。 そこと対応したメモリアドレスに対して適切な値を書くと、電圧が供給されて LED が光 るという仕組み。 今回のプログラムではそうしたペリフェラルにプログラム側からアクセスが可能。 24
  6. クレートの説明 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
  7. クレートの説明 stm32f4xx-hal: 今回使用する評価基板向けの HAL 。 cortex-m4-rt: Cortex-M4 向けのランタイムを提供するクレートで、たとえばこれによ り #[entry]

    が使える。 cortex-m-semihosting: Cortex-M シリーズ向けのデバッグ機能を提供するクレート で、 hprintln! などに使った。 panic-halt: いわゆるパニックハンドラを定義できる。 30
  8. ペリフェラルの有効化 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
  9. ペリフェラルの有効化 take でベリフェラルを取り出す。 RCC は Recent and clock control の略で、このインスタンスを通じてクロックを供給し

    て回路を有効にする。 48 MHz のクロックを供給して回路を有効化した。 constrain で操作用のインスタンスを取り出すことができる。 constrain はたとえば 2 回呼び出すことはできないようになっている。Rust の所有権シ ステムがリソース管理を行ういい例になっている。 33
  10. 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
  11. 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
  12. LED の操作をする set_high をすると LED を点灯させる。 set_low をすると LED を消灯させる。

    delay はウェイトを入れることで LED の on/off を確認できるようにしている。 36
  13. 40