esp_hal/interrupt/
mod.rs

1//! # Interrupt support
2//!
3//! ## Overview
4//! This module routes one or more peripheral interrupt sources to any one
5//! of the CPU’s peripheral interrupts.
6//!
7//! ## Configuration
8//! Usually peripheral drivers offer a mechanism to register your interrupt
9//! handler. e.g. the systimer offers `set_interrupt_handler` to register a
10//! handler for a specific alarm. Other drivers might take an interrupt handler
11//! as an optional parameter to their constructor.
12//!
13//! This is the preferred way to register handlers.
14//!
15//! There are additional ways to register interrupt handlers which are generally
16//! only meant to be used in very special situations (mostly internal to the HAL
17//! or the supporting libraries). Those are outside the scope of this
18//! documentation.
19//!
20//! It is even possible, but not recommended, to bind an interrupt directly to a
21//! CPU interrupt. This can offer lower latency, at the cost of more complexity
22//! in the interrupt handler. See the `direct_vectoring.rs` example
23//!
24//! We reserve a number of CPU interrupts, which cannot be used; see
25//! [`RESERVED_INTERRUPTS`].
26//!
27//! ## Examples
28//!
29//! ### Using the peripheral driver to register an interrupt handler
30//!
31//! ```rust, no_run
32#![doc = crate::before_snippet!()]
33//! let mut sw_int =
34//!     SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
35//! critical_section::with(|cs| {
36//!     sw_int
37//!         .software_interrupt0
38//!         .set_interrupt_handler(swint0_handler);
39//!     SWINT0
40//!         .borrow_ref_mut(cs)
41//!         .replace(sw_int.software_interrupt0);
42//! });
43//!
44//! critical_section::with(|cs| {
45//!     if let Some(swint) = SWINT0.borrow_ref(cs).as_ref(){
46//!         swint.raise();
47//!     }
48//! });
49//! #
50//! # loop {}
51//! # }
52//!
53//! # use core::cell::RefCell;
54//! #
55//! # use critical_section::Mutex;
56//! # use esp_hal::interrupt::software::{SoftwareInterrupt, SoftwareInterruptControl};
57//! # use esp_hal::interrupt::Priority;
58//! # use esp_hal::interrupt::InterruptHandler;
59//! #
60//! static SWINT0: Mutex<RefCell<Option<SoftwareInterrupt<0>>>> =
61//!     Mutex::new(RefCell::new(None));
62//!
63//! #[handler(priority = Priority::Priority1)]
64//! fn swint0_handler() {
65//!     println!("SW interrupt0");
66//!     critical_section::with(|cs| {
67//!         if let Some(swint) = SWINT0.borrow_ref(cs).as_ref() {
68//!             swint.reset();
69//!         }
70//!     });
71//! }
72//! ```
73
74use core::ops::BitAnd;
75
76#[cfg(riscv)]
77pub use self::riscv::*;
78#[cfg(xtensa)]
79pub use self::xtensa::*;
80
81#[cfg(riscv)]
82mod riscv;
83#[cfg(xtensa)]
84mod xtensa;
85
86pub mod software;
87
88#[cfg(xtensa)]
89#[no_mangle]
90extern "C" fn EspDefaultHandler(_level: u32, _interrupt: crate::peripherals::Interrupt) {
91    panic!("Unhandled level {} interrupt: {:?}", _level, _interrupt);
92}
93
94#[cfg(riscv)]
95#[no_mangle]
96extern "C" fn EspDefaultHandler(_interrupt: crate::peripherals::Interrupt) {
97    panic!("Unhandled interrupt: {:?}", _interrupt);
98}
99
100/// Default (unhandled) interrupt handler
101pub const DEFAULT_INTERRUPT_HANDLER: InterruptHandler = InterruptHandler::new(
102    unsafe { core::mem::transmute::<*const (), extern "C" fn()>(EspDefaultHandler as *const ()) },
103    Priority::min(),
104);
105
106/// Trait implemented by drivers which allow the user to set an
107/// [InterruptHandler]
108pub trait InterruptConfigurable: crate::private::Sealed {
109    #[cfg_attr(
110        not(multi_core),
111        doc = "Registers an interrupt handler for the peripheral."
112    )]
113    #[cfg_attr(
114        multi_core,
115        doc = "Registers an interrupt handler for the peripheral on the current core."
116    )]
117    #[doc = ""]
118    /// Note that this will replace any previously registered interrupt
119    /// handlers. Some peripherals offer a shared interrupt handler for
120    /// multiple purposes. It's the users duty to honor this.
121    ///
122    /// You can restore the default/unhandled interrupt handler by using
123    /// [DEFAULT_INTERRUPT_HANDLER]
124    fn set_interrupt_handler(&mut self, handler: InterruptHandler);
125}
126
127/// An interrupt handler
128#[cfg_attr(
129    multi_core,
130    doc = "**Note**: Interrupts are handled on the core they were setup on, if a driver is initialized on core 0, and moved to core 1, core 0 will still handle the interrupt."
131)]
132#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
133#[cfg_attr(feature = "defmt", derive(defmt::Format))]
134pub struct InterruptHandler {
135    f: extern "C" fn(),
136    prio: Priority,
137}
138
139impl InterruptHandler {
140    /// Creates a new [InterruptHandler] which will call the given function at
141    /// the given priority.
142    pub const fn new(f: extern "C" fn(), prio: Priority) -> Self {
143        Self { f, prio }
144    }
145
146    /// The function to be called
147    #[inline]
148    pub fn handler(&self) -> extern "C" fn() {
149        self.f
150    }
151
152    /// Priority to be used when registering the interrupt
153    #[inline]
154    pub fn priority(&self) -> Priority {
155        self.prio
156    }
157}
158
159#[cfg(large_intr_status)]
160const STATUS_WORDS: usize = 3;
161
162#[cfg(very_large_intr_status)]
163const STATUS_WORDS: usize = 4;
164
165#[cfg(not(any(large_intr_status, very_large_intr_status)))]
166const STATUS_WORDS: usize = 2;
167
168/// Representation of peripheral-interrupt status bits.
169#[derive(Clone, Copy, Default, Debug)]
170pub struct InterruptStatus {
171    status: [u32; STATUS_WORDS],
172}
173
174impl InterruptStatus {
175    const fn empty() -> Self {
176        InterruptStatus {
177            status: [0u32; STATUS_WORDS],
178        }
179    }
180
181    #[cfg(large_intr_status)]
182    const fn from(w0: u32, w1: u32, w2: u32) -> Self {
183        Self {
184            status: [w0, w1, w2],
185        }
186    }
187
188    #[cfg(very_large_intr_status)]
189    const fn from(w0: u32, w1: u32, w2: u32, w3: u32) -> Self {
190        Self {
191            status: [w0, w1, w2, w3],
192        }
193    }
194
195    #[cfg(not(any(large_intr_status, very_large_intr_status)))]
196    const fn from(w0: u32, w1: u32) -> Self {
197        Self { status: [w0, w1] }
198    }
199
200    /// Is the given interrupt bit set
201    pub fn is_set(&self, interrupt: u16) -> bool {
202        (self.status[interrupt as usize / 32] & (1 << (interrupt as u32 % 32))) != 0
203    }
204
205    /// Set the given interrupt status bit
206    pub fn set(&mut self, interrupt: u16) {
207        self.status[interrupt as usize / 32] |= 1 << (interrupt as u32 % 32);
208    }
209
210    /// Return an iterator over the set interrupt status bits
211    pub fn iterator(&self) -> InterruptStatusIterator {
212        InterruptStatusIterator {
213            status: *self,
214            idx: 0,
215        }
216    }
217}
218
219impl BitAnd for InterruptStatus {
220    type Output = InterruptStatus;
221
222    fn bitand(self, rhs: Self) -> Self::Output {
223        #[cfg(large_intr_status)]
224        return Self::Output {
225            status: [
226                self.status[0] & rhs.status[0],
227                self.status[1] & rhs.status[1],
228                self.status[2] & rhs.status[2],
229            ],
230        };
231
232        #[cfg(very_large_intr_status)]
233        return Self::Output {
234            status: [
235                self.status[0] & rhs.status[0],
236                self.status[1] & rhs.status[1],
237                self.status[2] & rhs.status[2],
238                self.status[3] & rhs.status[3],
239            ],
240        };
241
242        #[cfg(not(any(large_intr_status, very_large_intr_status)))]
243        return Self::Output {
244            status: [
245                self.status[0] & rhs.status[0],
246                self.status[1] & rhs.status[1],
247            ],
248        };
249    }
250}
251
252/// Iterator over set interrupt status bits
253pub struct InterruptStatusIterator {
254    status: InterruptStatus,
255    idx: usize,
256}
257
258impl Iterator for InterruptStatusIterator {
259    type Item = u8;
260
261    fn next(&mut self) -> Option<Self::Item> {
262        for i in self.idx..STATUS_WORDS {
263            if self.status.status[i] != 0 {
264                let bit = self.status.status[i].trailing_zeros();
265                self.idx = i;
266                self.status.status[i] &= !1 << bit;
267                return Some((bit + 32 * i as u32) as u8);
268            }
269        }
270        self.idx = usize::MAX;
271        None
272    }
273}