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 | |