diff --git a/rp2040-hal/src/timer.rs b/rp2040-hal/src/timer.rs index 403e2a0..ab991b7 100644 --- a/rp2040-hal/src/timer.rs +++ b/rp2040-hal/src/timer.rs @@ -14,10 +14,26 @@ use crate::atomic_register_access::{write_bitmask_clear, write_bitmask_set}; use crate::pac::{RESETS, TIMER}; use crate::resets::SubsystemReset; use core::marker::PhantomData; +use core::sync::atomic::{AtomicU8, Ordering}; /// Instant type used by the Timer & Alarm methods. pub type Instant = TimerInstantU64<1_000_000>; +static ALARMS: AtomicU8 = AtomicU8::new(0x0F); +fn take_alarm(mask: u8) -> bool { + critical_section::with(|_| { + let alarms = ALARMS.load(Ordering::Relaxed); + ALARMS.store(alarms & !mask, Ordering::Relaxed); + (alarms & mask) != 0 + }) +} +fn release_alarm(mask: u8) { + critical_section::with(|_| { + let alarms = ALARMS.load(Ordering::Relaxed); + ALARMS.store(alarms | mask, Ordering::Relaxed); + }); +} + fn get_counter(timer: &crate::pac::timer::RegisterBlock) -> Instant { let mut hi0 = timer.timerawh.read().bits(); let timestamp = loop { @@ -33,7 +49,6 @@ fn get_counter(timer: &crate::pac::timer::RegisterBlock) -> Instant { /// Timer peripheral pub struct Timer { timer: TIMER, - alarms: [bool; 4], } impl Timer { @@ -41,10 +56,7 @@ impl Timer { pub fn new(timer: TIMER, resets: &mut RESETS) -> Self { timer.reset_bring_down(resets); timer.reset_bring_up(resets); - Self { - timer, - alarms: [true; 4], - } + Self { timer } } /// Get the current counter value. @@ -65,48 +77,30 @@ impl Timer { next_end: None, } } - /// Retrieve a reference to alarm 0. Will only return a value the first time this is called pub fn alarm_0(&mut self) -> Option { - if self.alarms[0] { - self.alarms[0] = false; - Some(Alarm0(PhantomData)) - } else { - None - } + take_alarm(1 << 0).then_some(Alarm0(PhantomData)) } /// Retrieve a reference to alarm 1. Will only return a value the first time this is called pub fn alarm_1(&mut self) -> Option { - if self.alarms[1] { - self.alarms[1] = false; - Some(Alarm1(PhantomData)) - } else { - None - } + take_alarm(1 << 1).then_some(Alarm1(PhantomData)) } /// Retrieve a reference to alarm 2. Will only return a value the first time this is called pub fn alarm_2(&mut self) -> Option { - if self.alarms[2] { - self.alarms[2] = false; - Some(Alarm2(PhantomData)) - } else { - None - } + take_alarm(1 << 2).then_some(Alarm2(PhantomData)) } /// Retrieve a reference to alarm 3. Will only return a value the first time this is called pub fn alarm_3(&mut self) -> Option { - if self.alarms[3] { - self.alarms[3] = false; - Some(Alarm3(PhantomData)) - } else { - None - } + take_alarm(1 << 3).then_some(Alarm3(PhantomData)) } } +// safety: all write operations are synchronised and all reads are atomic +unsafe impl Sync for Timer {} + /// Implementation of the embedded_hal::Timer traits using rp2040_hal::timer counter /// /// ## Usage @@ -340,6 +334,13 @@ macro_rules! impl_alarm { (bits & $armed_bit_mask) == 0 } } + + impl Drop for $name { + fn drop(&mut self) { + self.disable_interrupt(); + release_alarm($armed_bit_mask) + } + } }; }