ラズピコでRust(16) Delayオブジェクトなしで delay() を実現する

ラズピコでRust(16) Delayオブジェクトなしで delay() を実現する

皆さん こんにちは。
ポンコツRustacean の moon です。

この記事は開発環境を構築することを前提にしています。
環境構築について知りたい方は こちらの記事 をご覧になってください。

このサイトは 書籍 基礎から学ぶ組込みRust を参考にしています。

今回は軽い記事ですから、さっと読むことができます。

ディレイ

今回はディレイ(遅延・待ち)の関数をつくってみます。

Delay 構造体を使って delay するのが一般的ですが、このオブジェクトを2つ作ることはできないようです。

良く以下のコードを見かけますが、 new() で core.SYST を消費してしまうため new() は一度しか使えないようです。

let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());

また、次のように インスタンス.メソッド() のような記述が必要で、使う側の関数(メソッド)の引数にインスタンスを渡す必要があり「ちょっと、かったるい」です。

delay.delay_ms(100)

そこで単に関数を呼び出せば遅延できるようにしました。

以下のコードはHALの中身を少し改造したものです。
unsafe でポインタを使って64ビットカウンタの下位32ビットのレジスタを読んでいます。
この読み出し自体は他に影響を与えないので排他制御は不要です。

この32ビットカウンタは1マイクロ秒に一度カウントアップするため約71分でオーバーフローします。
たまたまオーバーフローする瞬間に使っても、wrapping_sub()が桁上げ分をカバーしてくれるので、msecやμsecオーダーの時間待ちをする分には全く問題なく使えます。

手軽に時間待ちが必要な場面で、ぜひ使ってみてください。

use rp_pico::hal::pac;

pub fn delay_us(mut us: u32) {
    let mut start = get_counter_low();
    loop {
        let now = get_counter_low();
        let waited = now.wrapping_sub(start);
        if waited >= us {
            break;
        }
        start = now;
        us -= waited;
    }
}

pub fn delay_ms(ms: u32) {
    for _ in 0..ms {
        delay_us(1000);
    }
}

pub fn get_counter_low() -> u32 {
    unsafe { &*pac::TIMER::PTR }.timerawl().read().bits()
}

GitHubにアップするまでもないので、必要ならこれをコピペして試してみてください。

お疲れさまでした。

Timerカテゴリの最新記事