aboutsummaryrefslogtreecommitdiff
path: root/embassy-cortex-m/src/interrupt.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-cortex-m/src/interrupt.rs')
-rw-r--r--embassy-cortex-m/src/interrupt.rs214
1 files changed, 151 insertions, 63 deletions
diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-cortex-m/src/interrupt.rs
index 0e790eaaf..e9fa43e87 100644
--- a/embassy-cortex-m/src/interrupt.rs
+++ b/embassy-cortex-m/src/interrupt.rs
@@ -2,120 +2,208 @@
2use core::mem; 2use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering}; 3use core::sync::atomic::{compiler_fence, Ordering};
4 4
5use cortex_m::interrupt::InterruptNumber;
5use cortex_m::peripheral::NVIC; 6use cortex_m::peripheral::NVIC;
6 7
7/// Do not use. Used for macros and HALs only. Not covered by semver guarantees. 8/// Generate a standard `mod interrupt` for a HAL.
8#[doc(hidden)] 9#[macro_export]
9pub mod _export { 10macro_rules! interrupt_mod {
10 pub use atomic_polyfill as atomic; 11 ($($irqs:ident),* $(,)?) => {
11 pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare}; 12 #[cfg(feature = "rt")]
12} 13 pub use cortex_m_rt::interrupt;
13 14
14/// Interrupt handler trait. 15 /// Interrupt definitions.
15/// 16 pub mod interrupt {
16/// Drivers that need to handle interrupts implement this trait. 17 pub use embassy_cortex_m::interrupt::{InterruptExt, Priority};
17/// The user must ensure `on_interrupt()` is called every time the interrupt fires. 18 pub use crate::pac::Interrupt::*;
18/// Drivers must use use [`Binding`] to assert at compile time that the user has done so. 19 pub use crate::pac::Interrupt;
19pub trait Handler<I: Interrupt> {
20 /// Interrupt handler function.
21 ///
22 /// Must be called every time the `I` interrupt fires, synchronously from
23 /// the interrupt handler context.
24 ///
25 /// # Safety
26 ///
27 /// This function must ONLY be called from the interrupt handler for `I`.
28 unsafe fn on_interrupt();
29}
30 20
31/// Compile-time assertion that an interrupt has been bound to a handler. 21 /// Type-level interrupt infrastructure.
32/// 22 ///
33/// For the vast majority of cases, you should use the `bind_interrupts!` 23 /// This module contains one *type* per interrupt. This is used for checking at compile time that
34/// macro instead of writing `unsafe impl`s of this trait. 24 /// the interrupts are correctly bound to HAL drivers.
35/// 25 ///
36/// # Safety 26 /// As an end user, you shouldn't need to use this module directly. Use the [`crate::bind_interrupts!`] macro
37/// 27 /// to bind interrupts, and the [`crate::interrupt`] module to manually register interrupt handlers and manipulate
38/// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()` 28 /// interrupts directly (pending/unpending, enabling/disabling, setting the priority, etc...)
39/// to be called every time the `I` interrupt fires. 29 pub mod typelevel {
40/// 30 use super::InterruptExt;
41/// This allows drivers to check bindings at compile-time. 31
42pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {} 32 mod sealed {
43 33 pub trait Interrupt {}
44#[derive(Clone, Copy)] 34 }
45pub(crate) struct NrWrap(pub(crate) u16); 35
46unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap { 36 /// Type-level interrupt.
47 fn number(self) -> u16 { 37 ///
48 self.0 38 /// This trait is implemented for all typelevel interrupt types in this module.
49 } 39 pub trait Interrupt: sealed::Interrupt {
40
41 /// Interrupt enum variant.
42 ///
43 /// This allows going from typelevel interrupts (one type per interrupt) to
44 /// non-typelevel interrupts (a single `Interrupt` enum type, with one variant per interrupt).
45 const IRQ: super::Interrupt;
46
47 /// Enable the interrupt.
48 #[inline]
49 unsafe fn enable() {
50 Self::IRQ.enable()
51 }
52
53 /// Disable the interrupt.
54 #[inline]
55 fn disable() {
56 Self::IRQ.disable()
57 }
58
59 /// Check if interrupt is enabled.
60 #[inline]
61 fn is_enabled() -> bool {
62 Self::IRQ.is_enabled()
63 }
64
65 /// Check if interrupt is pending.
66 #[inline]
67 fn is_pending() -> bool {
68 Self::IRQ.is_pending()
69 }
70
71 /// Set interrupt pending.
72 #[inline]
73 fn pend() {
74 Self::IRQ.pend()
75 }
76
77 /// Unset interrupt pending.
78 #[inline]
79 fn unpend() {
80 Self::IRQ.unpend()
81 }
82
83 /// Get the priority of the interrupt.
84 #[inline]
85 fn get_priority() -> crate::interrupt::Priority {
86 Self::IRQ.get_priority()
87 }
88
89 /// Set the interrupt priority.
90 #[inline]
91 fn set_priority(prio: crate::interrupt::Priority) {
92 Self::IRQ.set_priority(prio)
93 }
94 }
95
96 $(
97 #[allow(non_camel_case_types)]
98 #[doc=stringify!($irqs)]
99 #[doc=" typelevel interrupt."]
100 pub enum $irqs {}
101 impl sealed::Interrupt for $irqs{}
102 impl Interrupt for $irqs {
103 const IRQ: super::Interrupt = super::Interrupt::$irqs;
104 }
105 )*
106
107 /// Interrupt handler trait.
108 ///
109 /// Drivers that need to handle interrupts implement this trait.
110 /// The user must ensure `on_interrupt()` is called every time the interrupt fires.
111 /// Drivers must use use [`Binding`] to assert at compile time that the user has done so.
112 pub trait Handler<I: Interrupt> {
113 /// Interrupt handler function.
114 ///
115 /// Must be called every time the `I` interrupt fires, synchronously from
116 /// the interrupt handler context.
117 ///
118 /// # Safety
119 ///
120 /// This function must ONLY be called from the interrupt handler for `I`.
121 unsafe fn on_interrupt();
122 }
123
124 /// Compile-time assertion that an interrupt has been bound to a handler.
125 ///
126 /// For the vast majority of cases, you should use the `bind_interrupts!`
127 /// macro instead of writing `unsafe impl`s of this trait.
128 ///
129 /// # Safety
130 ///
131 /// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()`
132 /// to be called every time the `I` interrupt fires.
133 ///
134 /// This allows drivers to check bindings at compile-time.
135 pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {}
136 }
137 }
138 };
50} 139}
51 140
52/// Represents an interrupt type that can be configured by embassy to handle 141/// Represents an interrupt type that can be configured by embassy to handle
53/// interrupts. 142/// interrupts.
54pub unsafe trait Interrupt { 143pub unsafe trait InterruptExt: InterruptNumber + Copy {
55 /// Return the NVIC interrupt number for this interrupt.
56 fn number() -> u16;
57
58 /// Enable the interrupt. 144 /// Enable the interrupt.
59 #[inline] 145 #[inline]
60 unsafe fn enable() { 146 unsafe fn enable(self) {
61 compiler_fence(Ordering::SeqCst); 147 compiler_fence(Ordering::SeqCst);
62 NVIC::unmask(NrWrap(Self::number())) 148 NVIC::unmask(self)
63 } 149 }
64 150
65 /// Disable the interrupt. 151 /// Disable the interrupt.
66 #[inline] 152 #[inline]
67 fn disable() { 153 fn disable(self) {
68 NVIC::mask(NrWrap(Self::number())); 154 NVIC::mask(self);
69 compiler_fence(Ordering::SeqCst); 155 compiler_fence(Ordering::SeqCst);
70 } 156 }
71 157
72 /// Check if interrupt is being handled. 158 /// Check if interrupt is being handled.
73 #[inline] 159 #[inline]
74 #[cfg(not(armv6m))] 160 #[cfg(not(armv6m))]
75 fn is_active() -> bool { 161 fn is_active(self) -> bool {
76 NVIC::is_active(NrWrap(Self::number())) 162 NVIC::is_active(self)
77 } 163 }
78 164
79 /// Check if interrupt is enabled. 165 /// Check if interrupt is enabled.
80 #[inline] 166 #[inline]
81 fn is_enabled() -> bool { 167 fn is_enabled(self) -> bool {
82 NVIC::is_enabled(NrWrap(Self::number())) 168 NVIC::is_enabled(self)
83 } 169 }
84 170
85 /// Check if interrupt is pending. 171 /// Check if interrupt is pending.
86 #[inline] 172 #[inline]
87 fn is_pending() -> bool { 173 fn is_pending(self) -> bool {
88 NVIC::is_pending(NrWrap(Self::number())) 174 NVIC::is_pending(self)
89 } 175 }
90 176
91 /// Set interrupt pending. 177 /// Set interrupt pending.
92 #[inline] 178 #[inline]
93 fn pend() { 179 fn pend(self) {
94 NVIC::pend(NrWrap(Self::number())) 180 NVIC::pend(self)
95 } 181 }
96 182
97 /// Unset interrupt pending. 183 /// Unset interrupt pending.
98 #[inline] 184 #[inline]
99 fn unpend() { 185 fn unpend(self) {
100 NVIC::unpend(NrWrap(Self::number())) 186 NVIC::unpend(self)
101 } 187 }
102 188
103 /// Get the priority of the interrupt. 189 /// Get the priority of the interrupt.
104 #[inline] 190 #[inline]
105 fn get_priority() -> Priority { 191 fn get_priority(self) -> Priority {
106 Priority::from(NVIC::get_priority(NrWrap(Self::number()))) 192 Priority::from(NVIC::get_priority(self))
107 } 193 }
108 194
109 /// Set the interrupt priority. 195 /// Set the interrupt priority.
110 #[inline] 196 #[inline]
111 fn set_priority(prio: Priority) { 197 fn set_priority(self, prio: Priority) {
112 critical_section::with(|_| unsafe { 198 critical_section::with(|_| unsafe {
113 let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(()); 199 let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
114 nvic.set_priority(NrWrap(Self::number()), prio.into()) 200 nvic.set_priority(self, prio.into())
115 }) 201 })
116 } 202 }
117} 203}
118 204
205unsafe impl<T: InterruptNumber + Copy> InterruptExt for T {}
206
119impl From<u8> for Priority { 207impl From<u8> for Priority {
120 fn from(priority: u8) -> Self { 208 fn from(priority: u8) -> Self {
121 unsafe { mem::transmute(priority & PRIO_MASK) } 209 unsafe { mem::transmute(priority & PRIO_MASK) }