From 02781ed744b6e76d3790844f898235088b0fd8aa Mon Sep 17 00:00:00 2001 From: Liam Murphy Date: Sat, 26 Jun 2021 17:58:36 +1000 Subject: [PATCH 1/8] Add an nRF Timer driver Resolves #189 --- embassy-nrf/src/buffered_uarte.rs | 40 ++-- embassy-nrf/src/timer.rs | 377 +++++++++++++++++++++++++++++- embassy-nrf/src/uarte.rs | 36 ++- 3 files changed, 405 insertions(+), 48 deletions(-) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 517afa38c..39a8cd887 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -15,7 +15,9 @@ 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::uarte::{Config, Instance as UarteInstance}; // Re-export SVD variants to allow user to directly set values @@ -35,7 +37,7 @@ enum TxState { struct State<'d, U: UarteInstance, T: TimerInstance> { phantom: PhantomData<&'d mut U>, - timer: T, + timer: Timer<'d, T>, _ppi_ch1: Ppi<'d, AnyConfigurableChannel>, _ppi_ch2: Ppi<'d, AnyConfigurableChannel>, @@ -76,10 +78,11 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { rx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8], ) -> Self { - unborrow!(timer, ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts); + unborrow!(ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts); let r = U::regs(); - let rt = timer.regs(); + + let timer = Timer::new_irqless(timer); rxd.conf().write(|w| w.input().connect().drive().h0h1()); r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); @@ -133,25 +136,19 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { // This gives us the amount of 16M ticks for 20 bits. let timeout = 0x8000_0000 / (config.baudrate as u32 / 40); - rt.tasks_stop.write(|w| unsafe { w.bits(1) }); - rt.bitmode.write(|w| w.bitmode()._32bit()); - rt.prescaler.write(|w| unsafe { w.prescaler().bits(0) }); - rt.cc[0].write(|w| unsafe { w.bits(timeout) }); - rt.mode.write(|w| w.mode().timer()); - rt.shorts.write(|w| { - w.compare0_clear().set_bit(); - w.compare0_stop().set_bit(); - w - }); + timer.set_frequency(Frequency::F16MHz); + timer.cc0().set(timeout); + timer.cc0().short_compare_clear(); + timer.cc0().short_compare_stop(); let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade_configurable()); ppi_ch1.set_event(Event::from_reg(&r.events_rxdrdy)); - ppi_ch1.set_task(Task::from_reg(&rt.tasks_clear)); - ppi_ch1.set_fork_task(Task::from_reg(&rt.tasks_start)); + ppi_ch1.set_task(timer.task_clear()); + ppi_ch1.set_fork_task(timer.task_start()); ppi_ch1.enable(); let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade_configurable()); - ppi_ch2.set_event(Event::from_reg(&rt.events_compare[0])); + ppi_ch2.set_event(timer.cc0().event_compare()); ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx)); ppi_ch2.enable(); @@ -181,11 +178,10 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { inner.as_mut().register_interrupt(); inner.with(|state, _irq| { let r = U::regs(); - let rt = state.timer.regs(); let timeout = 0x8000_0000 / (baudrate as u32 / 40); - rt.cc[0].write(|w| unsafe { w.bits(timeout) }); - rt.tasks_clear.write(|w| unsafe { w.bits(1) }); + state.timer.cc0().set(timeout); + state.timer.clear(); r.baudrate.write(|w| w.baudrate().variant(baudrate)); }); @@ -268,11 +264,10 @@ impl<'d, U: UarteInstance, T: TimerInstance> AsyncWrite for BufferedUarte<'d, U, impl<'a, U: UarteInstance, T: TimerInstance> Drop for State<'a, U, T> { fn drop(&mut self) { let r = U::regs(); - let rt = self.timer.regs(); // TODO this probably deadlocks. do like Uarte instead. - rt.tasks_stop.write(|w| unsafe { w.bits(1) }); + self.timer.stop(); if let RxState::Receiving = self.rx_state { r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); } @@ -293,7 +288,6 @@ impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for State<'a, U, T> fn on_interrupt(&mut self) { trace!("irq: start"); let r = U::regs(); - let rt = self.timer.regs(); loop { match self.rx_state { @@ -330,7 +324,7 @@ impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for State<'a, U, T> RxState::Receiving => { trace!(" irq_rx: in state receiving"); if r.events_endrx.read().bits() != 0 { - rt.tasks_stop.write(|w| unsafe { w.bits(1) }); + self.timer.stop(); let n: usize = r.rxd.amount.read().amount().bits() as usize; trace!(" irq_rx: endrx {:?}", n); diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 2490bfd93..3b2678a0b 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -1,15 +1,30 @@ #![macro_use] +use core::marker::PhantomData; +use core::task::Poll; + use embassy::interrupt::Interrupt; +use embassy::interrupt::InterruptExt; +use embassy::util::OnDrop; use embassy::util::Unborrow; +use embassy_extras::unborrow; +use futures::future::poll_fn; use crate::pac; +use crate::ppi::Event; +use crate::ppi::Task; pub(crate) mod sealed { + use embassy::util::AtomicWaker; + use super::*; pub trait Instance { - fn regs(&self) -> &pac::timer0::RegisterBlock; + /// 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 {} } @@ -20,19 +35,373 @@ pub trait Instance: Unborrow + sealed::Instance + 'static { pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} macro_rules! impl_timer { - ($type:ident, $pac_type:ident, $irq:ident) => { + ($type:ident, $pac_type:ident, $irq:ident, $ccs:literal) => { impl crate::timer::sealed::Instance for peripherals::$type { - fn regs(&self) -> &pac::timer0::RegisterBlock { + 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::AtomicWaker { + use ::embassy::util::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); + 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 { + // TODO: These variant names are terrible, what should they be? + 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 struct Timer<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, +} + +impl<'d, T: Instance> Timer<'d, T> { + pub fn new( + timer: impl Unborrow + 'd, + irq: impl Unborrow + 'd, + ) -> Self { + unborrow!(irq); + + irq.set_handler(Self::on_interrupt); + irq.unpend(); + irq.enable(); + + Self::new_irqless(timer) + } + + /// 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 { + let regs = T::regs(); + + // 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()); + + let this = Self { + phantom: PhantomData, + }; + + // Initialize the timer as stopped. + this.stop(); + + // Initialize the counter at 0. + this.clear(); + + // Initialize all the shorts as disabled. + for n in 0..T::CCS { + let cc = Cc:: { + n, + phantom: PhantomData, + }; + cc.unshort_compare_clear(); + cc.unshort_compare_stop(); + } + + this + } + + /// Starts the timer. + pub fn start(&self) { + T::regs().tasks_start.write(|w| w.tasks_start().trigger()) + } + + /// Stops the timer. + pub fn stop(&self) { + T::regs().tasks_stop.write(|w| w.tasks_stop().trigger()) + } + + /// Reset the timer's counter to 0. + pub fn clear(&self) { + T::regs().tasks_clear.write(|w| w.tasks_clear().trigger()) + } + + /// 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() + .events_compare() + .is_generated() + { + T::waker(n).wake(); + } + } + } + + /// Returns the 0th CC register. + pub fn cc0<'a>(&'a self) -> Cc<'a, T> { + Cc { + n: 0, + phantom: PhantomData, + } + } + + /// Returns the 1st CC register. + pub fn cc1<'a>(&'a self) -> Cc<'a, T> { + Cc { + n: 1, + phantom: PhantomData, + } + } + + /// Returns the 2nd CC register. + pub fn cc2<'a>(&'a self) -> Cc<'a, T> { + Cc { + n: 2, + phantom: PhantomData, + } + } + + /// Returns the 3rd CC register. + pub fn cc3<'a>(&'a self) -> Cc<'a, T> { + Cc { + n: 3, + phantom: PhantomData, + } + } +} + +impl<'d, T: ExtendedInstance> Timer<'d, T> { + /// Returns the 4th CC register. + pub fn cc4<'a>(&'a self) -> Cc<'a, T> { + Cc { + n: 4, + phantom: PhantomData, + } + } + + /// Returns the 5th CC register. + pub fn cc5<'a>(&'a self) -> Cc<'a, T> { + Cc { + n: 5, + phantom: PhantomData, + } + } +} + +/// A representation of a timer's Capture/Compare (CC) register. +/// +/// A CC register holds a 32-bit value. +/// This is used either to store a capture of the timer's current count, or to specify the value for the timer to compare against. +/// +/// 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> { + n: usize, + phantom: PhantomData<&'a mut T>, +} + +impl<'a, T: Instance> Cc<'a, T> { + /// Get the current value stored in the register. + pub fn value(&self) -> u32 { + T::regs().cc[self.n].read().cc().bits() + } + + /// Set the value stored in the register. + /// + /// `event_compare` will fire when the timer's counter reaches this value. + pub fn set(&self, value: u32) { + // SAFETY: there are no invalid values for the CC register. + T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) }) + } + + /// Capture the current value of the timer's counter in this register, and return it. + pub fn capture(&self) -> u32 { + T::regs().tasks_capture[self.n].write(|w| w.tasks_capture().trigger()); + self.value() + } + + /// Returns this CC register's CAPTURE task, for use with PPI. + /// + /// When triggered, this task will capture the current value of the timer's counter in this register. + pub fn task_capture(&self) -> Task { + Task::from_reg(&T::regs().tasks_capture[self.n]) + } + + /// Returns this CC register's COMPARE event, for use with PPI. + /// + /// This event will fire when the timer's counter reaches the value in this CC register. + pub fn event_compare(&self) -> Event { + Event::from_reg(&T::regs().events_compare) + } + + /// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. + /// + /// This means that when the COMPARE event is fired, the CLEAR task will be triggered. + /// + /// So, when the timer's counter reaches the value stored in this register, the timer's counter will be reset to 0. + pub fn short_compare_clear(&self) { + T::regs().shorts.write(|w| match self.n { + 0 => w.compare0_clear().enabled(), + 1 => w.compare1_clear().enabled(), + 2 => w.compare2_clear().enabled(), + 3 => w.compare3_clear().enabled(), + 4 => w.compare4_clear().enabled(), + 5 => w.compare5_clear().enabled(), + _ => unreachable!("a `Cc` cannot be created with `n > 5`"), + }) + } + + /// Disable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. + pub fn unshort_compare_clear(&self) { + T::regs().shorts.write(|w| match self.n { + 0 => w.compare0_clear().disabled(), + 1 => w.compare1_clear().disabled(), + 2 => w.compare2_clear().disabled(), + 3 => w.compare3_clear().disabled(), + 4 => w.compare4_clear().disabled(), + 5 => w.compare5_clear().disabled(), + _ => unreachable!("a `Cc` cannot be created with `n > 5`"), + }) + } + + /// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task. + /// + /// This means that when the COMPARE event is fired, the STOP task will be triggered. + /// + /// So, when the timer's counter reaches the value stored in this register, the timer will stop counting up. + pub fn short_compare_stop(&self) { + T::regs().shorts.write(|w| match self.n { + 0 => w.compare0_stop().enabled(), + 1 => w.compare1_stop().enabled(), + 2 => w.compare2_stop().enabled(), + 3 => w.compare3_stop().enabled(), + 4 => w.compare4_stop().enabled(), + 5 => w.compare5_stop().enabled(), + _ => unreachable!("a `Cc` cannot be created with `n > 5`"), + }) + } + + /// Disable the shortcut between this CC register's COMPARE event and the timer's STOP task. + pub fn unshort_compare_stop(&self) { + T::regs().shorts.write(|w| match self.n { + 0 => w.compare0_stop().disabled(), + 1 => w.compare1_stop().disabled(), + 2 => w.compare2_stop().disabled(), + 3 => w.compare3_stop().disabled(), + 4 => w.compare4_stop().disabled(), + 5 => w.compare5_stop().disabled(), + _ => unreachable!("a `Cc` cannot be created with `n > 5`"), + }) + } + + /// Wait until the timer's counter reaches the value stored in this register. + pub async fn wait(&self) { + let regs = T::regs(); + + // Enable the interrupt for this CC's COMPARE event. + regs.intenset.write(|w| match self.n { + 0 => w.compare0().set(), + 1 => w.compare1().set(), + 2 => w.compare2().set(), + 3 => w.compare3().set(), + 4 => w.compare4().set(), + 5 => w.compare5().set(), + _ => unreachable!("a `Cc` cannot be created with `n > 5`"), + }); + + // Disable the interrupt if the future is dropped. + let on_drop = OnDrop::new(|| { + regs.intenclr.write(|w| match self.n { + 0 => w.compare0().clear(), + 1 => w.compare1().clear(), + 2 => w.compare2().clear(), + 3 => w.compare3().clear(), + 4 => w.compare4().clear(), + 5 => w.compare5().clear(), + _ => unreachable!("a `Cc` cannot be created with `n > 5`"), + }); + }); + + poll_fn(|cx| { + T::waker(self.n).register(cx.waker()); + + if regs.events_compare[self.n] + .read() + .events_compare() + .is_generated() + { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + + // Trigger the interrupt to be disabled. + drop(on_drop); + } +} diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index de093c7f0..d138257c7 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -18,7 +18,9 @@ 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; // 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}; @@ -287,7 +289,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: T, + timer: Timer<'d, T>, ppi_ch1: Ppi<'d, AnyConfigurableChannel>, _ppi_ch2: Ppi<'d, AnyConfigurableChannel>, } @@ -316,11 +318,11 @@ 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 timer = Timer::new_irqless(timer); - unborrow!(timer, ppi_ch1, ppi_ch2); + unborrow!(ppi_ch1, ppi_ch2); let r = U::regs(); - let rt = timer.regs(); // BAUDRATE register values are `baudrate * 2^32 / 16000000` // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values @@ -330,25 +332,19 @@ impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> { // This gives us the amount of 16M ticks for 20 bits. let timeout = 0x8000_0000 / (baudrate as u32 / 40); - rt.tasks_stop.write(|w| unsafe { w.bits(1) }); - rt.bitmode.write(|w| w.bitmode()._32bit()); - rt.prescaler.write(|w| unsafe { w.prescaler().bits(0) }); - rt.cc[0].write(|w| unsafe { w.bits(timeout) }); - rt.mode.write(|w| w.mode().timer()); - rt.shorts.write(|w| { - w.compare0_clear().set_bit(); - w.compare0_stop().set_bit(); - w - }); + timer.set_frequency(Frequency::F16MHz); + timer.cc0().set(timeout); + timer.cc0().short_compare_clear(); + timer.cc0().short_compare_stop(); let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade_configurable()); ppi_ch1.set_event(Event::from_reg(&r.events_rxdrdy)); - ppi_ch1.set_task(Task::from_reg(&rt.tasks_clear)); - ppi_ch1.set_fork_task(Task::from_reg(&rt.tasks_start)); + ppi_ch1.set_task(timer.task_clear()); + ppi_ch1.set_fork_task(timer.task_start()); ppi_ch1.enable(); let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade_configurable()); - ppi_ch2.set_event(Event::from_reg(&rt.events_compare[0])); + ppi_ch2.set_event(timer.cc0().event_compare()); ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx)); ppi_ch2.enable(); @@ -373,12 +369,10 @@ impl<'d, U: Instance, T: TimerInstance> ReadUntilIdle for UarteWithIdle<'d, U, T let r = U::regs(); let s = U::state(); - let rt = self.timer.regs(); - - let drop = OnDrop::new(move || { + let drop = OnDrop::new(|| { info!("read drop: stopping"); - rt.tasks_stop.write(|w| unsafe { w.bits(1) }); + self.timer.stop(); r.intenclr.write(|w| w.endrx().clear()); r.events_rxto.reset(); @@ -413,7 +407,7 @@ impl<'d, U: Instance, T: TimerInstance> ReadUntilIdle for UarteWithIdle<'d, U, T let n = r.rxd.amount.read().amount().bits() as usize; // Stop timer - rt.tasks_stop.write(|w| unsafe { w.bits(1) }); + self.timer.stop(); r.events_rxstarted.reset(); drop.defuse(); From e7addf094b4d2cfed32ff3728e1d3d816430cf07 Mon Sep 17 00:00:00 2001 From: Liam Murphy Date: Tue, 29 Jun 2021 10:33:41 +1000 Subject: [PATCH 2/8] Fix `Cc::wait` never resolving and refactor some APIs I think the interrupt was getting immediately re-triggered as soon as the handler exited, so I disabled the interrupt in the handler. --- embassy-nrf/src/buffered_uarte.rs | 12 ++-- embassy-nrf/src/timer.rs | 94 +++++++++++++------------------ embassy-nrf/src/uarte.rs | 10 ++-- 3 files changed, 49 insertions(+), 67 deletions(-) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 39a8cd887..a5a37b982 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -82,7 +82,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { let r = U::regs(); - let timer = Timer::new_irqless(timer); + let mut timer = Timer::new_irqless(timer); rxd.conf().write(|w| w.input().connect().drive().h0h1()); r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); @@ -137,9 +137,9 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { let timeout = 0x8000_0000 / (config.baudrate as u32 / 40); timer.set_frequency(Frequency::F16MHz); - timer.cc0().set(timeout); - timer.cc0().short_compare_clear(); - timer.cc0().short_compare_stop(); + timer.cc(0).write(timeout); + timer.cc(0).short_compare_clear(); + timer.cc(0).short_compare_stop(); let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade_configurable()); ppi_ch1.set_event(Event::from_reg(&r.events_rxdrdy)); @@ -148,7 +148,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { ppi_ch1.enable(); let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade_configurable()); - ppi_ch2.set_event(timer.cc0().event_compare()); + ppi_ch2.set_event(timer.cc(0).event_compare()); ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx)); ppi_ch2.enable(); @@ -180,7 +180,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { let r = U::regs(); let timeout = 0x8000_0000 / (baudrate as u32 / 40); - state.timer.cc0().set(timeout); + state.timer.cc(0).write(timeout); state.timer.clear(); r.baudrate.write(|w| w.baudrate().variant(baudrate)); diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 3b2678a0b..d71a5c4e7 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -115,7 +115,7 @@ impl<'d, T: Instance> Timer<'d, T> { // TODO: is there a reason someone would want to set this lower? regs.bitmode.write(|w| w.bitmode()._32bit()); - let this = Self { + let mut this = Self { phantom: PhantomData, }; @@ -125,14 +125,13 @@ impl<'d, T: Instance> Timer<'d, T> { // Initialize the counter at 0. this.clear(); - // Initialize all the shorts as disabled. for n in 0..T::CCS { - let cc = Cc:: { - n, - phantom: PhantomData, - }; + 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 @@ -196,57 +195,36 @@ impl<'d, T: Instance> Timer<'d, T> { .events_compare() .is_generated() { + // 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.write(|w| match n { + 0 => w.compare0().clear(), + 1 => w.compare1().clear(), + 2 => w.compare2().clear(), + 3 => w.compare3().clear(), + 4 => w.compare4().clear(), + 5 => w.compare5().clear(), + _ => unreachable!("No timers have more than 6 CC registers"), + }); T::waker(n).wake(); } } } - /// Returns the 0th CC register. - pub fn cc0<'a>(&'a self) -> Cc<'a, T> { - Cc { - n: 0, - phantom: PhantomData, + /// 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 { + if n >= T::CCS { + panic!( + "Cannot get CC register {} of timer with {} CC registers.", + n, + T::CCS + ); } - } - - /// Returns the 1st CC register. - pub fn cc1<'a>(&'a self) -> Cc<'a, T> { Cc { - n: 1, - phantom: PhantomData, - } - } - - /// Returns the 2nd CC register. - pub fn cc2<'a>(&'a self) -> Cc<'a, T> { - Cc { - n: 2, - phantom: PhantomData, - } - } - - /// Returns the 3rd CC register. - pub fn cc3<'a>(&'a self) -> Cc<'a, T> { - Cc { - n: 3, - phantom: PhantomData, - } - } -} - -impl<'d, T: ExtendedInstance> Timer<'d, T> { - /// Returns the 4th CC register. - pub fn cc4<'a>(&'a self) -> Cc<'a, T> { - Cc { - n: 4, - phantom: PhantomData, - } - } - - /// Returns the 5th CC register. - pub fn cc5<'a>(&'a self) -> Cc<'a, T> { - Cc { - n: 5, + n, phantom: PhantomData, } } @@ -266,14 +244,14 @@ pub struct Cc<'a, T: Instance> { impl<'a, T: Instance> Cc<'a, T> { /// Get the current value stored in the register. - pub fn value(&self) -> u32 { + pub fn read(&self) -> u32 { T::regs().cc[self.n].read().cc().bits() } /// Set the value stored in the register. /// /// `event_compare` will fire when the timer's counter reaches this value. - pub fn set(&self, value: u32) { + pub fn write(&self, value: u32) { // SAFETY: there are no invalid values for the CC register. T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) }) } @@ -281,7 +259,7 @@ impl<'a, T: Instance> Cc<'a, T> { /// Capture the current value of the timer's counter in this register, and return it. pub fn capture(&self) -> u32 { T::regs().tasks_capture[self.n].write(|w| w.tasks_capture().trigger()); - self.value() + self.read() } /// Returns this CC register's CAPTURE task, for use with PPI. @@ -359,7 +337,9 @@ impl<'a, T: Instance> Cc<'a, T> { } /// Wait until the timer's counter reaches the value stored in this register. - pub async fn wait(&self) { + /// + /// 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. @@ -394,6 +374,8 @@ impl<'a, T: Instance> Cc<'a, T> { .events_compare() .is_generated() { + // Reset the register for next time + regs.events_compare[self.n].write(|w| w.events_compare().not_generated()); Poll::Ready(()) } else { Poll::Pending @@ -401,7 +383,7 @@ impl<'a, T: Instance> Cc<'a, T> { }) .await; - // Trigger the interrupt to be disabled. - drop(on_drop); + // The interrupt was already disabled in the interrupt handler, so there's no need to disable it again. + on_drop.defuse(); } } diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index d138257c7..67ec5d73f 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -318,7 +318,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 timer = Timer::new_irqless(timer); + let mut timer = Timer::new_irqless(timer); unborrow!(ppi_ch1, ppi_ch2); @@ -333,9 +333,9 @@ impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> { let timeout = 0x8000_0000 / (baudrate as u32 / 40); timer.set_frequency(Frequency::F16MHz); - timer.cc0().set(timeout); - timer.cc0().short_compare_clear(); - timer.cc0().short_compare_stop(); + timer.cc(0).write(timeout); + timer.cc(0).short_compare_clear(); + timer.cc(0).short_compare_stop(); let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade_configurable()); ppi_ch1.set_event(Event::from_reg(&r.events_rxdrdy)); @@ -344,7 +344,7 @@ impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> { ppi_ch1.enable(); let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade_configurable()); - ppi_ch2.set_event(timer.cc0().event_compare()); + ppi_ch2.set_event(timer.cc(0).event_compare()); ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx)); ppi_ch2.enable(); From e5a5031f204c2c63912beba1c340c27d01d54672 Mon Sep 17 00:00:00 2001 From: Liam Murphy Date: Tue, 29 Jun 2021 11:29:32 +1000 Subject: [PATCH 3/8] Get rid of the TODO about variant names, stop the timer before setting BITMODE and set a default frequency. --- embassy-nrf/src/timer.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index d71a5c4e7..02f02bc17 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -64,7 +64,7 @@ macro_rules! impl_timer { #[repr(u8)] pub enum Frequency { - // TODO: These variant names are terrible, what should they be? + // I'd prefer not to prefix these with `F`, but Rust identifiers can't start with digits. F16MHz = 0, F8MHz = 1, F4MHz = 2, @@ -108,6 +108,14 @@ impl<'d, T: Instance> Timer<'d, T> { pub(crate) fn new_irqless(_timer: impl Unborrow + 'd) -> Self { let regs = T::regs(); + let mut this = Self { + phantom: 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()); @@ -115,16 +123,12 @@ impl<'d, T: Instance> Timer<'d, T> { // TODO: is there a reason someone would want to set this lower? regs.bitmode.write(|w| w.bitmode()._32bit()); - let mut this = Self { - phantom: PhantomData, - }; - - // Initialize the timer as stopped. - this.stop(); - // 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. From 94e13ef053d788238899bffb8f4fc450101b78ee Mon Sep 17 00:00:00 2001 From: Liam Murphy Date: Tue, 29 Jun 2021 11:39:50 +1000 Subject: [PATCH 4/8] Fix `Cc::event_compare` --- embassy-nrf/src/timer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 02f02bc17..a96c6a823 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -277,7 +277,7 @@ impl<'a, T: Instance> Cc<'a, T> { /// /// This event will fire when the timer's counter reaches the value in this CC register. pub fn event_compare(&self) -> Event { - Event::from_reg(&T::regs().events_compare) + Event::from_reg(&T::regs().events_compare[self.n]) } /// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. From 0c0597f775e3197b87e9370f390ccc3814b637a1 Mon Sep 17 00:00:00 2001 From: Liam Murphy Date: Tue, 29 Jun 2021 12:07:10 +1000 Subject: [PATCH 5/8] Don't include extended timer support on chips without it --- embassy-nrf/src/timer.rs | 84 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index a96c6a823..0f37a6d65 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -206,7 +206,19 @@ impl<'d, T: Instance> Timer<'d, T> { 1 => w.compare1().clear(), 2 => w.compare2().clear(), 3 => w.compare3().clear(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 4 => w.compare4().clear(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 5 => w.compare5().clear(), _ => unreachable!("No timers have more than 6 CC registers"), }); @@ -291,7 +303,19 @@ impl<'a, T: Instance> Cc<'a, T> { 1 => w.compare1_clear().enabled(), 2 => w.compare2_clear().enabled(), 3 => w.compare3_clear().enabled(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 4 => w.compare4_clear().enabled(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 5 => w.compare5_clear().enabled(), _ => unreachable!("a `Cc` cannot be created with `n > 5`"), }) @@ -304,7 +328,19 @@ impl<'a, T: Instance> Cc<'a, T> { 1 => w.compare1_clear().disabled(), 2 => w.compare2_clear().disabled(), 3 => w.compare3_clear().disabled(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 4 => w.compare4_clear().disabled(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 5 => w.compare5_clear().disabled(), _ => unreachable!("a `Cc` cannot be created with `n > 5`"), }) @@ -321,7 +357,19 @@ impl<'a, T: Instance> Cc<'a, T> { 1 => w.compare1_stop().enabled(), 2 => w.compare2_stop().enabled(), 3 => w.compare3_stop().enabled(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 4 => w.compare4_stop().enabled(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 5 => w.compare5_stop().enabled(), _ => unreachable!("a `Cc` cannot be created with `n > 5`"), }) @@ -334,7 +382,19 @@ impl<'a, T: Instance> Cc<'a, T> { 1 => w.compare1_stop().disabled(), 2 => w.compare2_stop().disabled(), 3 => w.compare3_stop().disabled(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 4 => w.compare4_stop().disabled(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 5 => w.compare5_stop().disabled(), _ => unreachable!("a `Cc` cannot be created with `n > 5`"), }) @@ -352,7 +412,19 @@ impl<'a, T: Instance> Cc<'a, T> { 1 => w.compare1().set(), 2 => w.compare2().set(), 3 => w.compare3().set(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 4 => w.compare4().set(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 5 => w.compare5().set(), _ => unreachable!("a `Cc` cannot be created with `n > 5`"), }); @@ -364,7 +436,19 @@ impl<'a, T: Instance> Cc<'a, T> { 1 => w.compare1().clear(), 2 => w.compare2().clear(), 3 => w.compare3().clear(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 4 => w.compare4().clear(), + #[cfg(any( + feature = "nrf52805", + feature = "nrf52811", + feature = "nrf52820", + feature = "nrf52833", + ))] 5 => w.compare5().clear(), _ => unreachable!("a `Cc` cannot be created with `n > 5`"), }); From 87ca902e44099266b1de709857ba7d44bc4b471b Mon Sep 17 00:00:00 2001 From: Liam Murphy Date: Tue, 29 Jun 2021 13:04:05 +1000 Subject: [PATCH 6/8] Handle differences between PACs --- embassy-nrf/src/timer.rs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 0f37a6d65..055c1d881 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -143,17 +143,17 @@ impl<'d, T: Instance> Timer<'d, T> { /// Starts the timer. pub fn start(&self) { - T::regs().tasks_start.write(|w| w.tasks_start().trigger()) + T::regs().tasks_start.write(|w| unsafe { w.bits(1) }) } /// Stops the timer. pub fn stop(&self) { - T::regs().tasks_stop.write(|w| w.tasks_stop().trigger()) + 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| w.tasks_clear().trigger()) + T::regs().tasks_clear.write(|w| unsafe { w.bits(1) }) } /// Returns the START task, for use with PPI. @@ -194,11 +194,7 @@ impl<'d, T: Instance> Timer<'d, T> { fn on_interrupt(_: *mut ()) { let regs = T::regs(); for n in 0..T::CCS { - if regs.events_compare[n] - .read() - .events_compare() - .is_generated() - { + 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.write(|w| match n { @@ -274,7 +270,7 @@ impl<'a, T: Instance> Cc<'a, T> { /// Capture the current value of the timer's counter in this register, and return it. pub fn capture(&self) -> u32 { - T::regs().tasks_capture[self.n].write(|w| w.tasks_capture().trigger()); + T::regs().tasks_capture[self.n].write(|w| unsafe { w.bits(1) }); self.read() } @@ -457,13 +453,9 @@ impl<'a, T: Instance> Cc<'a, T> { poll_fn(|cx| { T::waker(self.n).register(cx.waker()); - if regs.events_compare[self.n] - .read() - .events_compare() - .is_generated() - { + if regs.events_compare[self.n].read().bits() != 0 { // Reset the register for next time - regs.events_compare[self.n].write(|w| w.events_compare().not_generated()); + regs.events_compare[self.n].reset(); Poll::Ready(()) } else { Poll::Pending From e6d0dba5ca6f986f6d4cd20df5334fe824c40dde Mon Sep 17 00:00:00 2001 From: Liam Murphy Date: Tue, 29 Jun 2021 14:37:37 +1000 Subject: [PATCH 7/8] Write bits directly to intenset/clr + shorts --- embassy-nrf/src/timer.rs | 165 +++++---------------------------------- 1 file changed, 18 insertions(+), 147 deletions(-) diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 055c1d881..9c04e1580 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -197,27 +197,8 @@ impl<'d, T: Instance> Timer<'d, T> { 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.write(|w| match n { - 0 => w.compare0().clear(), - 1 => w.compare1().clear(), - 2 => w.compare2().clear(), - 3 => w.compare3().clear(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 4 => w.compare4().clear(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 5 => w.compare5().clear(), - _ => unreachable!("No timers have more than 6 CC registers"), - }); + regs.intenclr + .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + n))) }); T::waker(n).wake(); } } @@ -294,52 +275,16 @@ impl<'a, T: Instance> Cc<'a, T> { /// /// So, when the timer's counter reaches the value stored in this register, the timer's counter will be reset to 0. pub fn short_compare_clear(&self) { - T::regs().shorts.write(|w| match self.n { - 0 => w.compare0_clear().enabled(), - 1 => w.compare1_clear().enabled(), - 2 => w.compare2_clear().enabled(), - 3 => w.compare3_clear().enabled(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 4 => w.compare4_clear().enabled(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 5 => w.compare5_clear().enabled(), - _ => unreachable!("a `Cc` cannot be created with `n > 5`"), - }) + T::regs() + .shorts + .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.n)) }) } /// Disable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. pub fn unshort_compare_clear(&self) { - T::regs().shorts.write(|w| match self.n { - 0 => w.compare0_clear().disabled(), - 1 => w.compare1_clear().disabled(), - 2 => w.compare2_clear().disabled(), - 3 => w.compare3_clear().disabled(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 4 => w.compare4_clear().disabled(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 5 => w.compare5_clear().disabled(), - _ => unreachable!("a `Cc` cannot be created with `n > 5`"), - }) + T::regs() + .shorts + .modify(|r, w| unsafe { w.bits(r.bits() & (0 << self.n)) }) } /// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task. @@ -348,52 +293,16 @@ impl<'a, T: Instance> Cc<'a, T> { /// /// So, when the timer's counter reaches the value stored in this register, the timer will stop counting up. pub fn short_compare_stop(&self) { - T::regs().shorts.write(|w| match self.n { - 0 => w.compare0_stop().enabled(), - 1 => w.compare1_stop().enabled(), - 2 => w.compare2_stop().enabled(), - 3 => w.compare3_stop().enabled(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 4 => w.compare4_stop().enabled(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 5 => w.compare5_stop().enabled(), - _ => unreachable!("a `Cc` cannot be created with `n > 5`"), - }) + T::regs() + .shorts + .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (8 + self.n))) }) } /// Disable the shortcut between this CC register's COMPARE event and the timer's STOP task. pub fn unshort_compare_stop(&self) { - T::regs().shorts.write(|w| match self.n { - 0 => w.compare0_stop().disabled(), - 1 => w.compare1_stop().disabled(), - 2 => w.compare2_stop().disabled(), - 3 => w.compare3_stop().disabled(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 4 => w.compare4_stop().disabled(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 5 => w.compare5_stop().disabled(), - _ => unreachable!("a `Cc` cannot be created with `n > 5`"), - }) + T::regs() + .shorts + .modify(|r, w| unsafe { w.bits(r.bits() & (0 << (8 + self.n))) }) } /// Wait until the timer's counter reaches the value stored in this register. @@ -403,51 +312,13 @@ impl<'a, T: Instance> Cc<'a, T> { let regs = T::regs(); // Enable the interrupt for this CC's COMPARE event. - regs.intenset.write(|w| match self.n { - 0 => w.compare0().set(), - 1 => w.compare1().set(), - 2 => w.compare2().set(), - 3 => w.compare3().set(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 4 => w.compare4().set(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 5 => w.compare5().set(), - _ => unreachable!("a `Cc` cannot be created with `n > 5`"), - }); + 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.write(|w| match self.n { - 0 => w.compare0().clear(), - 1 => w.compare1().clear(), - 2 => w.compare2().clear(), - 3 => w.compare3().clear(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 4 => w.compare4().clear(), - #[cfg(any( - feature = "nrf52805", - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - ))] - 5 => w.compare5().clear(), - _ => unreachable!("a `Cc` cannot be created with `n > 5`"), - }); + regs.intenclr + .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) }); }); poll_fn(|cx| { From c0ef40d6e9ee91ef754e90424ecd76fd80c0f125 Mon Sep 17 00:00:00 2001 From: Liam Murphy Date: Tue, 29 Jun 2021 15:12:42 +1000 Subject: [PATCH 8/8] Correctly unset bits --- embassy-nrf/src/timer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 9c04e1580..a6e91f228 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -284,7 +284,7 @@ impl<'a, T: Instance> Cc<'a, T> { pub fn unshort_compare_clear(&self) { T::regs() .shorts - .modify(|r, w| unsafe { w.bits(r.bits() & (0 << self.n)) }) + .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.n)) }) } /// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task. @@ -302,7 +302,7 @@ impl<'a, T: Instance> Cc<'a, T> { pub fn unshort_compare_stop(&self) { T::regs() .shorts - .modify(|r, w| unsafe { w.bits(r.bits() & (0 << (8 + self.n))) }) + .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << (8 + self.n))) }) } /// Wait until the timer's counter reaches the value stored in this register.