From 4d71c0ee76cee0bee651eb7b131bdad6a3c259b5 Mon Sep 17 00:00:00 2001 From: Rahix Date: Thu, 9 May 2019 10:58:29 +0200 Subject: [PATCH] Add interrupts and use cfg-if Signed-off-by: Rahix --- Cargo.toml | 3 +- src/devices/mod.rs | 11 +++++--- src/interrupt.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 31 ++++++++++++++------- 4 files changed, 98 insertions(+), 15 deletions(-) create mode 100644 src/interrupt.rs diff --git a/Cargo.toml b/Cargo.toml index 4a32280..1598624 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,9 +5,10 @@ authors = ["Rahix "] edition = "2018" [features] -attiny85 = [] atmega32u4 = [] +attiny85 = [] [dependencies] bare-metal = "0.2.4" vcell = "0.1.0" +cfg-if = "0.1.7" diff --git a/src/devices/mod.rs b/src/devices/mod.rs index b068eec..0ef1b14 100644 --- a/src/devices/mod.rs +++ b/src/devices/mod.rs @@ -1,4 +1,7 @@ -#[cfg(feature = "attiny85")] -pub mod attiny85; -#[cfg(feature = "atmega32u4")] -pub mod atmega32u4; +cfg_if::cfg_if! { + if #[cfg(feature = "atmega32u4")] { + pub mod atmega32u4; + } else if #[cfg(feature = "attiny85")] { + pub mod attiny85; + } +} diff --git a/src/interrupt.rs b/src/interrupt.rs new file mode 100644 index 0000000..3e2a5ac --- /dev/null +++ b/src/interrupt.rs @@ -0,0 +1,68 @@ +//! Interrupts +//! +//! For the most part, [interrupt::free] is what you want: +//! +//! ``` +//! atmega32u4::interrupt::free(|cs| { +//! // Interrupts are disabled here +//! }) +//! ``` + +pub use bare_metal::{CriticalSection, Mutex, Nr}; + +#[inline] +/// Disables all interrupts +pub fn disable() { + unsafe { + asm!( + "cli" :::: "volatile" + ); + } +} + +#[inline] +/// Enables all the interrupts +/// +/// # Safety +/// +/// - Do not call this function inside an `interrupt::free` critical section +pub fn enable() { + unsafe { + asm!( + "sei" :::: "volatile" + ); + } +} + +/// Execute closure `f` in an interrupt-free context. +/// +/// This as also known as a "critical section". +pub fn free(f: F) -> R +where + F: FnOnce(&CriticalSection) -> R, +{ + let sreg: u8; + + // Store current state + unsafe { + asm!( + "in $0,0x35" + : "=r"(sreg) + : + : + : "volatile" + ); + } + + // Disable interrupts + disable(); + + let r = f(unsafe { &CriticalSection::new() }); + + // Restore interrupt state + if sreg & 0x80 != 0x00 { + enable(); + } + + r +} diff --git a/src/lib.rs b/src/lib.rs index d437777..e9f6a60 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,21 +1,32 @@ #![no_std] +#![feature(asm)] -#[allow(non_camel_case_types)] +#[allow(non_camel_case_types, unused_attributes)] mod devices; -#[cfg(feature = "attiny85")] -pub use crate::devices::attiny85::*; -#[cfg(feature = "atmega32u4")] -pub use crate::devices::atmega32u4::*; +pub mod interrupt; +cfg_if::cfg_if! { + if #[cfg(feature = "atmega32u4")] { + pub use crate::devices::atmega32u4::*; + } else if #[cfg(feature = "attiny85")] { + pub use crate::devices::attiny85::*; + } else { + compile_error!("You need to select exactly one chip as a feature!"); + } +} + +#[cfg(any(feature = "attiny85", feature = "atmega32u4"))] impl Peripherals { /// Returns all the peripherals *once* #[inline] pub fn take() -> Option { - if unsafe { DEVICE_PERIPHERALS } { - None - } else { - Some(unsafe { Peripherals::steal() }) - } + interrupt::free(|_| { + if unsafe { DEVICE_PERIPHERALS } { + None + } else { + Some(unsafe { Peripherals::steal() }) + } + }) } } -- 2.49.0