#![macro_use] use core::marker::PhantomData; use core::task::Poll; use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; use embassy_util::waitqueue::AtomicWaker; use futures::future::poll_fn; use crate::interrupt::{Interrupt, InterruptExt}; use crate::ppi::{Event, Task}; use crate::{pac, Peripheral}; pub(crate) mod sealed { use super::*; pub trait Instance { /// 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 {} pub trait TimerType {} } pub trait Instance: Peripheral
+ sealed::Instance + 'static + Send { type Interrupt: Interrupt; } pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} macro_rules! impl_timer { ($type:ident, $pac_type:ident, $irq:ident, $ccs:literal) => { impl crate::timer::sealed::Instance for peripherals::$type { const CCS: usize = $ccs; fn regs() -> &'static pac::timer0::RegisterBlock { unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } } fn waker(n: usize) -> &'static ::embassy_util::waitqueue::AtomicWaker { use ::embassy_util::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; } }; ($type:ident, $pac_type:ident, $irq:ident) => { impl_timer!($type, $pac_type, $irq, 4); }; ($type:ident, $pac_type:ident, $irq:ident, extended) => { impl_timer!($type, $pac_type, $irq, 6); impl crate::timer::sealed::ExtendedInstance for peripherals::$type {} impl crate::timer::ExtendedInstance for peripherals::$type {} }; } #[repr(u8)] pub enum Frequency { // I'd prefer not to prefix these with `F`, but Rust identifiers can't start with digits. F16MHz = 0, F8MHz = 1, F4MHz = 2, F2MHz = 3, F1MHz = 4, F500kHz = 5, F250kHz = 6, F125kHz = 7, F62500Hz = 8, F31250Hz = 9, } /// 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. /// /// 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 {} pub enum Awaitable {} pub enum NotAwaitable {} impl sealed::TimerType for Awaitable {} impl sealed::TimerType for NotAwaitable {} impl TimerType for Awaitable {} impl TimerType for NotAwaitable {} pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> { _p: PeripheralRef<'d, T>, _i: PhantomData, } impl<'d, T: Instance> Timer<'d, T, Awaitable> { 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_irqless(timer) } } impl<'d, T: Instance> Timer<'d, T, NotAwaitable> { /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work. /// /// This can be useful for triggering tasks via PPI /// `Uarte` uses this internally. pub fn new(timer: impl Peripheral
+ 'd) -> Self { Self::new_irqless(timer) } } 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_irqless(timer: impl Peripheral
+ 'd) -> Self {
into_ref!(timer);
let regs = T::regs();
let mut this = Self {
_p: timer,
_i: PhantomData,
};
// Stop the timer before doing anything else,
// since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
this.stop();
// Set the instance to timer mode.
regs.mode.write(|w| w.mode().timer());
// Make the counter's max value as high as possible.
// TODO: is there a reason someone would want to set this lower?
regs.bitmode.write(|w| w.bitmode()._32bit());
// Initialize the counter at 0.
this.clear();
// Default to the max frequency of the lower power clock
this.set_frequency(Frequency::F1MHz);
for n in 0..T::CCS {
let cc = this.cc(n);
// Initialize all the shorts as disabled.
cc.unshort_compare_clear();
cc.unshort_compare_stop();
// Initialize the CC registers as 0.
cc.write(0);
}
this
}
/// Starts the timer.
pub fn start(&self) {
T::regs().tasks_start.write(|w| unsafe { w.bits(1) })
}
/// Stops the timer.
pub fn stop(&self) {
T::regs().tasks_stop.write(|w| unsafe { w.bits(1) })
}
/// Reset the timer's counter to 0.
pub fn clear(&self) {
T::regs().tasks_clear.write(|w| unsafe { w.bits(1) })
}
/// Returns the START task, for use with PPI.
///
/// When triggered, this task starts the timer.
pub fn task_start(&self) -> Task {
Task::from_reg(&T::regs().tasks_start)
}
/// Returns the STOP task, for use with PPI.
///
/// When triggered, this task stops the timer.
pub fn task_stop(&self) -> Task {
Task::from_reg(&T::regs().tasks_stop)
}
/// Returns the CLEAR task, for use with PPI.
///
/// When triggered, this task resets the timer's counter to 0.
pub fn task_clear(&self) -> Task {
Task::from_reg(&T::regs().tasks_clear)
}
/// Change the timer's frequency.
///
/// This will stop the timer if it isn't already stopped,
/// because the timer may exhibit 'unpredictable behaviour' if it's frequency is changed while it's running.
pub fn set_frequency(&self, frequency: Frequency) {
self.stop();
T::regs()
.prescaler
// SAFETY: `frequency` is a variant of `Frequency`,
// whose values are all in the range of 0-9 (the valid range of `prescaler`).
.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