タイマー
「ベアメタル」の組み込みシステムの大きな利点の 1 つは、自分のマシンで起こるあらゆることを自分で制御できることです。これにより、時間を本当に高精度に制御できます。自分でそうしない限り、何かによって処理が遅くなることはありません。
しかし、時間を本当に正確に扱いたいのであれば、おそらく助けが必要になることもこれまでに見てきました。nRF52833 のような組み込み MCU はすべて、「タイマー」という形でこの種の支援を提供しています。タイマーは、その名のとおり、時間を非常に高精度に追跡する小さな時計のように動作するペリフェラルです。
nRF52833 には 4 つのタイマーが搭載されています。チップのドキュメントを見ると、それらのセットアップや使用方法はかなり複雑であることがわかります。幸い、HAL はタイマーをラップしており、一般的な用途を簡単に扱えるようにしてくれます。タイマーの最も一般的な用途は、正確な時間だけ待機することです。これは、前のセクションの wait() 関数がまさに実現しようとしていたことです。
examples/timer-blinky.rs を見てみましょう。このコードはタイマーをセットアップし、各トグルの間に 500ms(0.5 秒)の遅延を入れるために使用しています。
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use embedded_hal::{delay::DelayNs, digital::OutputPin};
use nrf52833_hal::{gpio, pac, timer};
use panic_halt as _;
#[entry]
fn main() -> ! {
let peripherals = pac::Peripherals::take().unwrap();
let p0 = gpio::p0::Parts::new(peripherals.P0);
let mut row1 = p0.p0_21.into_push_pull_output(gpio::Level::High);
let _col1 = p0.p0_28.into_push_pull_output(gpio::Level::Low);
let mut timer0 = timer::Timer::new(peripherals.TIMER0);
loop {
timer0.delay_ms(500);
row1.set_high().unwrap();
timer0.delay_ms(500);
row1.set_low().unwrap();
}
}
このコードを cargo run --release --example timer-blinky で実行し、ストップウォッチで時間を測ってみてください。オン・オフの各サイクルがちょうど 1 秒であることがわかるはずです。
気づくかもしれない点:
-
使用している
delay_ms()メソッドを利用するには、embedded_hal::Delayトレイトを使う必要があります。 -
これまでと同様に、PAC のペリフェラル構造体からそのペリフェラルを取り出して HAL に渡します。
これで、実運用レベルの blinky になりました。では、これが持つ意味について少し話しましょう。