nrf/timer: remove awaitable.

This commit is contained in:
Dario Nieuwenhuis 2023-03-05 20:27:33 +01:00
parent 9cf000ef4e
commit 63b75eaf64
2 changed files with 10 additions and 150 deletions

View File

@ -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()

View File

@ -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");
}
}