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);
}
}