aboutsummaryrefslogtreecommitdiff
path: root/src/interrupt.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/interrupt.rs')
-rw-r--r--src/interrupt.rs64
1 files changed, 64 insertions, 0 deletions
diff --git a/src/interrupt.rs b/src/interrupt.rs
new file mode 100644
index 0000000..68719ec
--- /dev/null
+++ b/src/interrupt.rs
@@ -0,0 +1,64 @@
+//! Interrupts
+
+pub use bare_metal::{CriticalSection, Mutex};
+
+/// Trait for enums of external interrupt numbers.
+///
+/// This trait should be implemented by a peripheral access crate (PAC)
+/// on its enum of available external interrupts for a specific device.
+/// Each variant must convert to a u16 of its interrupt number,
+/// which is its exception number - 16.
+///
+/// # Safety
+///
+/// This trait must only be implemented on enums of device interrupts. Each
+/// enum variant must represent a distinct value (no duplicates are permitted),
+/// and must always return the same value (do not change at runtime).
+///
+/// These requirements ensure safe nesting of critical sections.
+pub unsafe trait InterruptNumber: Copy {
+ /// Return the interrupt number associated with this variant.
+ ///
+ /// See trait documentation for safety requirements.
+ fn number(self) -> u16;
+}
+
+/// Disables all interrupts
+#[inline]
+pub fn disable() {
+ call_asm!(__cpsid());
+}
+
+/// Enables all the interrupts
+///
+/// # Safety
+///
+/// - Do not call this function inside an `interrupt::free` critical section
+#[inline]
+pub unsafe fn enable() {
+ call_asm!(__cpsie());
+}
+
+/// Execute closure `f` in an interrupt-free context.
+///
+/// This as also known as a "critical section".
+#[inline]
+pub fn free<F, R>(f: F) -> R
+where
+ F: FnOnce(&CriticalSection) -> R,
+{
+ let primask = crate::register::primask::read();
+
+ // disable interrupts
+ disable();
+
+ let r = f(unsafe { &CriticalSection::new() });
+
+ // If the interrupts were active before our `disable` call, then re-enable
+ // them. Otherwise, keep them disabled
+ if primask.is_active() {
+ unsafe { enable() }
+ }
+
+ r
+}