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}