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///
42/// Forms a read/write memory barrier for the compiler.
43#[inline]
44#[asm_cfg(cortex_m)]
45pub fn disable() {
46    unsafe { asm!("cpsid i", options(nostack, preserves_flags)) };
47
48    // Ensure no subsequent memory accesses are reordered to before interrupts are disabled.
49    compiler_fence(Ordering::SeqCst);
50}
51
52/// Enables all the interrupts
53///
54/// Forms a read/write memory barrier for the compiler.
55///
56/// # Safety
57///
58/// - Do not call this function inside an `interrupt::free` critical section
59#[inline]
60#[asm_cfg(cortex_m)]
61pub unsafe fn enable() {
62    // Ensure no preceeding memory accesses are reordered to after interrupts are enabled.
63    compiler_fence(Ordering::SeqCst);
64
65    unsafe { asm!("cpsie i", options(nostack, preserves_flags)) };
66}
67
68/// Execute closure `f` in an interrupt-free context.
69///
70/// This as also known as a "critical section".
71#[inline]
72pub fn free<F, R>(f: F) -> R
73where
74    F: FnOnce(&CriticalSection) -> R,
75{
76    // Backup previous state of PRIMASK register. We access the entire register directly as a
77    // u32 instead of using the primask::read() function to minimize the number of processor
78    // cycles during which interrupts are disabled.
79    let primask = crate::register::primask::read_raw();
80
81    // disable interrupts
82    disable();
83
84    let r = f(&unsafe { CriticalSection::new() });
85
86    unsafe {
87        crate::register::primask::write_raw(primask);
88    }
89
90    r
91}