| 1 | //! Interrupts |
| 2 | |
| 3 | pub use bare_metal::{CriticalSection, Mutex, Nr}; |
| 4 | |
| 5 | /// Trait for enums of external interrupt numbers. |
| 6 | /// |
| 7 | /// This trait should be implemented by a peripheral access crate (PAC) |
| 8 | /// on its enum of available external interrupts for a specific device. |
| 9 | /// Each variant must convert to a u16 of its interrupt number, |
| 10 | /// which is its exception number - 16. |
| 11 | /// |
| 12 | /// # Safety |
| 13 | /// |
| 14 | /// This trait must only be implemented on enums of device interrupts. Each |
| 15 | /// enum variant must represent a distinct value (no duplicates are permitted), |
| 16 | /// and must always return the same value (do not change at runtime). |
| 17 | /// |
| 18 | /// These requirements ensure safe nesting of critical sections. |
| 19 | pub unsafe trait InterruptNumber: Copy { |
| 20 | /// Return the interrupt number associated with this variant. |
| 21 | /// |
| 22 | /// See trait documentation for safety requirements. |
| 23 | fn number(self) -> u16; |
| 24 | } |
| 25 | |
| 26 | /// Implement InterruptNumber for the old bare_metal::Nr trait. |
| 27 | /// This implementation is for backwards compatibility only and will be removed in cortex-m 0.8. |
| 28 | unsafe impl<T: Nr + Copy> InterruptNumber for T { |
| 29 | #[inline ] |
| 30 | fn number(self) -> u16 { |
| 31 | self.nr() as u16 |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | /// Disables all interrupts |
| 36 | #[inline ] |
| 37 | pub fn disable() { |
| 38 | call_asm!(__cpsid()); |
| 39 | } |
| 40 | |
| 41 | /// Enables all the interrupts |
| 42 | /// |
| 43 | /// # Safety |
| 44 | /// |
| 45 | /// - Do not call this function inside an `interrupt::free` critical section |
| 46 | #[inline ] |
| 47 | pub unsafe fn enable() { |
| 48 | call_asm!(__cpsie()); |
| 49 | } |
| 50 | |
| 51 | /// Execute closure `f` in an interrupt-free context. |
| 52 | /// |
| 53 | /// This as also known as a "critical section". |
| 54 | #[inline ] |
| 55 | pub fn free<F, R>(f: F) -> R |
| 56 | where |
| 57 | F: FnOnce(&CriticalSection) -> R, |
| 58 | { |
| 59 | let primask: Primask = crate::register::primask::read(); |
| 60 | |
| 61 | // disable interrupts |
| 62 | disable(); |
| 63 | |
| 64 | let r: R = f(unsafe { &CriticalSection::new() }); |
| 65 | |
| 66 | // If the interrupts were active before our `disable` call, then re-enable |
| 67 | // them. Otherwise, keep them disabled |
| 68 | if primask.is_active() { |
| 69 | unsafe { enable() } |
| 70 | } |
| 71 | |
| 72 | r |
| 73 | } |
| 74 | |