Skip to main content

cortex_m/
interrupt.rs

1//! Interrupts
2
3pub use bare_metal::{CriticalSection, Mutex, Nr};
4#[cfg(cortex_m)]
5use core::arch::asm;
6#[cfg(cortex_m)]
7use core::sync::atomic::{Ordering, compiler_fence};
8use cortex_m_macros::asm_cfg;
9
10/// Trait for enums of external interrupt numbers.
11///
12/// This trait should be implemented by a peripheral access crate (PAC)
13/// on its enum of available external interrupts for a specific device.
14/// Each variant must convert to a u16 of its interrupt number,
15/// which is its exception number - 16.
16///
17/// # Safety
18///
19/// This trait must only be implemented on enums of device interrupts. Each
20/// enum variant must represent a distinct value (no duplicates are permitted),
21/// and must always return the same value (do not change at runtime).
22///
23/// These requirements ensure safe nesting of critical sections.
24pub unsafe trait InterruptNumber: Copy {
25    /// Return the interrupt number associated with this variant.
26    ///
27    /// See trait documentation for safety requirements.
28    fn number(self) -> u16;
29}
30
31/// Implement InterruptNumber for the old bare_metal::Nr trait.
32/// This implementation is for backwards compatibility only and will be removed in cortex-m 0.8.
33unsafe impl<T: Nr + Copy> InterruptNumber for T {
34    #[inline]
35    fn number(self) -> u16 {
36        self.nr() as u16
37    }
38}
39
40/// Disables all interrupts
41#[inline]
42#[asm_cfg(cortex_m)]
43pub fn disable() {
44    unsafe { asm!("cpsid i", options(nomem, nostack, preserves_flags)) };
45
46    // Ensure no subsequent memory accesses are reordered to before interrupts are disabled.
47    compiler_fence(Ordering::SeqCst);
48}
49
50/// Enables all the interrupts
51///
52/// # Safety
53///
54/// - Do not call this function inside an `interrupt::free` critical section
55#[inline]
56#[asm_cfg(cortex_m)]
57pub unsafe fn enable() {
58    // Ensure no preceeding memory accesses are reordered to after interrupts are enabled.
59    compiler_fence(Ordering::SeqCst);
60
61    unsafe { asm!("cpsie i", options(nomem, nostack, preserves_flags)) };
62}
63
64/// Execute closure `f` in an interrupt-free context.
65///
66/// This as also known as a "critical section".
67#[cfg(cortex_m)]
68#[inline]
69pub fn free<F, R>(f: F) -> R
70where
71    F: FnOnce(&CriticalSection) -> R,
72{
73    // Backup previous state of PRIMASK register. We access the entire register directly as a
74    // u32 instead of using the primask::read() function to minimize the number of processor
75    // cycles during which interrupts are disabled.
76    let primask = crate::register::primask::read_raw();
77
78    // disable interrupts
79    disable();
80
81    let r = f(&unsafe { CriticalSection::new() });
82
83    unsafe {
84        crate::register::primask::write_raw(primask);
85    }
86
87    r
88}
89
90// Make a `free()` function available on hosted platforms to allow checking dependencies without
91// specifying a target, but that will panic at runtime if executed.
92/// Execute closure `f` in an interrupt-free context.
93///
94/// This as also known as a "critical section".
95#[cfg(not(cortex_m))]
96#[inline]
97pub fn free<F, R>(_: F) -> R
98where
99    F: FnOnce(&CriticalSection) -> R,
100{
101    panic!("cortex_m::interrupt::free() is only functional on cortex-m platforms");
102}