Rp2040 interrupts doesn't fire (rp-hal/rp-pico)

I'm trying to get interrupt handling to work on a Raspberry Pico board with the rp-pico crate and rp-hal/embedded-hal.
But somehow I miss something, because the interrupt handler doesn't seem to run. Or at least the led is not switched.
Can you please have a look and tell me what is missing or done wrong?

[dependencies]
cortex-m = "0.7"
embedded-hal = "0.2"
embedded-time = "0.12"
panic-halt = "0.2"
rp-pico = { path = "./rp-hal/boards/rp-pico" }
  • rp-pico is from rp-hal GitHub checkout.

My code:

#![no_std]
#![no_main]
#![deny(clippy::all)]
#![deny(unsafe_code)]
#![deny(warnings)]

use core::{
    cell::RefCell,
    sync::atomic::{AtomicBool, Ordering},
};
use cortex_m::interrupt::Mutex;
use embedded_hal::digital::v2::OutputPin;
use embedded_time::duration::Extensions;
use panic_halt as _;
use rp_pico::{
    entry,
    hal::{
        self,
        gpio::{bank0::Gpio25, Output, Pin, PushPull},
    },
    pac::{self, interrupt},
};

type LEDPinType = Pin<Gpio25, Output<PushPull>>;

static G_LED_PIN: Mutex<RefCell<Option<LEDPinType>>> = Mutex::new(RefCell::new(None));
static G_IS_LED_HIGH: AtomicBool = AtomicBool::new(false);

#[entry]
fn main() -> ! {
    // Grab our singleton objects
    let mut peripherals = pac::Peripherals::take().unwrap();
    // let core = pac::CorePeripherals::take().unwrap();

    // Set up the watchdog driver - needed by the clock setup code
    let mut watchdog = hal::Watchdog::new(peripherals.WATCHDOG);

    // Configure the clocks
    //
    // The default is to generate a 125 MHz system clock
    let _clocks = hal::clocks::init_clocks_and_plls(
        rp_pico::XOSC_CRYSTAL_FREQ,
        peripherals.XOSC,
        peripherals.CLOCKS,
        peripherals.PLL_SYS,
        peripherals.PLL_USB,
        &mut peripherals.RESETS,
        &mut watchdog,
    )
    .ok()
    .unwrap();

    #[allow(unsafe_code)]
    unsafe {
        cortex_m::interrupt::enable();
    }

    // Alarm timer
    let mut timer = hal::Timer::new(peripherals.TIMER, &mut peripherals.RESETS);
    let mut alarm0 = timer.alarm_0().unwrap();

    // The single-cycle I/O block controls our GPIO pins
    let sio = hal::Sio::new(peripherals.SIO);

    // Set the pins up according to their function on this particular board
    let pins = rp_pico::Pins::new(
        peripherals.IO_BANK0,
        peripherals.PADS_BANK0,
        sio.gpio_bank0,
        &mut peripherals.RESETS,
    );

    // Set the LED to be an output
    let led_pin = pins.led.into_push_pull_output();

    // Make led_pin global static for usage in interrupt handler
    cortex_m::interrupt::free(|cs| {
        G_LED_PIN.borrow(cs).replace(Some(led_pin));
        let ref mut g_led_pin = G_LED_PIN.borrow(cs).borrow_mut();
        if let Some(led_pin) = g_led_pin.as_mut() {
            // set led on for start --- this works
            led_pin.set_high().unwrap();
            G_IS_LED_HIGH.store(true, Ordering::Release);
        }
    });

    // schedule first timer interrupt after half second
    alarm0.schedule(500_000.microseconds()).unwrap();
    alarm0.enable_interrupt(&mut timer);

    // loop and set timer interrupts to switch led on and off
    // led on after 1.5 seconds and off after 0.5 seconds 
    loop {
        if alarm0.finished() {
            if G_IS_LED_HIGH.load(Ordering::Acquire) {
                alarm0.schedule(500_000.microseconds()).unwrap();
            } else {
                alarm0.schedule(1_500_000.microseconds()).unwrap();
            }
            alarm0.enable_interrupt(&mut timer);
        }
    }
}

#[interrupt]
fn TIMER_IRQ_0() {
    static mut LED: Option<LEDPinType> = None;

    if LED.is_none() {
        cortex_m::interrupt::free(|cs| {
            *LED = G_LED_PIN.borrow(&cs).take();
        });
    }

    // switch led
    if let Some(led) = LED {
        let is_high = G_IS_LED_HIGH.load(Ordering::Acquire);
        if is_high {
            led.set_low().unwrap();
        } else {
            led.set_high().unwrap();
        }
        G_IS_LED_HIGH.store(!is_high, Ordering::Release);
    }
}

Some rework with help from matrix:rp-rs ...
Now the sample is running.

#![no_std]
#![no_main]
#![deny(clippy::all)]
#![deny(unsafe_code)]
#![deny(warnings)]

use core::{
    cell::RefCell,
    sync::atomic::{AtomicBool, Ordering},
};
use cortex_m::interrupt::Mutex;
use embedded_hal::digital::v2::OutputPin;
use embedded_time::duration::Extensions;
use panic_halt as _;
use rp_pico::{
    entry,
    hal::{
        self,
        gpio::{bank0::Gpio25, Output, Pin, PushPull},
        timer::Alarm0,
    },
    pac::{self, interrupt},
};

