Make interrupt module more standard.

- Move typelevel interrupts to a special-purpose mod: `embassy_xx::interrupt::typelevel`.
- Reexport the PAC interrupt enum in `embassy_xx::interrupt`.

This has a few advantages:
- The `embassy_xx::interrupt` module is now more "standard".
  - It works with `cortex-m` functions for manipulating interrupts, for example.
  - It works with RTIC.
- the interrupt enum allows holding value that can be "any interrupt at runtime", this can't be done with typelevel irqs.
- When "const-generics on enums" is stable, we can remove the typelevel interrupts without disruptive changes to `embassy_xx::interrupt`.
This commit is contained in:
Dario Nieuwenhuis
2023-06-08 16:08:40 +02:00
parent 87ad66f2b4
commit 921780e6bf
72 changed files with 845 additions and 930 deletions

View File

@ -3,14 +3,14 @@ use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use embassy_cortex_m::interrupt::{Binding, Interrupt};
use embassy_sync::waitqueue::AtomicWaker;
use embedded_hal_02::adc::{Channel, OneShot};
use crate::gpio::Pin;
use crate::interrupt::{self, ADC_IRQ_FIFO};
use crate::interrupt::typelevel::Binding;
use crate::interrupt::InterruptExt;
use crate::peripherals::ADC;
use crate::{pac, peripherals, Peripheral};
use crate::{interrupt, pac, peripherals, Peripheral};
static WAKER: AtomicWaker = AtomicWaker::new();
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -47,7 +47,7 @@ impl<'d> Adc<'d> {
pub fn new(
_inner: impl Peripheral<P = ADC> + 'd,
_irq: impl Binding<ADC_IRQ_FIFO, InterruptHandler>,
_irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>,
_config: Config,
) -> Self {
unsafe {
@ -62,10 +62,8 @@ impl<'d> Adc<'d> {
}
// Setup IRQ
unsafe {
ADC_IRQ_FIFO::unpend();
ADC_IRQ_FIFO::enable();
};
interrupt::ADC_IRQ_FIFO.unpend();
unsafe { interrupt::ADC_IRQ_FIFO.enable() };
Self { phantom: PhantomData }
}
@ -164,7 +162,7 @@ pub struct InterruptHandler {
_empty: (),
}
impl interrupt::Handler<ADC_IRQ_FIFO> for InterruptHandler {
impl interrupt::typelevel::Handler<interrupt::typelevel::ADC_IRQ_FIFO> for InterruptHandler {
unsafe fn on_interrupt() {
let r = Adc::regs();
r.inte().write(|w| w.set_fifo(false));

View File

@ -4,11 +4,11 @@ use core::pin::Pin;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::{Context, Poll};
use embassy_cortex_m::interrupt::Interrupt;
use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
use pac::dma::vals::DataSize;
use crate::interrupt::InterruptExt;
use crate::pac::dma::vals;
use crate::{interrupt, pac, peripherals};
@ -29,12 +29,12 @@ unsafe fn DMA_IRQ_0() {
}
pub(crate) unsafe fn init() {
interrupt::DMA_IRQ_0::disable();
interrupt::DMA_IRQ_0::set_priority(interrupt::Priority::P3);
interrupt::DMA_IRQ_0.disable();
interrupt::DMA_IRQ_0.set_priority(interrupt::Priority::P3);
pac::DMA.inte0().write(|w| w.set_inte0(0xFFFF));
interrupt::DMA_IRQ_0::enable();
interrupt::DMA_IRQ_0.enable();
}
pub unsafe fn read<'a, C: Channel, W: Word>(

View File

@ -3,10 +3,10 @@ use core::future::Future;
use core::pin::Pin as FuturePin;
use core::task::{Context, Poll};
use embassy_cortex_m::interrupt::Interrupt;
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
use crate::interrupt::InterruptExt;
use crate::pac::common::{Reg, RW};
use crate::pac::SIO;
use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
@ -137,9 +137,9 @@ pub enum InterruptTrigger {
}
pub(crate) unsafe fn init() {
interrupt::IO_IRQ_BANK0::disable();
interrupt::IO_IRQ_BANK0::set_priority(interrupt::Priority::P3);
interrupt::IO_IRQ_BANK0::enable();
interrupt::IO_IRQ_BANK0.disable();
interrupt::IO_IRQ_BANK0.set_priority(interrupt::Priority::P3);
interrupt::IO_IRQ_BANK0.enable();
}
#[interrupt]

View File

@ -2,14 +2,14 @@ use core::future;
use core::marker::PhantomData;
use core::task::Poll;
use embassy_cortex_m::interrupt::{self, Binding, Interrupt};
use embassy_hal_common::{into_ref, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
use pac::i2c;
use crate::gpio::sealed::Pin;
use crate::gpio::AnyPin;
use crate::{pac, peripherals, Peripheral};
use crate::interrupt::typelevel::{Binding, Interrupt};
use crate::{interrupt, pac, peripherals, Peripheral};
/// I2C error abort reason
#[derive(Debug)]
@ -312,7 +312,7 @@ pub struct InterruptHandler<T: Instance> {
_uart: PhantomData<T>,
}
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
// Mask interrupts and wake any task waiting for this interrupt
unsafe fn on_interrupt() {
let i2c = T::regs();
@ -760,14 +760,15 @@ fn i2c_reserved_addr(addr: u16) -> bool {
}
mod sealed {
use embassy_cortex_m::interrupt::Interrupt;
use embassy_sync::waitqueue::AtomicWaker;
use crate::interrupt;
pub trait Instance {
const TX_DREQ: u8;
const RX_DREQ: u8;
type Interrupt: Interrupt;
type Interrupt: interrupt::typelevel::Interrupt;
fn regs() -> crate::pac::i2c::I2c;
fn reset() -> crate::pac::resets::regs::Peripherals;
@ -803,7 +804,7 @@ macro_rules! impl_instance {
const TX_DREQ: u8 = $tx_dreq;
const RX_DREQ: u8 = $rx_dreq;
type Interrupt = crate::interrupt::$irq;
type Interrupt = crate::interrupt::typelevel::$irq;
#[inline]
fn regs() -> pac::i2c::I2c {

View File

@ -1,65 +0,0 @@
//! Interrupt definitions and macros to bind them.
pub use cortex_m::interrupt::{CriticalSection, Mutex};
use embassy_cortex_m::interrupt::_export::declare;
pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, Priority};
use crate::pac::Interrupt as InterruptEnum;
declare!(TIMER_IRQ_0);
declare!(TIMER_IRQ_1);
declare!(TIMER_IRQ_2);
declare!(TIMER_IRQ_3);
declare!(PWM_IRQ_WRAP);
declare!(USBCTRL_IRQ);
declare!(XIP_IRQ);
declare!(PIO0_IRQ_0);
declare!(PIO0_IRQ_1);
declare!(PIO1_IRQ_0);
declare!(PIO1_IRQ_1);
declare!(DMA_IRQ_0);
declare!(DMA_IRQ_1);
declare!(IO_IRQ_BANK0);
declare!(IO_IRQ_QSPI);
declare!(SIO_IRQ_PROC0);
declare!(SIO_IRQ_PROC1);
declare!(CLOCKS_IRQ);
declare!(SPI0_IRQ);
declare!(SPI1_IRQ);
declare!(UART0_IRQ);
declare!(UART1_IRQ);
declare!(ADC_IRQ_FIFO);
declare!(I2C0_IRQ);
declare!(I2C1_IRQ);
declare!(RTC_IRQ);
declare!(SWI_IRQ_0);
declare!(SWI_IRQ_1);
declare!(SWI_IRQ_2);
declare!(SWI_IRQ_3);
declare!(SWI_IRQ_4);
declare!(SWI_IRQ_5);
/// Macro to bind interrupts to handlers.
///
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
/// prove at compile-time that the right interrupts have been bound.
// developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`.
#[macro_export]
macro_rules! bind_interrupts {
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
$vis struct $name;
$(
#[allow(non_snake_case)]
#[no_mangle]
unsafe extern "C" fn $irq() {
$(
<$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt();
)*
}
$(
unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {}
)*
)*
};
}

View File

@ -16,7 +16,6 @@ pub mod flash;
mod float;
pub mod gpio;
pub mod i2c;
pub mod interrupt;
pub mod multicore;
pub mod pwm;
mod reset;
@ -38,13 +37,74 @@ pub mod relocate;
// Reexports
pub use embassy_cortex_m::executor;
pub use embassy_cortex_m::interrupt::_export::interrupt;
pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
#[cfg(feature = "unstable-pac")]
pub use rp_pac as pac;
#[cfg(not(feature = "unstable-pac"))]
pub(crate) use rp_pac as pac;
embassy_cortex_m::interrupt_mod!(
TIMER_IRQ_0,
TIMER_IRQ_1,
TIMER_IRQ_2,
TIMER_IRQ_3,
PWM_IRQ_WRAP,
USBCTRL_IRQ,
XIP_IRQ,
PIO0_IRQ_0,
PIO0_IRQ_1,
PIO1_IRQ_0,
PIO1_IRQ_1,
DMA_IRQ_0,
DMA_IRQ_1,
IO_IRQ_BANK0,
IO_IRQ_QSPI,
SIO_IRQ_PROC0,
SIO_IRQ_PROC1,
CLOCKS_IRQ,
SPI0_IRQ,
SPI1_IRQ,
UART0_IRQ,
UART1_IRQ,
ADC_IRQ_FIFO,
I2C0_IRQ,
I2C1_IRQ,
RTC_IRQ,
SWI_IRQ_0,
SWI_IRQ_1,
SWI_IRQ_2,
SWI_IRQ_3,
SWI_IRQ_4,
SWI_IRQ_5,
);
/// Macro to bind interrupts to handlers.
///
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
/// prove at compile-time that the right interrupts have been bound.
// developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`.
#[macro_export]
macro_rules! bind_interrupts {
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
$vis struct $name;
$(
#[allow(non_snake_case)]
#[no_mangle]
unsafe extern "C" fn $irq() {
$(
<$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
)*
}
$(
unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
)*
)*
};
}
embassy_hal_common::peripherals! {
PIN_0,
PIN_1,

View File

@ -50,7 +50,7 @@
use core::mem::ManuallyDrop;
use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
use crate::interrupt::Interrupt;
use crate::interrupt::InterruptExt;
use crate::peripherals::CORE1;
use crate::{gpio, interrupt, pac};
@ -156,7 +156,7 @@ where
IS_CORE1_INIT.store(true, Ordering::Release);
// Enable fifo interrupt on CORE1 for `pause` functionality.
unsafe { interrupt::SIO_IRQ_PROC1::enable() };
unsafe { interrupt::SIO_IRQ_PROC1.enable() };
entry()
}

View File

@ -5,7 +5,6 @@ use core::sync::atomic::{compiler_fence, Ordering};
use core::task::{Context, Poll};
use atomic_polyfill::{AtomicU32, AtomicU8};
use embassy_cortex_m::interrupt::Interrupt;
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
use fixed::types::extra::U8;
@ -17,6 +16,7 @@ use pio::{SideSet, Wrap};
use crate::dma::{Channel, Transfer, Word};
use crate::gpio::sealed::Pin as SealedPin;
use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate};
use crate::interrupt::InterruptExt;
use crate::pac::dma::vals::TreqSel;
use crate::relocate::RelocatedProgram;
use crate::{interrupt, pac, peripherals, pio_instr_util, RegExt};
@ -110,15 +110,15 @@ unsafe fn PIO1_IRQ_0() {
}
pub(crate) unsafe fn init() {
interrupt::PIO0_IRQ_0::disable();
interrupt::PIO0_IRQ_0::set_priority(interrupt::Priority::P3);
interrupt::PIO0_IRQ_0.disable();
interrupt::PIO0_IRQ_0.set_priority(interrupt::Priority::P3);
pac::PIO0.irqs(0).inte().write(|m| m.0 = 0);
interrupt::PIO0_IRQ_0::enable();
interrupt::PIO0_IRQ_0.enable();
interrupt::PIO1_IRQ_0::disable();
interrupt::PIO1_IRQ_0::set_priority(interrupt::Priority::P3);
interrupt::PIO1_IRQ_0.disable();
interrupt::PIO1_IRQ_0.set_priority(interrupt::Priority::P3);
pac::PIO1.irqs(0).inte().write(|m| m.0 = 0);
interrupt::PIO1_IRQ_0::enable();
interrupt::PIO1_IRQ_0.enable();
}
/// Future that waits for TX-FIFO to become writable

View File

@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::blocking_mutex::Mutex;
use embassy_time::driver::{AlarmHandle, Driver};
use crate::interrupt::Interrupt;
use crate::interrupt::InterruptExt;
use crate::{interrupt, pac};
struct AlarmState {
@ -145,10 +145,10 @@ pub unsafe fn init() {
w.set_alarm(2, true);
w.set_alarm(3, true);
});
interrupt::TIMER_IRQ_0::enable();
interrupt::TIMER_IRQ_1::enable();
interrupt::TIMER_IRQ_2::enable();
interrupt::TIMER_IRQ_3::enable();
interrupt::TIMER_IRQ_0.enable();
interrupt::TIMER_IRQ_1.enable();
interrupt::TIMER_IRQ_2.enable();
interrupt::TIMER_IRQ_3.enable();
}
#[interrupt]

View File

@ -3,14 +3,14 @@ use core::slice;
use core::task::Poll;
use atomic_polyfill::{AtomicU8, Ordering};
use embassy_cortex_m::interrupt::{self, Binding, Interrupt};
use embassy_hal_common::atomic_ring_buffer::RingBuffer;
use embassy_sync::waitqueue::AtomicWaker;
use embassy_time::{Duration, Timer};
use super::*;
use crate::clocks::clk_peri_freq;
use crate::RegExt;
use crate::interrupt::typelevel::{Binding, Interrupt};
use crate::{interrupt, RegExt};
pub struct State {
tx_waker: AtomicWaker,
@ -485,7 +485,7 @@ pub struct BufferedInterruptHandler<T: Instance> {
_uart: PhantomData<T>,
}
impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
unsafe fn on_interrupt() {
let r = T::regs();
if r.uartdmacr().read().rxdmae() {

View File

@ -3,7 +3,6 @@ use core::marker::PhantomData;
use core::task::Poll;
use atomic_polyfill::{AtomicU16, Ordering};
use embassy_cortex_m::interrupt::{self, Binding, Interrupt};
use embassy_futures::select::{select, Either};
use embassy_hal_common::{into_ref, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
@ -14,8 +13,9 @@ use crate::clocks::clk_peri_freq;
use crate::dma::{AnyChannel, Channel};
use crate::gpio::sealed::Pin;
use crate::gpio::AnyPin;
use crate::interrupt::typelevel::{Binding, Interrupt};
use crate::pac::io::vals::{Inover, Outover};
use crate::{pac, peripherals, Peripheral, RegExt};
use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
#[cfg(feature = "nightly")]
mod buffered;
@ -332,7 +332,7 @@ pub struct InterruptHandler<T: Instance> {
_uart: PhantomData<T>,
}
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let uart = T::regs();
if !uart.uartdmacr().read().rxdmae() {
@ -930,7 +930,7 @@ mod sealed {
const TX_DREQ: u8;
const RX_DREQ: u8;
type Interrupt: crate::interrupt::Interrupt;
type Interrupt: interrupt::typelevel::Interrupt;
fn regs() -> pac::uart::Uart;
@ -968,7 +968,7 @@ macro_rules! impl_instance {
const TX_DREQ: u8 = $tx_dreq;
const RX_DREQ: u8 = $rx_dreq;
type Interrupt = crate::interrupt::$irq;
type Interrupt = crate::interrupt::typelevel::$irq;
fn regs() -> pac::uart::Uart {
pac::$inst

View File

@ -4,15 +4,14 @@ use core::slice;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use embassy_cortex_m::interrupt::{self, Binding};
use embassy_sync::waitqueue::AtomicWaker;
use embassy_usb_driver as driver;
use embassy_usb_driver::{
Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
};
use crate::interrupt::Interrupt;
use crate::{pac, peripherals, Peripheral, RegExt};
use crate::interrupt::typelevel::{Binding, Interrupt};
use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
pub(crate) mod sealed {
pub trait Instance {
@ -22,7 +21,7 @@ pub(crate) mod sealed {
}
pub trait Instance: sealed::Instance + 'static {
type Interrupt: Interrupt;
type Interrupt: interrupt::typelevel::Interrupt;
}
impl crate::usb::sealed::Instance for peripherals::USB {
@ -35,7 +34,7 @@ impl crate::usb::sealed::Instance for peripherals::USB {
}
impl crate::usb::Instance for peripherals::USB {
type Interrupt = crate::interrupt::USBCTRL_IRQ;
type Interrupt = crate::interrupt::typelevel::USBCTRL_IRQ;
}
const EP_COUNT: usize = 16;
@ -249,7 +248,7 @@ pub struct InterruptHandler<T: Instance> {
_uart: PhantomData<T>,
}
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let regs = T::regs();
//let x = regs.istr().read().0;