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