//! Timer driver. //! //! Important note! This driver is very low level. For most time-related use cases, like //! "sleep for X seconds", "do something every X seconds", or measuring time, you should //! use [`embassy-time`](https://crates.io/crates/embassy-time) instead! #![macro_use] use embassy_hal_common::{into_ref, PeripheralRef}; use crate::interrupt::Interrupt; 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; } pub trait ExtendedInstance {} pub trait TimerType {} } /// Basic Timer instance. pub trait Instance: Peripheral
+ sealed::Instance + 'static + Send { /// Interrupt for this peripheral. type Interrupt: Interrupt; } /// Extended timer instance. 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) } } } 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 {} }; } /// Timer frequency #[repr(u8)] pub enum Frequency { /// 16MHz F16MHz = 0, /// 8MHz F8MHz = 1, /// 4MHz F4MHz = 2, /// 2MHz F2MHz = 3, /// 1MHz F1MHz = 4, /// 500kHz F500kHz = 5, /// 250kHz F250kHz = 6, /// 125kHz F125kHz = 7, /// 62500Hz F62500Hz = 8, /// 31250Hz 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 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. /// Timer driver. pub struct Timer<'d, T: Instance> { _p: PeripheralRef<'d, T>, } 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. pub fn new(timer: impl Peripheral
+ 'd) -> Self { Self::new_inner(timer, false) } /// 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
+ 'd) -> Self { Self::new_inner(timer, true) } fn new_inner(timer: impl Peripheral
 + 'd, is_counter: bool) -> Self {
        into_ref!(timer);
        let regs = T::regs();
        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.
        this.stop();
        if is_counter {
            regs.mode.write(|w| w.mode().counter());
        } else {
            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)
    }
    /// Returns the COUNT task, for use with PPI.
    ///
    /// When triggered, this task increments the timer's counter by 1.
    /// Only works in counter mode.
    pub fn task_count(&self) -> Task {
        Task::from_reg(&T::regs().tasks_count)
    }
    /// 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) })
    }
    /// 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