nrf/timer: remove awaitable.
This commit is contained in:
		
							parent
							
								
									9cf000ef4e
								
							
						
					
					
						commit
						63b75eaf64
					
				| @ -6,15 +6,9 @@ | |||||||
| 
 | 
 | ||||||
| #![macro_use] | #![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_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::ppi::{Event, Task}; | ||||||
| use crate::{pac, Peripheral}; | use crate::{pac, Peripheral}; | ||||||
| 
 | 
 | ||||||
| @ -26,8 +20,6 @@ pub(crate) mod sealed { | |||||||
|         /// The number of CC registers this instance has.
 |         /// The number of CC registers this instance has.
 | ||||||
|         const CCS: usize; |         const CCS: usize; | ||||||
|         fn regs() -> &'static pac::timer0::RegisterBlock; |         fn regs() -> &'static pac::timer0::RegisterBlock; | ||||||
|         /// Storage for the waker for CC register `n`.
 |  | ||||||
|         fn waker(n: usize) -> &'static AtomicWaker; |  | ||||||
|     } |     } | ||||||
|     pub trait ExtendedInstance {} |     pub trait ExtendedInstance {} | ||||||
| 
 | 
 | ||||||
| @ -50,12 +42,6 @@ macro_rules! impl_timer { | |||||||
|             fn regs() -> &'static pac::timer0::RegisterBlock { |             fn regs() -> &'static pac::timer0::RegisterBlock { | ||||||
|                 unsafe { &*(pac::$pac_type::ptr() as *const 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 { |         impl crate::timer::Instance for peripherals::$type { | ||||||
|             type Interrupt = crate::interrupt::$irq; |             type Interrupt = crate::interrupt::$irq; | ||||||
| @ -99,59 +85,18 @@ pub enum Frequency { | |||||||
| /// nRF Timer driver.
 | /// nRF Timer driver.
 | ||||||
| ///
 | ///
 | ||||||
| /// The timer has an internal counter, which is incremented for every tick of the timer.
 | /// 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
 | /// 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.
 | /// 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.
 | /// Timer driver.
 | ||||||
| pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> { | pub struct Timer<'d, T: Instance> { | ||||||
|     _p: PeripheralRef<'d, T>, |     _p: PeripheralRef<'d, T>, | ||||||
|     _i: PhantomData<I>, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'d, T: Instance> Timer<'d, T, Awaitable> { | impl<'d, T: Instance> Timer<'d, T> { | ||||||
|     /// Create a new async-capable timer driver.
 |     /// Create a new `Timer` driver.
 | ||||||
|     pub fn new_awaitable(timer: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + '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<P = T> + 'd, |  | ||||||
|         irq: impl Peripheral<P = T::Interrupt> + '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.
 |  | ||||||
|     ///
 |     ///
 | ||||||
|     /// This can be useful for triggering tasks via PPI
 |     /// This can be useful for triggering tasks via PPI
 | ||||||
|     /// `Uarte` uses this internally.
 |     /// `Uarte` uses this internally.
 | ||||||
| @ -159,28 +104,20 @@ impl<'d, T: Instance> Timer<'d, T, NotAwaitable> { | |||||||
|         Self::new_inner(timer, false) |         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
 |     /// This can be useful for triggering tasks via PPI
 | ||||||
|     /// `Uarte` uses this internally.
 |     /// `Uarte` uses this internally.
 | ||||||
|     pub fn new_counter(timer: impl Peripheral<P = T> + 'd) -> Self { |     pub fn new_counter(timer: impl Peripheral<P = T> + 'd) -> Self { | ||||||
|         Self::new_inner(timer, true) |         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<P = T> + 'd, is_counter: bool) -> Self { |     fn new_inner(timer: impl Peripheral<P = T> + 'd, is_counter: bool) -> Self { | ||||||
|         into_ref!(timer); |         into_ref!(timer); | ||||||
| 
 | 
 | ||||||
|         let regs = T::regs(); |         let regs = T::regs(); | ||||||
| 
 | 
 | ||||||
|         let mut this = Self { |         let mut this = Self { _p: timer }; | ||||||
|             _p: timer, |  | ||||||
|             _i: PhantomData, |  | ||||||
|         }; |  | ||||||
| 
 | 
 | ||||||
|         // Stop the timer before doing anything else,
 |         // Stop the timer before doing anything else,
 | ||||||
|         // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
 |         // 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) }) |             .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.
 |     /// Returns this timer's `n`th CC register.
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// # Panics
 |     /// # Panics
 | ||||||
|     /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer).
 |     /// 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<T, I> { |     pub fn cc(&mut self, n: usize) -> Cc<T> { | ||||||
|         if n >= T::CCS { |         if n >= T::CCS { | ||||||
|             panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS); |             panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS); | ||||||
|         } |         } | ||||||
|         Cc { |         Cc { | ||||||
|             n, |             n, | ||||||
|             _p: self._p.reborrow(), |             _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.
 | /// 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
 | /// 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, |     n: usize, | ||||||
|     _p: PeripheralRef<'d, T>, |     _p: PeripheralRef<'d, T>, | ||||||
|     _i: PhantomData<I>, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'d, T: Instance> Cc<'d, T, Awaitable> { | impl<'d, T: Instance> Cc<'d, T> { | ||||||
|     /// 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> { |  | ||||||
|     /// Get the current value stored in the register.
 |     /// Get the current value stored in the register.
 | ||||||
|     pub fn read(&self) -> u32 { |     pub fn read(&self) -> u32 { | ||||||
|         T::regs().cc[self.n].read().cc().bits() |         T::regs().cc[self.n].read().cc().bits() | ||||||
|  | |||||||
| @ -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"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user