diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 3b0d2f1c..a9487a9f 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -6,15 +6,9 @@ #![macro_use] -use core::future::poll_fn; -use core::marker::PhantomData; -use core::task::Poll; - -use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; -use embassy_sync::waitqueue::AtomicWaker; -use crate::interrupt::{Interrupt, InterruptExt}; +use crate::interrupt::Interrupt; use crate::ppi::{Event, Task}; use crate::{pac, Peripheral}; @@ -26,8 +20,6 @@ pub(crate) mod sealed { /// The number of CC registers this instance has. const CCS: usize; fn regs() -> &'static pac::timer0::RegisterBlock; - /// Storage for the waker for CC register `n`. - fn waker(n: usize) -> &'static AtomicWaker; } pub trait ExtendedInstance {} @@ -50,12 +42,6 @@ macro_rules! impl_timer { fn regs() -> &'static pac::timer0::RegisterBlock { unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } } - fn waker(n: usize) -> &'static ::embassy_sync::waitqueue::AtomicWaker { - use ::embassy_sync::waitqueue::AtomicWaker; - const NEW_AW: AtomicWaker = AtomicWaker::new(); - static WAKERS: [AtomicWaker; $ccs] = [NEW_AW; $ccs]; - &WAKERS[n] - } } impl crate::timer::Instance for peripherals::$type { type Interrupt = crate::interrupt::$irq; @@ -99,59 +85,18 @@ pub enum Frequency { /// nRF Timer driver. /// /// The timer has an internal counter, which is incremented for every tick of the timer. -/// The counter is 32-bit, so it wraps back to 0 at 4294967296. +/// The counter is 32-bit, so it wraps back to 0 when it reaches 2^32. /// /// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter /// or trigger an event when the counter reaches a certain value. -pub trait TimerType: sealed::TimerType {} - -/// Marker type indicating the timer driver can await expiration (it owns the timer interrupt). -pub enum Awaitable {} - -/// Marker type indicating the timer driver cannot await expiration (it does not own the timer interrupt). -pub enum NotAwaitable {} - -impl sealed::TimerType for Awaitable {} -impl sealed::TimerType for NotAwaitable {} -impl TimerType for Awaitable {} -impl TimerType for NotAwaitable {} - /// Timer driver. -pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> { +pub struct Timer<'d, T: Instance> { _p: PeripheralRef<'d, T>, - _i: PhantomData, } -impl<'d, T: Instance> Timer<'d, T, Awaitable> { - /// Create a new async-capable timer driver. - pub fn new_awaitable(timer: impl Peripheral

+ 'd, irq: impl Peripheral

+ 'd) -> Self { - into_ref!(irq); - - irq.set_handler(Self::on_interrupt); - irq.unpend(); - irq.enable(); - - Self::new_inner(timer, false) - } - - /// Create a new async-capable timer driver in counter mode. - pub fn new_awaitable_counter( - timer: impl Peripheral

+ 'd, - irq: impl Peripheral

+ 'd, - ) -> Self { - into_ref!(irq); - - irq.set_handler(Self::on_interrupt); - irq.unpend(); - irq.enable(); - - Self::new_inner(timer, true) - } -} - -impl<'d, T: Instance> Timer<'d, T, NotAwaitable> { - /// Create a `Timer` driver without an interrupt, meaning `Cc::wait` won't work. +impl<'d, T: Instance> Timer<'d, T> { + /// Create a new `Timer` driver. /// /// This can be useful for triggering tasks via PPI /// `Uarte` uses this internally. @@ -159,28 +104,20 @@ impl<'d, T: Instance> Timer<'d, T, NotAwaitable> { Self::new_inner(timer, false) } - /// Create a `Timer` driver in counter mode without an interrupt, meaning `Cc::wait` won't work. + /// Create a new `Timer` driver in counter mode. /// /// This can be useful for triggering tasks via PPI /// `Uarte` uses this internally. pub fn new_counter(timer: impl Peripheral

+ 'd) -> Self { Self::new_inner(timer, true) } -} -impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { - /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work. - /// - /// This is used by the public constructors. fn new_inner(timer: impl Peripheral

+ 'd, is_counter: bool) -> Self { into_ref!(timer); let regs = T::regs(); - let mut this = Self { - _p: timer, - _i: PhantomData, - }; + let mut this = Self { _p: timer }; // Stop the timer before doing anything else, // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. @@ -272,31 +209,17 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { .write(|w| unsafe { w.prescaler().bits(frequency as u8) }) } - fn on_interrupt(_: *mut ()) { - let regs = T::regs(); - for n in 0..T::CCS { - if regs.events_compare[n].read().bits() != 0 { - // Clear the interrupt, otherwise the interrupt will be repeatedly raised as soon as the interrupt handler exits. - // We can't clear the event, because it's used to poll whether the future is done or still pending. - regs.intenclr - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + n))) }); - T::waker(n).wake(); - } - } - } - /// Returns this timer's `n`th CC register. /// /// # Panics /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer). - pub fn cc(&mut self, n: usize) -> Cc { + pub fn cc(&mut self, n: usize) -> Cc { if n >= T::CCS { panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS); } Cc { n, _p: self._p.reborrow(), - _i: PhantomData, } } } @@ -308,49 +231,12 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { /// /// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register. /// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register -pub struct Cc<'d, T: Instance, I: TimerType = NotAwaitable> { +pub struct Cc<'d, T: Instance> { n: usize, _p: PeripheralRef<'d, T>, - _i: PhantomData, } -impl<'d, T: Instance> Cc<'d, T, Awaitable> { - /// Wait until the timer's counter reaches the value stored in this register. - /// - /// This requires a mutable reference so that this task's waker cannot be overwritten by a second call to `wait`. - pub async fn wait(&mut self) { - let regs = T::regs(); - - // Enable the interrupt for this CC's COMPARE event. - regs.intenset - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) }); - - // Disable the interrupt if the future is dropped. - let on_drop = OnDrop::new(|| { - regs.intenclr - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) }); - }); - - poll_fn(|cx| { - T::waker(self.n).register(cx.waker()); - - if regs.events_compare[self.n].read().bits() != 0 { - // Reset the register for next time - regs.events_compare[self.n].reset(); - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; - - // The interrupt was already disabled in the interrupt handler, so there's no need to disable it again. - on_drop.defuse(); - } -} -impl<'d, T: Instance> Cc<'d, T, NotAwaitable> {} - -impl<'d, T: Instance, I: TimerType> Cc<'d, T, I> { +impl<'d, T: Instance> Cc<'d, T> { /// Get the current value stored in the register. pub fn read(&self) -> u32 { T::regs().cc[self.n].read().cc().bits() diff --git a/examples/nrf52840/src/bin/awaitable_timer.rs b/examples/nrf52840/src/bin/awaitable_timer.rs deleted file mode 100644 index b32af236..00000000 --- a/examples/nrf52840/src/bin/awaitable_timer.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -use defmt::info; -use embassy_executor::Spawner; -use embassy_nrf::interrupt; -use embassy_nrf::timer::Timer; -use {defmt_rtt as _, panic_probe as _}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = embassy_nrf::init(Default::default()); - let mut t = Timer::new_awaitable(p.TIMER0, interrupt::take!(TIMER0)); - // default frequency is 1MHz, so this triggers every second - t.cc(0).write(1_000_000); - // clear the timer value on cc[0] compare match - t.cc(0).short_compare_clear(); - t.start(); - - loop { - // wait for compare match - t.cc(0).wait().await; - info!("hardware timer tick"); - } -}