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}