⑥割り込み処理

このコード部分の話

#[hal::pac::interrupt]
fn IO_IRQ_BANK0() {
    static mut LED_AND_BUTTON: Option<LedAndButton> = None;

    if LED_AND_BUTTON.is_none() {
        critical_section::with(|cs| {
            *LED_AND_BUTTON = GLOBAL_PINS.borrow(cs).take();
        });
    }

    if let Some(gpios) = LED_AND_BUTTON {
        let (green_led, red_led, orange_led, button, timer) = gpios;
        if button.interrupt_status(hal::gpio::Interrupt::EdgeLow) {
            info!("Button pressed");

            red_led.set_low().unwrap();

            info!("green");
            green_led.set_high().unwrap();
            timer.delay_ms(2000);
            green_led.set_low().unwrap();

            info!("orange");
            for _ in 1..4 {
                orange_led.set_high().unwrap();
                timer.delay_ms(500);
                orange_led.set_low().unwrap();
                timer.delay_ms(500);
            }
            orange_led.set_low().unwrap();

            info!("red");
            red_led.set_high().unwrap();
            button.clear_interrupt(hal::gpio::Interrupt::EdgeLow);
        }
    }
}

hal::pac::interrupt

関数を割り込みの関数として表すマクロです。 次のIO_IRQ_BANK0を割り込みの関数として扱うことを意味しています。

IO_IRQ_BANK0

IO割り込みとして予約されている関数です。 割り込み登録をしたIO_IRQ_BANK0に紐づく関数です。このように割り込みの関数は、割り込みによって関数名が決められています。

割り込み関数内での借用

    static mut LED_AND_BUTTON: Option<LedAndButton> = None;

LED_AND_BUTTONstaticな変数として用意されます。 staticは、プログラムの最初に初期化されてからプログラムが終了するまで残り続ける変数を意味しています。

そしてIO_IRQ_BANK0の中で宣言されるということは、この関数が呼び出され終了した後もLED_AND_BUTTONは残り続け、再びIO_IRQ_BANK0が呼び出されると残り続けているLED_AND_BUTTONがそのまま再利用されます。

    if LED_AND_BUTTON.is_none() {
        critical_section::with(|cs| {
            *LED_AND_BUTTON = GLOBAL_PINS.borrow(cs).take();
        });
    }

IO_IRQ_BANK0内で宣言したLED_AND_BUTTONNoneだった時に、Critical Sectionを借用し、GLOBAL_PINSLED_AND_BUTTONに入れる処理です。

LED_AND_BUTTONの前に*がついていますが、これはC言語のポインターに近い概念です。 LED_AND_BUTTONは、static mutになっていますがRustが自動的に&mutと解釈するため、これをmutとして扱う(&を外す)ために*が必要になります。

割り込みされたか確認

    if button.interrupt_status(hal::gpio::Interrupt::EdgeLow) {...}

IO_IRQ_BANK0は、GPIOの割り込みがあったと時に動作し、それがどのGPIOのPinであったか認識することはできません。 このif文は、buttonのPinでEdgeLowの割り込みがあったか確認をしています。 もし割り込みがあった場合は、{...}の処理を実行します。

割り込み情報のクリア

    button.clear_interrupt(hal::gpio::Interrupt::EdgeLow);

clear_interruptbuttonのPinに割り込みがあった情報をクリアします。

今回は、割り込みを検出するPinが1つしなかったため、必要性を感じないですが、複数の割り込みを検知するPinがあった場合、このclear_interruptをしないとすべてのGPIO割り込みでbuttonのPinの処理が実行されてしまいます。 そのため、このclear_interruptの処理は必須になります。