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…
Reference in New Issue
Block a user