Interrupts on alarms
Now let’s see an example of using the Pico to interrupt on a timer alarm:
#![no_std]
#![no_main]
mod aux;
use aux::{blink_led, setup_xosc_on_clks};
use cortex_m::{asm, interrupt::InterruptNumber, peripheral::NVIC};
pub use cortex_m_rt::entry;
use defmt::info;
use crate::aux::start_second_cpu;
mod interrupt {
pub const TIMER0_IRQ_0: isize = 0;
pub const TIMER0_IRQ_1: isize = 1;
}
#[derive(Clone, Copy)]
struct Interrupt0;
unsafe impl InterruptNumber for Interrupt0 {
fn number(self) -> u16 {
0
}
}
#[derive(Clone, Copy)]
struct Interrupt1;
unsafe impl InterruptNumber for Interrupt1 {
fn number(self) -> u16 {
1
}
}
#[cortex_m_rt_macros::interrupt]
fn TIMER0_IRQ_0() {
unsafe {
info!(
"Hello from interrupt TIMER0_IRQ_0 at CPU {}!",
// SIO: CPUID Register
core::ptr::read_volatile(0xd0000000 as *const u32)
);
// TIMER0: INTR Register
// Clear interrupt
core::ptr::write_volatile((0x400b003c + 0x3000) as *mut u32, 1);
// Will fire the interrupt for ALARM1
// (which is unmasked on CPU0)
alarmer(3_000_000, 1);
}
}
#[cortex_m_rt_macros::interrupt]
fn TIMER0_IRQ_1() {
unsafe {
info!(
"Hello from interrupt TIMER0_IRQ_1 at CPU {}!",
// SIO: CPUID Register
core::ptr::read_volatile(0xd0000000 as *const u32)
);
// TIMER0: INTR Register
// Clear interrupt
core::ptr::write_volatile((0x400b003c + 0x3000) as *mut u32, 2);
// Will fire the interrupt for ALARM0
// (which is unmasked on CPU1)
alarmer(1_000_000, 0);
}
}
fn second_cpu_entry_point() -> ! {
unsafe {
NVIC::unmask(Interrupt0);
}
loop {
asm::wfi();
}
}
#[entry]
fn main() -> ! {
unsafe {
// GPIO 16 to visually signal board startup to us
blink_led();
setup_xosc_on_clks();
start_second_cpu(second_cpu_entry_point);
NVIC::unmask(Interrupt1);
// TICKS: TIMER0_CTRL Register
core::ptr::write_volatile(0x40108018 as *mut u32, 1);
// TICKS: TIMER0_CYCLES Register
// A divider that must result in a 1MHz clock.
// If using the XOSC of reference board which 12MHz
// this needs to be 12.
core::ptr::write_volatile(0x4010801c as *mut u32, 12);
// TIMER0: INTE Register
// Enable interrupts ALARM0 and ALARM1
// for TIMER0
core::ptr::write_volatile(0x400b0040 as *mut u32, 0b11);
// Will fire the interrupt for ALARM0
// (which is unmasked on CPU1)
alarmer(1_000_000, 0);
};
loop {
asm::wfi();
}
}
unsafe fn alarmer(to_add: u32, alarm_id: u32) {
if alarm_id > 3 {
panic!()
}
unsafe {
// TIMER: PAUSE Register
// Pause timer
core::ptr::write_volatile(0x400b0030 as *mut u32, 1);
let firing_when = core::ptr::read_volatile(0x400b000c as *const u32);
let firing_when = firing_when.wrapping_add(to_add);
// TIMER0: ALARMx Register
core::ptr::write_volatile(
(0x400b0010 + alarm_id * 4) as *mut u32,
firing_when,
);
// TIMER: PAUSE Register
// Unpause timer
core::ptr::write_volatile(0x400b0030 as *mut u32, 0);
}
}