//! Interrupt handling for cortex-m devices. use core::mem; use core::sync::atomic::{compiler_fence, Ordering}; use cortex_m::interrupt::InterruptNumber; use cortex_m::peripheral::NVIC; use critical_section::CriticalSection; /// Generate a standard `mod interrupt` for a HAL. #[macro_export] macro_rules! interrupt_mod { ($($irqs:ident),* $(,)?) => { #[cfg(feature = "rt")] pub use cortex_m_rt::interrupt; /// Interrupt definitions. pub mod interrupt { pub use $crate::interrupt::{InterruptExt, Priority}; pub use crate::pac::Interrupt::*; pub use crate::pac::Interrupt; /// Type-level interrupt infrastructure. /// /// This module contains one *type* per interrupt. This is used for checking at compile time that /// the interrupts are correctly bound to HAL drivers. /// /// As an end user, you shouldn't need to use this module directly. Use the [`crate::bind_interrupts!`] macro /// to bind interrupts, and the [`crate::interrupt`] module to manually register interrupt handlers and manipulate /// interrupts directly (pending/unpending, enabling/disabling, setting the priority, etc...) pub mod typelevel { use super::InterruptExt; mod sealed { pub trait Interrupt {} } /// Type-level interrupt. /// /// This trait is implemented for all typelevel interrupt types in this module. pub trait Interrupt: sealed::Interrupt { /// Interrupt enum variant. /// /// This allows going from typelevel interrupts (one type per interrupt) to /// non-typelevel interrupts (a single `Interrupt` enum type, with one variant per interrupt). const IRQ: super::Interrupt; /// Enable the interrupt. #[inline] unsafe fn enable() { Self::IRQ.enable() } /// Disable the interrupt. #[inline] fn disable() { Self::IRQ.disable() } /// Check if interrupt is enabled. #[inline] fn is_enabled() -> bool { Self::IRQ.is_enabled() } /// Check if interrupt is pending. #[inline] fn is_pending() -> bool { Self::IRQ.is_pending() } /// Set interrupt pending. #[inline] fn pend() { Self::IRQ.pend() } /// Unset interrupt pending. #[inline] fn unpend() { Self::IRQ.unpend() } /// Get the priority of the interrupt. #[inline] fn get_priority() -> crate::interrupt::Priority { Self::IRQ.get_priority() } /// Set the interrupt priority. #[inline] fn set_priority(prio: crate::interrupt::Priority) { Self::IRQ.set_priority(prio) } /// Set the interrupt priority with an already-acquired critical section #[inline] fn set_priority_with_cs(cs: critical_section::CriticalSection, prio: crate::interrupt::Priority) { Self::IRQ.set_priority_with_cs(cs, prio) } } $( #[allow(non_camel_case_types)] #[doc=stringify!($irqs)] #[doc=" typelevel interrupt."] pub enum $irqs {} impl sealed::Interrupt for $irqs{} impl Interrupt for $irqs { const IRQ: super::Interrupt = super::Interrupt::$irqs; } )* /// Interrupt handler trait. /// /// Drivers that need to handle interrupts implement this trait. /// The user must ensure `on_interrupt()` is called every time the interrupt fires. /// Drivers must use use [`Binding`] to assert at compile time that the user has done so. pub trait Handler { /// Interrupt handler function. /// /// Must be called every time the `I` interrupt fires, synchronously from /// the interrupt handler context. /// /// # Safety /// /// This function must ONLY be called from the interrupt handler for `I`. unsafe fn on_interrupt(); } /// Compile-time assertion that an interrupt has been bound to a handler. /// /// For the vast majority of cases, you should use the `bind_interrupts!` /// macro instead of writing `unsafe impl`s of this trait. /// /// # Safety /// /// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()` /// to be called every time the `I` interrupt fires. /// /// This allows drivers to check bindings at compile-time. pub unsafe trait Binding> {} } } }; } /// Represents an interrupt type that can be configured by embassy to handle /// interrupts. pub unsafe trait InterruptExt: InterruptNumber + Copy { /// Enable the interrupt. #[inline] unsafe fn enable(self) { compiler_fence(Ordering::SeqCst); NVIC::unmask(self) } /// Disable the interrupt. #[inline] fn disable(self) { NVIC::mask(self); compiler_fence(Ordering::SeqCst); } /// Check if interrupt is being handled. #[inline] #[cfg(not(armv6m))] fn is_active(self) -> bool { NVIC::is_active(self) } /// Check if interrupt is enabled. #[inline] fn is_enabled(self) -> bool { NVIC::is_enabled(self) } /// Check if interrupt is pending. #[inline] fn is_pending(self) -> bool { NVIC::is_pending(self) } /// Set interrupt pending. #[inline] fn pend(self) { NVIC::pend(self) } /// Unset interrupt pending. #[inline] fn unpend(self) { NVIC::unpend(self) } /// Get the priority of the interrupt. #[inline] fn get_priority(self) -> Priority { Priority::from(NVIC::get_priority(self)) } /// Set the interrupt priority. #[inline] fn set_priority(self, prio: Priority) { unsafe { let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(()); // On thumbv6, set_priority must do a RMW to change 8bit in a 32bit reg. #[cfg(armv6m)] critical_section::with(|_| nvic.set_priority(self, prio.into())); // On thumbv7+, set_priority does an atomic 8bit write, so no CS needed. #[cfg(not(armv6m))] nvic.set_priority(self, prio.into()); } } /// Set the interrupt priority with an already-acquired critical section /// /// Equivalent to `set_priority`, except you pass a `CriticalSection` to prove /// you've already acquired a critical section. This prevents acquiring another /// one, which saves code size. #[inline] fn set_priority_with_cs(self, _cs: CriticalSection, prio: Priority) { unsafe { let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(()); nvic.set_priority(self, prio.into()); } } } unsafe impl InterruptExt for T {} impl From for Priority { fn from(priority: u8) -> Self { unsafe { mem::transmute(priority & PRIO_MASK) } } } impl From for u8 { fn from(p: Priority) -> Self { p as u8 } } #[cfg(feature = "prio-bits-0")] const PRIO_MASK: u8 = 0x00; #[cfg(feature = "prio-bits-1")] const PRIO_MASK: u8 = 0x80; #[cfg(feature = "prio-bits-2")] const PRIO_MASK: u8 = 0xc0; #[cfg(feature = "prio-bits-3")] const PRIO_MASK: u8 = 0xe0; #[cfg(feature = "prio-bits-4")] const PRIO_MASK: u8 = 0xf0; #[cfg(feature = "prio-bits-5")] const PRIO_MASK: u8 = 0xf8; #[cfg(feature = "prio-bits-6")] const PRIO_MASK: u8 = 0xfc; #[cfg(feature = "prio-bits-7")] const PRIO_MASK: u8 = 0xfe; #[cfg(feature = "prio-bits-8")] const PRIO_MASK: u8 = 0xff; /// The interrupt priority level. /// /// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. #[cfg(feature = "prio-bits-0")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] #[allow(missing_docs)] pub enum Priority { P0 = 0x0, } /// The interrupt priority level. /// /// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. #[cfg(feature = "prio-bits-1")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] #[allow(missing_docs)] pub enum Priority { P0 = 0x0, P1 = 0x80, } /// The interrupt priority level. /// /// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. #[cfg(feature = "prio-bits-2")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] #[allow(missing_docs)] pub enum Priority { P0 = 0x0, P1 = 0x40, P2 = 0x80, P3 = 0xc0, } /// The interrupt priority level. /// /// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. #[cfg(feature = "prio-bits-3")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] #[allow(missing_docs)] pub enum Priority { P0 = 0x0, P1 = 0x20, P2 = 0x40, P3 = 0x60, P4 = 0x80, P5 = 0xa0, P6 = 0xc0, P7 = 0xe0, } /// The interrupt priority level. /// /// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. #[cfg(feature = "prio-bits-4")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] #[allow(missing_docs)] pub enum Priority { P0 = 0x0, P1 = 0x10, P2 = 0x20, P3 = 0x30, P4 = 0x40, P5 = 0x50, P6 = 0x60, P7 = 0x70, P8 = 0x80, P9 = 0x90, P10 = 0xa0, P11 = 0xb0, P12 = 0xc0, P13 = 0xd0, P14 = 0xe0, P15 = 0xf0, } /// The interrupt priority level. /// /// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. #[cfg(feature = "prio-bits-5")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] #[allow(missing_docs)] pub enum Priority { P0 = 0x0, P1 = 0x8, P2 = 0x10, P3 = 0x18, P4 = 0x20, P5 = 0x28, P6 = 0x30, P7 = 0x38, P8 = 0x40, P9 = 0x48, P10 = 0x50, P11 = 0x58, P12 = 0x60, P13 = 0x68, P14 = 0x70, P15 = 0x78, P16 = 0x80, P17 = 0x88, P18 = 0x90, P19 = 0x98, P20 = 0xa0, P21 = 0xa8, P22 = 0xb0, P23 = 0xb8, P24 = 0xc0, P25 = 0xc8, P26 = 0xd0, P27 = 0xd8, P28 = 0xe0, P29 = 0xe8, P30 = 0xf0, P31 = 0xf8, } /// The interrupt priority level. /// /// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. #[cfg(feature = "prio-bits-6")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] #[allow(missing_docs)] pub enum Priority { P0 = 0x0, P1 = 0x4, P2 = 0x8, P3 = 0xc, P4 = 0x10, P5 = 0x14, P6 = 0x18, P7 = 0x1c, P8 = 0x20, P9 = 0x24, P10 = 0x28, P11 = 0x2c, P12 = 0x30, P13 = 0x34, P14 = 0x38, P15 = 0x3c, P16 = 0x40, P17 = 0x44, P18 = 0x48, P19 = 0x4c, P20 = 0x50, P21 = 0x54, P22 = 0x58, P23 = 0x5c, P24 = 0x60, P25 = 0x64, P26 = 0x68, P27 = 0x6c, P28 = 0x70, P29 = 0x74, P30 = 0x78, P31 = 0x7c, P32 = 0x80, P33 = 0x84, P34 = 0x88, P35 = 0x8c, P36 = 0x90, P37 = 0x94, P38 = 0x98, P39 = 0x9c, P40 = 0xa0, P41 = 0xa4, P42 = 0xa8, P43 = 0xac, P44 = 0xb0, P45 = 0xb4, P46 = 0xb8, P47 = 0xbc, P48 = 0xc0, P49 = 0xc4, P50 = 0xc8, P51 = 0xcc, P52 = 0xd0, P53 = 0xd4, P54 = 0xd8, P55 = 0xdc, P56 = 0xe0, P57 = 0xe4, P58 = 0xe8, P59 = 0xec, P60 = 0xf0, P61 = 0xf4, P62 = 0xf8, P63 = 0xfc, } /// The interrupt priority level. /// /// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. #[cfg(feature = "prio-bits-7")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] #[allow(missing_docs)] pub enum Priority { P0 = 0x0, P1 = 0x2, P2 = 0x4, P3 = 0x6, P4 = 0x8, P5 = 0xa, P6 = 0xc, P7 = 0xe, P8 = 0x10, P9 = 0x12, P10 = 0x14, P11 = 0x16, P12 = 0x18, P13 = 0x1a, P14 = 0x1c, P15 = 0x1e, P16 = 0x20, P17 = 0x22, P18 = 0x24, P19 = 0x26, P20 = 0x28, P21 = 0x2a, P22 = 0x2c, P23 = 0x2e, P24 = 0x30, P25 = 0x32, P26 = 0x34, P27 = 0x36, P28 = 0x38, P29 = 0x3a, P30 = 0x3c, P31 = 0x3e, P32 = 0x40, P33 = 0x42, P34 = 0x44, P35 = 0x46, P36 = 0x48, P37 = 0x4a, P38 = 0x4c, P39 = 0x4e, P40 = 0x50, P41 = 0x52, P42 = 0x54, P43 = 0x56, P44 = 0x58, P45 = 0x5a, P46 = 0x5c, P47 = 0x5e, P48 = 0x60, P49 = 0x62, P50 = 0x64, P51 = 0x66, P52 = 0x68, P53 = 0x6a, P54 = 0x6c, P55 = 0x6e, P56 = 0x70, P57 = 0x72, P58 = 0x74, P59 = 0x76, P60 = 0x78, P61 = 0x7a, P62 = 0x7c, P63 = 0x7e, P64 = 0x80, P65 = 0x82, P66 = 0x84, P67 = 0x86, P68 = 0x88, P69 = 0x8a, P70 = 0x8c, P71 = 0x8e, P72 = 0x90, P73 = 0x92, P74 = 0x94, P75 = 0x96, P76 = 0x98, P77 = 0x9a, P78 = 0x9c, P79 = 0x9e, P80 = 0xa0, P81 = 0xa2, P82 = 0xa4, P83 = 0xa6, P84 = 0xa8, P85 = 0xaa, P86 = 0xac, P87 = 0xae, P88 = 0xb0, P89 = 0xb2, P90 = 0xb4, P91 = 0xb6, P92 = 0xb8, P93 = 0xba, P94 = 0xbc, P95 = 0xbe, P96 = 0xc0, P97 = 0xc2, P98 = 0xc4, P99 = 0xc6, P100 = 0xc8, P101 = 0xca, P102 = 0xcc, P103 = 0xce, P104 = 0xd0, P105 = 0xd2, P106 = 0xd4, P107 = 0xd6, P108 = 0xd8, P109 = 0xda, P110 = 0xdc, P111 = 0xde, P112 = 0xe0, P113 = 0xe2, P114 = 0xe4, P115 = 0xe6, P116 = 0xe8, P117 = 0xea, P118 = 0xec, P119 = 0xee, P120 = 0xf0, P121 = 0xf2, P122 = 0xf4, P123 = 0xf6, P124 = 0xf8, P125 = 0xfa, P126 = 0xfc, P127 = 0xfe, } /// The interrupt priority level. /// /// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature. #[cfg(feature = "prio-bits-8")] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] #[allow(missing_docs)] pub enum Priority { P0 = 0x0, P1 = 0x1, P2 = 0x2, P3 = 0x3, P4 = 0x4, P5 = 0x5, P6 = 0x6, P7 = 0x7, P8 = 0x8, P9 = 0x9, P10 = 0xa, P11 = 0xb, P12 = 0xc, P13 = 0xd, P14 = 0xe, P15 = 0xf, P16 = 0x10, P17 = 0x11, P18 = 0x12, P19 = 0x13, P20 = 0x14, P21 = 0x15, P22 = 0x16, P23 = 0x17, P24 = 0x18, P25 = 0x19, P26 = 0x1a, P27 = 0x1b, P28 = 0x1c, P29 = 0x1d, P30 = 0x1e, P31 = 0x1f, P32 = 0x20, P33 = 0x21, P34 = 0x22, P35 = 0x23, P36 = 0x24, P37 = 0x25, P38 = 0x26, P39 = 0x27, P40 = 0x28, P41 = 0x29, P42 = 0x2a, P43 = 0x2b, P44 = 0x2c, P45 = 0x2d, P46 = 0x2e, P47 = 0x2f, P48 = 0x30, P49 = 0x31, P50 = 0x32, P51 = 0x33, P52 = 0x34, P53 = 0x35, P54 = 0x36, P55 = 0x37, P56 = 0x38, P57 = 0x39, P58 = 0x3a, P59 = 0x3b, P60 = 0x3c, P61 = 0x3d, P62 = 0x3e, P63 = 0x3f, P64 = 0x40, P65 = 0x41, P66 = 0x42, P67 = 0x43, P68 = 0x44, P69 = 0x45, P70 = 0x46, P71 = 0x47, P72 = 0x48, P73 = 0x49, P74 = 0x4a, P75 = 0x4b, P76 = 0x4c, P77 = 0x4d, P78 = 0x4e, P79 = 0x4f, P80 = 0x50, P81 = 0x51, P82 = 0x52, P83 = 0x53, P84 = 0x54, P85 = 0x55, P86 = 0x56, P87 = 0x57, P88 = 0x58, P89 = 0x59, P90 = 0x5a, P91 = 0x5b, P92 = 0x5c, P93 = 0x5d, P94 = 0x5e, P95 = 0x5f, P96 = 0x60, P97 = 0x61, P98 = 0x62, P99 = 0x63, P100 = 0x64, P101 = 0x65, P102 = 0x66, P103 = 0x67, P104 = 0x68, P105 = 0x69, P106 = 0x6a, P107 = 0x6b, P108 = 0x6c, P109 = 0x6d, P110 = 0x6e, P111 = 0x6f, P112 = 0x70, P113 = 0x71, P114 = 0x72, P115 = 0x73, P116 = 0x74, P117 = 0x75, P118 = 0x76, P119 = 0x77, P120 = 0x78, P121 = 0x79, P122 = 0x7a, P123 = 0x7b, P124 = 0x7c, P125 = 0x7d, P126 = 0x7e, P127 = 0x7f, P128 = 0x80, P129 = 0x81, P130 = 0x82, P131 = 0x83, P132 = 0x84, P133 = 0x85, P134 = 0x86, P135 = 0x87, P136 = 0x88, P137 = 0x89, P138 = 0x8a, P139 = 0x8b, P140 = 0x8c, P141 = 0x8d, P142 = 0x8e, P143 = 0x8f, P144 = 0x90, P145 = 0x91, P146 = 0x92, P147 = 0x93, P148 = 0x94, P149 = 0x95, P150 = 0x96, P151 = 0x97, P152 = 0x98, P153 = 0x99, P154 = 0x9a, P155 = 0x9b, P156 = 0x9c, P157 = 0x9d, P158 = 0x9e, P159 = 0x9f, P160 = 0xa0, P161 = 0xa1, P162 = 0xa2, P163 = 0xa3, P164 = 0xa4, P165 = 0xa5, P166 = 0xa6, P167 = 0xa7, P168 = 0xa8, P169 = 0xa9, P170 = 0xaa, P171 = 0xab, P172 = 0xac, P173 = 0xad, P174 = 0xae, P175 = 0xaf, P176 = 0xb0, P177 = 0xb1, P178 = 0xb2, P179 = 0xb3, P180 = 0xb4, P181 = 0xb5, P182 = 0xb6, P183 = 0xb7, P184 = 0xb8, P185 = 0xb9, P186 = 0xba, P187 = 0xbb, P188 = 0xbc, P189 = 0xbd, P190 = 0xbe, P191 = 0xbf, P192 = 0xc0, P193 = 0xc1, P194 = 0xc2, P195 = 0xc3, P196 = 0xc4, P197 = 0xc5, P198 = 0xc6, P199 = 0xc7, P200 = 0xc8, P201 = 0xc9, P202 = 0xca, P203 = 0xcb, P204 = 0xcc, P205 = 0xcd, P206 = 0xce, P207 = 0xcf, P208 = 0xd0, P209 = 0xd1, P210 = 0xd2, P211 = 0xd3, P212 = 0xd4, P213 = 0xd5, P214 = 0xd6, P215 = 0xd7, P216 = 0xd8, P217 = 0xd9, P218 = 0xda, P219 = 0xdb, P220 = 0xdc, P221 = 0xdd, P222 = 0xde, P223 = 0xdf, P224 = 0xe0, P225 = 0xe1, P226 = 0xe2, P227 = 0xe3, P228 = 0xe4, P229 = 0xe5, P230 = 0xe6, P231 = 0xe7, P232 = 0xe8, P233 = 0xe9, P234 = 0xea, P235 = 0xeb, P236 = 0xec, P237 = 0xed, P238 = 0xee, P239 = 0xef, P240 = 0xf0, P241 = 0xf1, P242 = 0xf2, P243 = 0xf3, P244 = 0xf4, P245 = 0xf5, P246 = 0xf6, P247 = 0xf7, P248 = 0xf8, P249 = 0xf9, P250 = 0xfa, P251 = 0xfb, P252 = 0xfc, P253 = 0xfd, P254 = 0xfe, P255 = 0xff, }