nrf/timer: remove awaitable.
This commit is contained in:
parent
9cf000ef4e
commit
63b75eaf64
@ -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<I>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Timer<'d, T, Awaitable> {
|
||||
/// Create a new async-capable 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.
|
||||
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<P = T> + '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<P = T> + '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<T, I> {
|
||||
pub fn cc(&mut self, n: usize) -> Cc<T> {
|
||||
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<I>,
|
||||
}
|
||||
|
||||
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()
|
||||
|
@ -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…
Reference in New Issue
Block a user