type LEDPinType = Pin<Gpio25, Output<PushPull>>;

static G_ALARM0: Mutex<RefCell<Option<Alarm0>>> = Mutex::new(RefCell::new(None));
static G_LED_PIN: Mutex<RefCell<Option<LEDPinType>>> = Mutex::new(RefCell::new(None));
static G_IS_LED_HIGH: AtomicBool = AtomicBool::new(false);
static G_TIMER: Mutex<RefCell<Option<hal::Timer>>> = Mutex::new(RefCell::new(None));

#[entry]
fn main() -> ! {
    // Grab our singleton objects
    let mut peripherals = pac::Peripherals::take().unwrap();
    // let core = pac::CorePeripherals::take().unwrap();

    // Set up the watchdog driver - needed by the clock setup code
    let mut watchdog = hal::Watchdog::new(peripherals.WATCHDOG);

    // Configure the clocks
    //
    // The default is to generate a 125 MHz system clock
    let _clocks = hal::clocks::init_clocks_and_plls(
        rp_pico::XOSC_CRYSTAL_FREQ,
        peripherals.XOSC,
        peripherals.CLOCKS,
        peripherals.PLL_SYS,
        peripherals.PLL_USB,
        &mut peripherals.RESETS,
        &mut watchdog,
    )
    .ok()
    .unwrap();

    // Alarm timer
    let mut timer = hal::Timer::new(peripherals.TIMER, &mut peripherals.RESETS);
    let alarm0 = timer.alarm_0().unwrap();

    // The single-cycle I/O block controls our GPIO pins
    let sio = hal::Sio::new(peripherals.SIO);

    // Set the pins up according to their function on this particular board
    let pins = rp_pico::Pins::new(
        peripherals.IO_BANK0,
        peripherals.PADS_BANK0,
        sio.gpio_bank0,
        &mut peripherals.RESETS,
    );

    // Set the LED to be an output
    let led_pin = pins.led.into_push_pull_output();

    // Make led_pin global static for usage in interrupt handler
    cortex_m::interrupt::free(|cs| {
        G_ALARM0.borrow(cs).replace(Some(alarm0));
        G_LED_PIN.borrow(cs).replace(Some(led_pin));
        G_TIMER.borrow(cs).replace(Some(timer));

        let ref mut g_alarm0 = G_ALARM0.borrow(cs).borrow_mut();
        if let Some(alarm0) = g_alarm0.as_mut() {
            let ref mut g_timer = G_TIMER.borrow(cs).borrow_mut();
            if let Some(timer) = g_timer.as_mut() {
                // schedule first timer interrupt after half second
                alarm0.schedule(500_000.microseconds()).unwrap();
                alarm0.enable_interrupt(timer);
            }
        }

        let ref mut g_led_pin = G_LED_PIN.borrow(cs).borrow_mut();
        if let Some(led_pin) = g_led_pin.as_mut() {
            // set led on for start
            led_pin.set_high().unwrap();
            G_IS_LED_HIGH.store(true, Ordering::Release);
        }
    });

    #[allow(unsafe_code)]
    unsafe {
        pac::NVIC::unmask(pac::Interrupt::TIMER_IRQ_0);
    }

    // loop and set timer interrupts to switch led on and off
    // led on after 1.5 seconds and off after 0.5 seconds
    loop {
        let mut is_alarm_finished = false;
        cortex_m::interrupt::free(|cs| {
            let ref mut g_alarm0 = G_ALARM0.borrow(cs).borrow_mut();
            if let Some(alarm0) = g_alarm0.as_mut() {
                is_alarm_finished = alarm0.finished();
            }
        });

        if is_alarm_finished {
            cortex_m::interrupt::free(|cs| {
                let ref mut g_alarm0 = G_ALARM0.borrow(cs).borrow_mut();
                if let Some(alarm0) = g_alarm0.as_mut() {
                    let ref mut g_timer = G_TIMER.borrow(cs).borrow_mut();
                    if let Some(timer) = g_timer.as_mut() {
                        if G_IS_LED_HIGH.load(Ordering::Acquire) {
                            alarm0.schedule(500_000.microseconds()).unwrap();
                        } else {
                            alarm0.schedule(1_500_000.microseconds()).unwrap();
                        }
                        alarm0.enable_interrupt(timer);
                    }
                }
            });
        }
    }
}

#[interrupt]
fn TIMER_IRQ_0() {
    static mut LED: Option<LEDPinType> = None;

    if LED.is_none() {
        cortex_m::interrupt::free(|cs| {
            *LED = G_LED_PIN.borrow(&cs).take();
        });
    }

    // switch led
    if let Some(led) = LED {
        let is_high = G_IS_LED_HIGH.load(Ordering::Acquire);
        if is_high {
            led.set_low().unwrap();
        } else {
            led.set_high().unwrap();
        }
        G_IS_LED_HIGH.store(!is_high, Ordering::Release);
    }

    cortex_m::interrupt::free(|cs| {
        let ref mut g_alarm0 = G_ALARM0.borrow(cs).borrow_mut();
        if let Some(alarm0) = g_alarm0.as_mut() {
            let ref mut g_timer = G_TIMER.borrow(cs).borrow_mut();
            if let Some(timer) = g_timer.as_mut() {
                alarm0.clear_interrupt(timer);
            }
        }
    });
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.