diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-06-29 07:37:06 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-06-29 07:37:06 +0200 |
| commit | d49adc98beebe5b7982204150ebdc0a485fefab2 (patch) | |
| tree | 4c51df41daf9b180eecbe584b50a46163aade0ce | |
| parent | f501907f9e69c1d47571b6e0980f22dde723b45d (diff) | |
| parent | c0ef40d6e9ee91ef754e90424ecd76fd80c0f125 (diff) | |
Merge pull request #260 from Liamolucko/nrf-timer
Add an nRF Timer driver
| -rw-r--r-- | embassy-nrf/src/buffered_uarte.rs | 40 | ||||
| -rw-r--r-- | embassy-nrf/src/timer.rs | 310 | ||||
| -rw-r--r-- | embassy-nrf/src/uarte.rs | 36 |
3 files changed, 338 insertions, 48 deletions
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 517afa38c..a5a37b982 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 _; | |||
| 15 | use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin}; | 15 | use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin}; |
| 16 | use crate::pac; | 16 | use crate::pac; |
| 17 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | 17 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; |
| 18 | use crate::timer::Frequency; | ||
| 18 | use crate::timer::Instance as TimerInstance; | 19 | use crate::timer::Instance as TimerInstance; |
| 20 | use crate::timer::Timer; | ||
| 19 | use crate::uarte::{Config, Instance as UarteInstance}; | 21 | use crate::uarte::{Config, Instance as UarteInstance}; |
| 20 | 22 | ||
| 21 | // Re-export SVD variants to allow user to directly set values | 23 | // Re-export SVD variants to allow user to directly set values |
| @@ -35,7 +37,7 @@ enum TxState { | |||
| 35 | 37 | ||
| 36 | struct State<'d, U: UarteInstance, T: TimerInstance> { | 38 | struct State<'d, U: UarteInstance, T: TimerInstance> { |
| 37 | phantom: PhantomData<&'d mut U>, | 39 | phantom: PhantomData<&'d mut U>, |
| 38 | timer: T, | 40 | timer: Timer<'d, T>, |
| 39 | _ppi_ch1: Ppi<'d, AnyConfigurableChannel>, | 41 | _ppi_ch1: Ppi<'d, AnyConfigurableChannel>, |
| 40 | _ppi_ch2: Ppi<'d, AnyConfigurableChannel>, | 42 | _ppi_ch2: Ppi<'d, AnyConfigurableChannel>, |
| 41 | 43 | ||
| @@ -76,10 +78,11 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | |||
| 76 | rx_buffer: &'d mut [u8], | 78 | rx_buffer: &'d mut [u8], |
| 77 | tx_buffer: &'d mut [u8], | 79 | tx_buffer: &'d mut [u8], |
| 78 | ) -> Self { | 80 | ) -> Self { |
| 79 | unborrow!(timer, ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts); | 81 | unborrow!(ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts); |
| 80 | 82 | ||
| 81 | let r = U::regs(); | 83 | let r = U::regs(); |
| 82 | let rt = timer.regs(); | 84 | |
| 85 | let mut timer = Timer::new_irqless(timer); | ||
| 83 | 86 | ||
| 84 | rxd.conf().write(|w| w.input().connect().drive().h0h1()); | 87 | rxd.conf().write(|w| w.input().connect().drive().h0h1()); |
| 85 | r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); | 88 | 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> { | |||
| 133 | // This gives us the amount of 16M ticks for 20 bits. | 136 | // This gives us the amount of 16M ticks for 20 bits. |
| 134 | let timeout = 0x8000_0000 / (config.baudrate as u32 / 40); | 137 | let timeout = 0x8000_0000 / (config.baudrate as u32 / 40); |
| 135 | 138 | ||
| 136 | rt.tasks_stop.write(|w| unsafe { w.bits(1) }); | 139 | timer.set_frequency(Frequency::F16MHz); |
| 137 | rt.bitmode.write(|w| w.bitmode()._32bit()); | 140 | timer.cc(0).write(timeout); |
| 138 | rt.prescaler.write(|w| unsafe { w.prescaler().bits(0) }); | 141 | timer.cc(0).short_compare_clear(); |
| 139 | rt.cc[0].write(|w| unsafe { w.bits(timeout) }); | 142 | timer.cc(0).short_compare_stop(); |
| 140 | rt.mode.write(|w| w.mode().timer()); | ||
| 141 | rt.shorts.write(|w| { | ||
| 142 | w.compare0_clear().set_bit(); | ||
| 143 | w.compare0_stop().set_bit(); | ||
| 144 | w | ||
| 145 | }); | ||
| 146 | 143 | ||
| 147 | let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade_configurable()); | 144 | let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade_configurable()); |
| 148 | ppi_ch1.set_event(Event::from_reg(&r.events_rxdrdy)); | 145 | ppi_ch1.set_event(Event::from_reg(&r.events_rxdrdy)); |
| 149 | ppi_ch1.set_task(Task::from_reg(&rt.tasks_clear)); | 146 | ppi_ch1.set_task(timer.task_clear()); |
| 150 | ppi_ch1.set_fork_task(Task::from_reg(&rt.tasks_start)); | 147 | ppi_ch1.set_fork_task(timer.task_start()); |
| 151 | ppi_ch1.enable(); | 148 | ppi_ch1.enable(); |
| 152 | 149 | ||
| 153 | let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade_configurable()); | 150 | let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade_configurable()); |
| 154 | ppi_ch2.set_event(Event::from_reg(&rt.events_compare[0])); | 151 | ppi_ch2.set_event(timer.cc(0).event_compare()); |
| 155 | ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx)); | 152 | ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx)); |
| 156 | ppi_ch2.enable(); | 153 | ppi_ch2.enable(); |
| 157 | 154 | ||
| @@ -181,11 +178,10 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | |||
| 181 | inner.as_mut().register_interrupt(); | 178 | inner.as_mut().register_interrupt(); |
| 182 | inner.with(|state, _irq| { | 179 | inner.with(|state, _irq| { |
| 183 | let r = U::regs(); | 180 | let r = U::regs(); |
| 184 | let rt = state.timer.regs(); | ||
| 185 | 181 | ||
| 186 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); | 182 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); |
| 187 | rt.cc[0].write(|w| unsafe { w.bits(timeout) }); | 183 | state.timer.cc(0).write(timeout); |
| 188 | rt.tasks_clear.write(|w| unsafe { w.bits(1) }); | 184 | state.timer.clear(); |
| 189 | 185 | ||
| 190 | r.baudrate.write(|w| w.baudrate().variant(baudrate)); | 186 | r.baudrate.write(|w| w.baudrate().variant(baudrate)); |
| 191 | }); | 187 | }); |
| @@ -268,11 +264,10 @@ impl<'d, U: UarteInstance, T: TimerInstance> AsyncWrite for BufferedUarte<'d, U, | |||
| 268 | impl<'a, U: UarteInstance, T: TimerInstance> Drop for State<'a, U, T> { | 264 | impl<'a, U: UarteInstance, T: TimerInstance> Drop for State<'a, U, T> { |
| 269 | fn drop(&mut self) { | 265 | fn drop(&mut self) { |
| 270 | let r = U::regs(); | 266 | let r = U::regs(); |
| 271 | let rt = self.timer.regs(); | ||
| 272 | 267 | ||
| 273 | // TODO this probably deadlocks. do like Uarte instead. | 268 | // TODO this probably deadlocks. do like Uarte instead. |
| 274 | 269 | ||
| 275 | rt.tasks_stop.write(|w| unsafe { w.bits(1) }); | 270 | self.timer.stop(); |
| 276 | if let RxState::Receiving = self.rx_state { | 271 | if let RxState::Receiving = self.rx_state { |
| 277 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | 272 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); |
| 278 | } | 273 | } |
| @@ -293,7 +288,6 @@ impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for State<'a, U, T> | |||
| 293 | fn on_interrupt(&mut self) { | 288 | fn on_interrupt(&mut self) { |
| 294 | trace!("irq: start"); | 289 | trace!("irq: start"); |
| 295 | let r = U::regs(); | 290 | let r = U::regs(); |
| 296 | let rt = self.timer.regs(); | ||
| 297 | 291 | ||
| 298 | loop { | 292 | loop { |
| 299 | match self.rx_state { | 293 | match self.rx_state { |
| @@ -330,7 +324,7 @@ impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for State<'a, U, T> | |||
| 330 | RxState::Receiving => { | 324 | RxState::Receiving => { |
| 331 | trace!(" irq_rx: in state receiving"); | 325 | trace!(" irq_rx: in state receiving"); |
| 332 | if r.events_endrx.read().bits() != 0 { | 326 | if r.events_endrx.read().bits() != 0 { |
| 333 | rt.tasks_stop.write(|w| unsafe { w.bits(1) }); | 327 | self.timer.stop(); |
| 334 | 328 | ||
| 335 | let n: usize = r.rxd.amount.read().amount().bits() as usize; | 329 | let n: usize = r.rxd.amount.read().amount().bits() as usize; |
| 336 | trace!(" irq_rx: endrx {:?}", n); | 330 | trace!(" irq_rx: endrx {:?}", n); |
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 2490bfd93..a6e91f228 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs | |||
| @@ -1,15 +1,30 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | use core::marker::PhantomData; | ||
| 4 | use core::task::Poll; | ||
| 5 | |||
| 3 | use embassy::interrupt::Interrupt; | 6 | use embassy::interrupt::Interrupt; |
| 7 | use embassy::interrupt::InterruptExt; | ||
| 8 | use embassy::util::OnDrop; | ||
| 4 | use embassy::util::Unborrow; | 9 | use embassy::util::Unborrow; |
| 10 | use embassy_extras::unborrow; | ||
| 11 | use futures::future::poll_fn; | ||
| 5 | 12 | ||
| 6 | use crate::pac; | 13 | use crate::pac; |
| 14 | use crate::ppi::Event; | ||
| 15 | use crate::ppi::Task; | ||
| 7 | 16 | ||
| 8 | pub(crate) mod sealed { | 17 | pub(crate) mod sealed { |
| 18 | use embassy::util::AtomicWaker; | ||
| 19 | |||
| 9 | use super::*; | 20 | use super::*; |
| 10 | 21 | ||
| 11 | pub trait Instance { | 22 | pub trait Instance { |
| 12 | fn regs(&self) -> &pac::timer0::RegisterBlock; | 23 | /// The number of CC registers this instance has. |
| 24 | const CCS: usize; | ||
| 25 | fn regs() -> &'static pac::timer0::RegisterBlock; | ||
| 26 | /// Storage for the waker for CC register `n`. | ||
| 27 | fn waker(n: usize) -> &'static AtomicWaker; | ||
| 13 | } | 28 | } |
| 14 | pub trait ExtendedInstance {} | 29 | pub trait ExtendedInstance {} |
| 15 | } | 30 | } |
| @@ -20,19 +35,306 @@ pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static { | |||
| 20 | pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} | 35 | pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} |
| 21 | 36 | ||
| 22 | macro_rules! impl_timer { | 37 | macro_rules! impl_timer { |
| 23 | ($type:ident, $pac_type:ident, $irq:ident) => { | 38 | ($type:ident, $pac_type:ident, $irq:ident, $ccs:literal) => { |
| 24 | impl crate::timer::sealed::Instance for peripherals::$type { | 39 | impl crate::timer::sealed::Instance for peripherals::$type { |
| 25 | fn regs(&self) -> &pac::timer0::RegisterBlock { | 40 | const CCS: usize = $ccs; |
| 41 | fn regs() -> &'static pac::timer0::RegisterBlock { | ||
| 26 | unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } | 42 | unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } |
| 27 | } | 43 | } |
| 44 | fn waker(n: usize) -> &'static ::embassy::util::AtomicWaker { | ||
| 45 | use ::embassy::util::AtomicWaker; | ||
| 46 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | ||
| 47 | static WAKERS: [AtomicWaker; $ccs] = [NEW_AW; $ccs]; | ||
| 48 | &WAKERS[n] | ||
| 49 | } | ||
| 28 | } | 50 | } |
| 29 | impl crate::timer::Instance for peripherals::$type { | 51 | impl crate::timer::Instance for peripherals::$type { |
| 30 | type Interrupt = crate::interrupt::$irq; | 52 | type Interrupt = crate::interrupt::$irq; |
| 31 | } | 53 | } |
| 32 | }; | 54 | }; |
| 55 | ($type:ident, $pac_type:ident, $irq:ident) => { | ||
| 56 | impl_timer!($type, $pac_type, $irq, 4); | ||
| 57 | }; | ||
| 33 | ($type:ident, $pac_type:ident, $irq:ident, extended) => { | 58 | ($type:ident, $pac_type:ident, $irq:ident, extended) => { |
| 34 | impl_timer!($type, $pac_type, $irq); | 59 | impl_timer!($type, $pac_type, $irq, 6); |
| 35 | impl crate::timer::sealed::ExtendedInstance for peripherals::$type {} | 60 | impl crate::timer::sealed::ExtendedInstance for peripherals::$type {} |
| 36 | impl crate::timer::ExtendedInstance for peripherals::$type {} | 61 | impl crate::timer::ExtendedInstance for peripherals::$type {} |
| 37 | }; | 62 | }; |
| 38 | } | 63 | } |
| 64 | |||
| 65 | #[repr(u8)] | ||
| 66 | pub enum Frequency { | ||
| 67 | // I'd prefer not to prefix these with `F`, but Rust identifiers can't start with digits. | ||
| 68 | F16MHz = 0, | ||
| 69 | F8MHz = 1, | ||
| 70 | F4MHz = 2, | ||
| 71 | F2MHz = 3, | ||
| 72 | F1MHz = 4, | ||
| 73 | F500kHz = 5, | ||
| 74 | F250kHz = 6, | ||
| 75 | F125kHz = 7, | ||
| 76 | F62500Hz = 8, | ||
| 77 | F31250Hz = 9, | ||
| 78 | } | ||
| 79 | |||
| 80 | /// nRF Timer driver. | ||
| 81 | /// | ||
| 82 | /// The timer has an internal counter, which is incremented for every tick of the timer. | ||
| 83 | /// The counter is 32-bit, so it wraps back to 0 at 4294967296. | ||
| 84 | /// | ||
| 85 | /// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter | ||
| 86 | /// or trigger an event when the counter reaches a certain value. | ||
| 87 | pub struct Timer<'d, T: Instance> { | ||
| 88 | phantom: PhantomData<&'d mut T>, | ||
| 89 | } | ||
| 90 | |||
| 91 | impl<'d, T: Instance> Timer<'d, T> { | ||
| 92 | pub fn new( | ||
| 93 | timer: impl Unborrow<Target = T> + 'd, | ||
| 94 | irq: impl Unborrow<Target = T::Interrupt> + 'd, | ||
| 95 | ) -> Self { | ||
| 96 | unborrow!(irq); | ||
| 97 | |||
| 98 | irq.set_handler(Self::on_interrupt); | ||
| 99 | irq.unpend(); | ||
| 100 | irq.enable(); | ||
| 101 | |||
| 102 | Self::new_irqless(timer) | ||
| 103 | } | ||
| 104 | |||
| 105 | /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work. | ||
| 106 | /// | ||
| 107 | /// This is used by `Uarte` internally. | ||
| 108 | pub(crate) fn new_irqless(_timer: impl Unborrow<Target = T> + 'd) -> Self { | ||
| 109 | let regs = T::regs(); | ||
| 110 | |||
| 111 | let mut this = Self { | ||
| 112 | phantom: PhantomData, | ||
| 113 | }; | ||
| 114 | |||
| 115 | // Stop the timer before doing anything else, | ||
| 116 | // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. | ||
| 117 | this.stop(); | ||
| 118 | |||
| 119 | // Set the instance to timer mode. | ||
| 120 | regs.mode.write(|w| w.mode().timer()); | ||
| 121 | |||
| 122 | // Make the counter's max value as high as possible. | ||
| 123 | // TODO: is there a reason someone would want to set this lower? | ||
| 124 | regs.bitmode.write(|w| w.bitmode()._32bit()); | ||
| 125 | |||
| 126 | // Initialize the counter at 0. | ||
| 127 | this.clear(); | ||
| 128 | |||
| 129 | // Default to the max frequency of the lower power clock | ||
| 130 | this.set_frequency(Frequency::F1MHz); | ||
| 131 | |||
| 132 | for n in 0..T::CCS { | ||
| 133 | let cc = this.cc(n); | ||
| 134 | // Initialize all the shorts as disabled. | ||
| 135 | cc.unshort_compare_clear(); | ||
| 136 | cc.unshort_compare_stop(); | ||
| 137 | // Initialize the CC registers as 0. | ||
| 138 | cc.write(0); | ||
| 139 | } | ||
| 140 | |||
| 141 | this | ||
| 142 | } | ||
| 143 | |||
| 144 | /// Starts the timer. | ||
| 145 | pub fn start(&self) { | ||
| 146 | T::regs().tasks_start.write(|w| unsafe { w.bits(1) }) | ||
| 147 | } | ||
| 148 | |||
| 149 | /// Stops the timer. | ||
| 150 | pub fn stop(&self) { | ||
| 151 | T::regs().tasks_stop.write(|w| unsafe { w.bits(1) }) | ||
| 152 | } | ||
| 153 | |||
| 154 | /// Reset the timer's counter to 0. | ||
| 155 | pub fn clear(&self) { | ||
| 156 | T::regs().tasks_clear.write(|w| unsafe { w.bits(1) }) | ||
| 157 | } | ||
| 158 | |||
| 159 | /// Returns the START task, for use with PPI. | ||
| 160 | /// | ||
| 161 | /// When triggered, this task starts the timer. | ||
| 162 | pub fn task_start(&self) -> Task { | ||
| 163 | Task::from_reg(&T::regs().tasks_start) | ||
| 164 | } | ||
| 165 | |||
| 166 | /// Returns the STOP task, for use with PPI. | ||
| 167 | /// | ||
| 168 | /// When triggered, this task stops the timer. | ||
| 169 | pub fn task_stop(&self) -> Task { | ||
| 170 | Task::from_reg(&T::regs().tasks_stop) | ||
| 171 | } | ||
| 172 | |||
| 173 | /// Returns the CLEAR task, for use with PPI. | ||
| 174 | /// | ||
| 175 | /// When triggered, this task resets the timer's counter to 0. | ||
| 176 | pub fn task_clear(&self) -> Task { | ||
| 177 | Task::from_reg(&T::regs().tasks_clear) | ||
| 178 | } | ||
| 179 | |||
| 180 | /// Change the timer's frequency. | ||
| 181 | /// | ||
| 182 | /// This will stop the timer if it isn't already stopped, | ||
| 183 | /// because the timer may exhibit 'unpredictable behaviour' if it's frequency is changed while it's running. | ||
| 184 | pub fn set_frequency(&self, frequency: Frequency) { | ||
| 185 | self.stop(); | ||
| 186 | |||
| 187 | T::regs() | ||
| 188 | .prescaler | ||
| 189 | // SAFETY: `frequency` is a variant of `Frequency`, | ||
| 190 | // whose values are all in the range of 0-9 (the valid range of `prescaler`). | ||
| 191 | .write(|w| unsafe { w.prescaler().bits(frequency as u8) }) | ||
| 192 | } | ||
| 193 | |||
| 194 | fn on_interrupt(_: *mut ()) { | ||
| 195 | let regs = T::regs(); | ||
| 196 | for n in 0..T::CCS { | ||
| 197 | if regs.events_compare[n].read().bits() != 0 { | ||
| 198 | // Clear the interrupt, otherwise the interrupt will be repeatedly raised as soon as the interrupt handler exits. | ||
| 199 | // We can't clear the event, because it's used to poll whether the future is done or still pending. | ||
| 200 | regs.intenclr | ||
| 201 | .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + n))) }); | ||
| 202 | T::waker(n).wake(); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | /// Returns this timer's `n`th CC register. | ||
| 208 | /// | ||
| 209 | /// # Panics | ||
| 210 | /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer). | ||
| 211 | pub fn cc(&mut self, n: usize) -> Cc<T> { | ||
| 212 | if n >= T::CCS { | ||
| 213 | panic!( | ||
| 214 | "Cannot get CC register {} of timer with {} CC registers.", | ||
| 215 | n, | ||
| 216 | T::CCS | ||
| 217 | ); | ||
| 218 | } | ||
| 219 | Cc { | ||
| 220 | n, | ||
| 221 | phantom: PhantomData, | ||
| 222 | } | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | /// A representation of a timer's Capture/Compare (CC) register. | ||
| 227 | /// | ||
| 228 | /// A CC register holds a 32-bit value. | ||
| 229 | /// 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. | ||
| 230 | /// | ||
| 231 | /// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register. | ||
| 232 | /// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register | ||
| 233 | pub struct Cc<'a, T: Instance> { | ||
| 234 | n: usize, | ||
| 235 | phantom: PhantomData<&'a mut T>, | ||
| 236 | } | ||
| 237 | |||
| 238 | impl<'a, T: Instance> Cc<'a, T> { | ||
| 239 | /// Get the current value stored in the register. | ||
| 240 | pub fn read(&self) -> u32 { | ||
| 241 | T::regs().cc[self.n].read().cc().bits() | ||
| 242 | } | ||
| 243 | |||
| 244 | /// Set the value stored in the register. | ||
| 245 | /// | ||
| 246 | /// `event_compare` will fire when the timer's counter reaches this value. | ||
| 247 | pub fn write(&self, value: u32) { | ||
| 248 | // SAFETY: there are no invalid values for the CC register. | ||
| 249 | T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) }) | ||
| 250 | } | ||
| 251 | |||
| 252 | /// Capture the current value of the timer's counter in this register, and return it. | ||
| 253 | pub fn capture(&self) -> u32 { | ||
| 254 | T::regs().tasks_capture[self.n].write(|w| unsafe { w.bits(1) }); | ||
| 255 | self.read() | ||
| 256 | } | ||
| 257 | |||
| 258 | /// Returns this CC register's CAPTURE task, for use with PPI. | ||
| 259 | /// | ||
| 260 | /// When triggered, this task will capture the current value of the timer's counter in this register. | ||
| 261 | pub fn task_capture(&self) -> Task { | ||
| 262 | Task::from_reg(&T::regs().tasks_capture[self.n]) | ||
| 263 | } | ||
| 264 | |||
| 265 | /// Returns this CC register's COMPARE event, for use with PPI. | ||
| 266 | /// | ||
| 267 | /// This event will fire when the timer's counter reaches the value in this CC register. | ||
| 268 | pub fn event_compare(&self) -> Event { | ||
| 269 | Event::from_reg(&T::regs().events_compare[self.n]) | ||
| 270 | } | ||
| 271 | |||
| 272 | /// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. | ||
| 273 | /// | ||
| 274 | /// This means that when the COMPARE event is fired, the CLEAR task will be triggered. | ||
| 275 | /// | ||
| 276 | /// So, when the timer's counter reaches the value stored in this register, the timer's counter will be reset to 0. | ||
| 277 | pub fn short_compare_clear(&self) { | ||
| 278 | T::regs() | ||
| 279 | .shorts | ||
| 280 | .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.n)) }) | ||
| 281 | } | ||
| 282 | |||
| 283 | /// Disable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. | ||
| 284 | pub fn unshort_compare_clear(&self) { | ||
| 285 | T::regs() | ||
| 286 | .shorts | ||
| 287 | .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.n)) }) | ||
| 288 | } | ||
| 289 | |||
| 290 | /// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task. | ||
| 291 | /// | ||
| 292 | /// This means that when the COMPARE event is fired, the STOP task will be triggered. | ||
| 293 | /// | ||
| 294 | /// So, when the timer's counter reaches the value stored in this register, the timer will stop counting up. | ||
| 295 | pub fn short_compare_stop(&self) { | ||
| 296 | T::regs() | ||
| 297 | .shorts | ||
| 298 | .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (8 + self.n))) }) | ||
| 299 | } | ||
| 300 | |||
| 301 | /// Disable the shortcut between this CC register's COMPARE event and the timer's STOP task. | ||
| 302 | pub fn unshort_compare_stop(&self) { | ||
| 303 | T::regs() | ||
| 304 | .shorts | ||
| 305 | .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << (8 + self.n))) }) | ||
| 306 | } | ||
| 307 | |||
| 308 | /// Wait until the timer's counter reaches the value stored in this register. | ||
| 309 | /// | ||
| 310 | /// This requires a mutable reference so that this task's waker cannot be overwritten by a second call to `wait`. | ||
| 311 | pub async fn wait(&mut self) { | ||
| 312 | let regs = T::regs(); | ||
| 313 | |||
| 314 | // Enable the interrupt for this CC's COMPARE event. | ||
| 315 | regs.intenset | ||
| 316 | .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) }); | ||
| 317 | |||
| 318 | // Disable the interrupt if the future is dropped. | ||
| 319 | let on_drop = OnDrop::new(|| { | ||
| 320 | regs.intenclr | ||
| 321 | .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) }); | ||
| 322 | }); | ||
| 323 | |||
| 324 | poll_fn(|cx| { | ||
| 325 | T::waker(self.n).register(cx.waker()); | ||
| 326 | |||
| 327 | if regs.events_compare[self.n].read().bits() != 0 { | ||
| 328 | // Reset the register for next time | ||
| 329 | regs.events_compare[self.n].reset(); | ||
| 330 | Poll::Ready(()) | ||
| 331 | } else { | ||
| 332 | Poll::Pending | ||
| 333 | } | ||
| 334 | }) | ||
| 335 | .await; | ||
| 336 | |||
| 337 | // The interrupt was already disabled in the interrupt handler, so there's no need to disable it again. | ||
| 338 | on_drop.defuse(); | ||
| 339 | } | ||
| 340 | } | ||
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index de093c7f0..67ec5d73f 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}; | |||
| 18 | use crate::interrupt::Interrupt; | 18 | use crate::interrupt::Interrupt; |
| 19 | use crate::pac; | 19 | use crate::pac; |
| 20 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | 20 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; |
| 21 | use crate::timer::Frequency; | ||
| 21 | use crate::timer::Instance as TimerInstance; | 22 | use crate::timer::Instance as TimerInstance; |
| 23 | use crate::timer::Timer; | ||
| 22 | 24 | ||
| 23 | // Re-export SVD variants to allow user to directly set values. | 25 | // Re-export SVD variants to allow user to directly set values. |
| 24 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | 26 | 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> { | |||
| 287 | /// allowing it to implement the ReadUntilIdle trait. | 289 | /// allowing it to implement the ReadUntilIdle trait. |
| 288 | pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> { | 290 | pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> { |
| 289 | uarte: Uarte<'d, U>, | 291 | uarte: Uarte<'d, U>, |
| 290 | timer: T, | 292 | timer: Timer<'d, T>, |
| 291 | ppi_ch1: Ppi<'d, AnyConfigurableChannel>, | 293 | ppi_ch1: Ppi<'d, AnyConfigurableChannel>, |
| 292 | _ppi_ch2: Ppi<'d, AnyConfigurableChannel>, | 294 | _ppi_ch2: Ppi<'d, AnyConfigurableChannel>, |
| 293 | } | 295 | } |
| @@ -316,11 +318,11 @@ impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> { | |||
| 316 | ) -> Self { | 318 | ) -> Self { |
| 317 | let baudrate = config.baudrate; | 319 | let baudrate = config.baudrate; |
| 318 | let uarte = Uarte::new(uarte, irq, rxd, txd, cts, rts, config); | 320 | let uarte = Uarte::new(uarte, irq, rxd, txd, cts, rts, config); |
| 321 | let mut timer = Timer::new_irqless(timer); | ||
| 319 | 322 | ||
| 320 | unborrow!(timer, ppi_ch1, ppi_ch2); | 323 | unborrow!(ppi_ch1, ppi_ch2); |
| 321 | 324 | ||
| 322 | let r = U::regs(); | 325 | let r = U::regs(); |
| 323 | let rt = timer.regs(); | ||
| 324 | 326 | ||
| 325 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` | 327 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` |
| 326 | // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values | 328 | // 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> { | |||
| 330 | // This gives us the amount of 16M ticks for 20 bits. | 332 | // This gives us the amount of 16M ticks for 20 bits. |
| 331 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); | 333 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); |
| 332 | 334 | ||
| 333 | rt.tasks_stop.write(|w| unsafe { w.bits(1) }); | 335 | timer.set_frequency(Frequency::F16MHz); |
| 334 | rt.bitmode.write(|w| w.bitmode()._32bit()); | 336 | timer.cc(0).write(timeout); |
| 335 | rt.prescaler.write(|w| unsafe { w.prescaler().bits(0) }); | 337 | timer.cc(0).short_compare_clear(); |
| 336 | rt.cc[0].write(|w| unsafe { w.bits(timeout) }); | 338 | timer.cc(0).short_compare_stop(); |
| 337 | rt.mode.write(|w| w.mode().timer()); | ||
| 338 | rt.shorts.write(|w| { | ||
| 339 | w.compare0_clear().set_bit(); | ||
| 340 | w.compare0_stop().set_bit(); | ||
| 341 | w | ||
| 342 | }); | ||
| 343 | 339 | ||
| 344 | let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade_configurable()); | 340 | let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade_configurable()); |
| 345 | ppi_ch1.set_event(Event::from_reg(&r.events_rxdrdy)); | 341 | ppi_ch1.set_event(Event::from_reg(&r.events_rxdrdy)); |
| 346 | ppi_ch1.set_task(Task::from_reg(&rt.tasks_clear)); | 342 | ppi_ch1.set_task(timer.task_clear()); |
| 347 | ppi_ch1.set_fork_task(Task::from_reg(&rt.tasks_start)); | 343 | ppi_ch1.set_fork_task(timer.task_start()); |
| 348 | ppi_ch1.enable(); | 344 | ppi_ch1.enable(); |
| 349 | 345 | ||
| 350 | let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade_configurable()); | 346 | let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade_configurable()); |
| 351 | ppi_ch2.set_event(Event::from_reg(&rt.events_compare[0])); | 347 | ppi_ch2.set_event(timer.cc(0).event_compare()); |
| 352 | ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx)); | 348 | ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx)); |
| 353 | ppi_ch2.enable(); | 349 | ppi_ch2.enable(); |
| 354 | 350 | ||
| @@ -373,12 +369,10 @@ impl<'d, U: Instance, T: TimerInstance> ReadUntilIdle for UarteWithIdle<'d, U, T | |||
| 373 | let r = U::regs(); | 369 | let r = U::regs(); |
| 374 | let s = U::state(); | 370 | let s = U::state(); |
| 375 | 371 | ||
| 376 | let rt = self.timer.regs(); | 372 | let drop = OnDrop::new(|| { |
| 377 | |||
| 378 | let drop = OnDrop::new(move || { | ||
| 379 | info!("read drop: stopping"); | 373 | info!("read drop: stopping"); |
| 380 | 374 | ||
| 381 | rt.tasks_stop.write(|w| unsafe { w.bits(1) }); | 375 | self.timer.stop(); |
| 382 | 376 | ||
| 383 | r.intenclr.write(|w| w.endrx().clear()); | 377 | r.intenclr.write(|w| w.endrx().clear()); |
| 384 | r.events_rxto.reset(); | 378 | r.events_rxto.reset(); |
| @@ -413,7 +407,7 @@ impl<'d, U: Instance, T: TimerInstance> ReadUntilIdle for UarteWithIdle<'d, U, T | |||
| 413 | let n = r.rxd.amount.read().amount().bits() as usize; | 407 | let n = r.rxd.amount.read().amount().bits() as usize; |
| 414 | 408 | ||
| 415 | // Stop timer | 409 | // Stop timer |
| 416 | rt.tasks_stop.write(|w| unsafe { w.bits(1) }); | 410 | self.timer.stop(); |
| 417 | r.events_rxstarted.reset(); | 411 | r.events_rxstarted.reset(); |
| 418 | 412 | ||
| 419 | drop.defuse(); | 413 | drop.defuse(); |
