From a0c40562eab224d273a972fdcf5029c585974bc7 Mon Sep 17 00:00:00 2001 From: f_punk Date: Wed, 1 Sep 2021 16:16:56 +0200 Subject: [PATCH] added typestate to nrf-Timer useful for hooking up the PPI to an Event without needing interrupt tested with buffered_uart example on nRF52840-DK --- embassy-nrf/src/buffered_uarte.rs | 7 +++--- embassy-nrf/src/timer.rs | 42 +++++++++++++++++++++++++------ embassy-nrf/src/uarte.rs | 7 +++--- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 048c36d3..5c9f4270 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -15,9 +15,8 @@ use crate::gpio::sealed::Pin as _; use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin}; use crate::pac; use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; -use crate::timer::Frequency; use crate::timer::Instance as TimerInstance; -use crate::timer::Timer; +use crate::timer::{Frequency, NotAwaitableTimer}; use crate::uarte::{Config, Instance as UarteInstance}; // Re-export SVD variants to allow user to directly set values @@ -44,7 +43,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> State<'d, U, T> { struct StateInner<'d, U: UarteInstance, T: TimerInstance> { phantom: PhantomData<&'d mut U>, - timer: Timer<'d, T>, + timer: NotAwaitableTimer<'d, T>, _ppi_ch1: Ppi<'d, AnyConfigurableChannel>, _ppi_ch2: Ppi<'d, AnyConfigurableChannel>, @@ -85,7 +84,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { let r = U::regs(); - let mut timer = Timer::new_irqless(timer); + let mut timer = NotAwaitableTimer::new(timer); rxd.conf().write(|w| w.input().connect().drive().h0h1()); r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index eab9a141..939e99ed 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -27,6 +27,8 @@ pub(crate) mod sealed { fn waker(n: usize) -> &'static AtomicWaker; } pub trait ExtendedInstance {} + + pub trait TimerType {} } pub trait Instance: Unborrow + sealed::Instance + 'static + Send { @@ -84,11 +86,25 @@ pub enum Frequency { /// /// 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 struct Timer<'d, T: Instance> { - phantom: PhantomData<&'d mut T>, + +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 type AwaitableTimer<'d, T> = Timer<'d, T, Awaitable>; +pub type NotAwaitableTimer<'d, T> = Timer<'d, T, NotAwaitable>; + +pub struct Timer<'d, T: Instance, I: TimerType> { + phantom: PhantomData<(&'d mut T, I)>, } -impl<'d, T: Instance> Timer<'d, T> { +impl<'d, T: Instance> Timer<'d, T, Awaitable> { pub fn new( timer: impl Unborrow + 'd, irq: impl Unborrow + 'd, @@ -101,11 +117,18 @@ impl<'d, T: Instance> Timer<'d, T> { Self::new_irqless(timer) } +} +impl<'d, T: Instance> Timer<'d, T, NotAwaitable> { + pub fn new(timer: impl Unborrow + '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 `Uarte` internally. - pub(crate) fn new_irqless(_timer: impl Unborrow + 'd) -> Self { + fn new_irqless(_timer: impl Unborrow + 'd) -> Self { let regs = T::regs(); let mut this = Self { @@ -208,7 +231,7 @@ impl<'d, T: Instance> Timer<'d, T> { /// /// # 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 { + pub fn cc(&mut self, n: usize) -> Cc { if n >= T::CCS { panic!( "Cannot get CC register {} of timer with {} CC registers.", @@ -219,6 +242,7 @@ impl<'d, T: Instance> Timer<'d, T> { Cc { n, phantom: PhantomData, + phantom2: PhantomData, } } } @@ -230,12 +254,16 @@ impl<'d, T: Instance> Timer<'d, T> { /// /// 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<'a, T: Instance> { +pub struct Cc<'a, T: Instance, I: TimerType> { n: usize, phantom: PhantomData<&'a mut T>, + phantom2: PhantomData, } -impl<'a, T: Instance> Cc<'a, T> { +impl<'a, T: Instance> Cc<'a, T, Awaitable> {} +impl<'a, T: Instance> Cc<'a, T, NotAwaitable> {} + +impl<'a, T: Instance, I: TimerType> Cc<'a, T, I> { /// Get the current value stored in the register. pub fn read(&self) -> u32 { T::regs().cc[self.n].read().cc().bits() diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index b2b29866..d164ebcb 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -18,9 +18,8 @@ use crate::gpio::{self, OptionalPin as GpioOptionalPin, Pin as GpioPin}; use crate::interrupt::Interrupt; use crate::pac; use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; -use crate::timer::Frequency; use crate::timer::Instance as TimerInstance; -use crate::timer::Timer; +use crate::timer::{Frequency, NotAwaitableTimer}; // Re-export SVD variants to allow user to directly set values. pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; @@ -289,7 +288,7 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { /// allowing it to implement the ReadUntilIdle trait. pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> { uarte: Uarte<'d, U>, - timer: Timer<'d, T>, + timer: NotAwaitableTimer<'d, T>, ppi_ch1: Ppi<'d, AnyConfigurableChannel>, _ppi_ch2: Ppi<'d, AnyConfigurableChannel>, } @@ -318,7 +317,7 @@ impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> { ) -> Self { let baudrate = config.baudrate; let uarte = Uarte::new(uarte, irq, rxd, txd, cts, rts, config); - let mut timer = Timer::new_irqless(timer); + let mut timer = NotAwaitableTimer::new(timer); unborrow!(ppi_ch1, ppi_ch2);