Interrupts on single-core
Let’s try with a single-core example. See what happens when you make GPIO go from high to low (e.g. use a button) or alternatively change the code to put the GPIO in output mode and make it go from high to low yourself.
#![no_std]
#![no_main]
use cortex_m::{
asm, interrupt::InterruptNumber,
peripheral::NVIC,
};
pub use cortex_m_rt::entry;
use defmt::info;
use rp235x_hal as _;
use {defmt_rtt as _, panic_probe as _};
#[unsafe(link_section = ".start_block")]
#[unsafe(no_mangle)]
static BOOT_ROM_INFO: [u8; 44] = [
0xd3, 0xde, 0xff, 0xff, 0x42, 0x01, 0x21,
0x10, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x79, 0x35, 0x12, 0xab, 0xf2,
0xeb, 0x88, 0x71, 0x6c, 0x93, 0x02, 0x10,
0x7c, 0x93, 0x02, 0x10, 0x70, 0xf6, 0x02,
0x10, 0x90, 0xa3, 0x1a, 0xe7, 0x1f, 0x01,
0x02, 0x03,
];
mod interrupt {
pub const IO_IRQ_BANK0: isize = 21;
}
#[derive(Clone, Copy)]
struct Interrupt;
unsafe impl InterruptNumber for Interrupt {
fn number(self) -> u16 {
21
}
}
#[cortex_m_rt_macros::interrupt]
fn IO_IRQ_BANK0() {
info!("Hello from interrupt!");
unsafe {
// IO_BANK0: INTR2 Register
// 3 GPIO16_EDGE_HIGH WC 0x0
// 2 GPIO16_EDGE_LOW WC 0x0
// 1 GPIO16_LEVEL_HIGH RO 0x0
// 0 GPIO16_LEVEL_LOW RO 0x0
core::ptr::write_volatile(
0x40028238 as *mut u32,
1 << 2 | 1 << 3,
);
}
for _ in 1..10000 {
asm::nop();
}
}
#[entry]
fn main() -> ! {
unsafe {
for _ in 1..10000 {
asm::nop();
}
// this would call the interrupt handler
NVIC::pend(Interrupt);
// if comment out this line, the interrupt handler will be
// called immediately after unmasking
NVIC::unpend(Interrupt);
info!("unmasking");
NVIC::unmask(Interrupt);
// now this will call the interrupt once
info!("pending");
NVIC::pend(Interrupt);
// IO_BANK0: GPIO16_CTRL Register
// Set to use SIO
core::ptr::write_volatile(
0x40028084 as *mut u32,
0x5,
);
// GPIO_OE_CLEAR
// 0x10000: enable output for bit 16 (pin 16)
core::ptr::write_volatile(
0xd0000040 as *mut u32,
1 << 16,
);
// PADS_BANK0: GPIO16 Register
// 0x48: set bit 6 (IE: Input enable) and bit 3 (PUE: Pull up enable)
core::ptr::write_volatile(
0x40038044 as *mut u32,
1 << 6 | 1 << 3,
);
info!("in input mode");
// IO_BANK0: PROC0_INTE2 Register
// Interrupt Enable for processor 0
// Bit 3: GPIO16_EDGE_HIGH
// Bit 2: GPIO16_EDGE_LOW
// Bit 1: GPIO16_LEVEL_HIGH
// Bit 0: GPIO16_LEVEL_LOW
info!("will enable interrupt now");
core::ptr::write_volatile(
0x40028250 as *mut u32,
1 << 2,
);
};
status();
loop {
unsafe {
info!(
"{:#x} GPIO_IN",
core::ptr::read_volatile(
0xd0000004 as *const u32
)
);
}
for _ in 1..100000 {
asm::nop();
}
}
}
fn status() {
unsafe {
info!(
"{:#x} IO_BANK0: GPIO16_STATUS Register",
core::ptr::read_volatile(
0x40028080 as *const u32
)
);
info!(
"{:#x} IO_BANK0: GPIO16_CTRL Register",
core::ptr::read_volatile(
0x40028084 as *const u32
)
);
info!(
"{:#x} GPIO_OUT",
core::ptr::read_volatile(
0xd0000010 as *const u32
)
);
info!(
"{:#x} GPIO_OE",
core::ptr::read_volatile(
0xd0000030 as *const u32
)
);
info!(
"{:#x} PADS_BANK0: GPIO16 Register",
core::ptr::read_volatile(
0x40038044 as *const u32
)
);
}
}
Cargo.toml changes
To make this work, we had again to make some changes in our Cargo.toml:
[package]
name = "pico-simple"
version = "0.1.0"
edition = "2024"
[dependencies]
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m-rt = { version = "0.7.0", features = ["device"] }
cortex-m-rt-macros = "0.7.5"
panic-probe = { version = "1.0.0", features = ["print-defmt"] }
defmt = "1.0.1"
defmt-rtt = "1.0.0"
rp235x-hal = "0.4.0"
We don’t need the multi-core critical section anymore as again running on single-core, but on the other hand we had to enable the device feature of cortex-m-rt and again needed to use the rp235x-hal crate. The reason for that is that the pointer to the function that is our interrupt handle must be stored at cortex-m-rt
If you try to use the Cargo.toml like it was in the previous sections, then the code won’t go our desired interrupt handler, but rather to a default one, that doesn’t clear the GPIO16_EDGE_LOW, so it will be stuck calling the interrupt handler again and again.