diff options
| author | Liam Murphy <[email protected]> | 2021-06-26 17:58:36 +1000 |
|---|---|---|
| committer | Liam Murphy <[email protected]> | 2021-06-26 17:58:36 +1000 |
| commit | 02781ed744b6e76d3790844f898235088b0fd8aa (patch) | |
| tree | 4f5cd29aebc7b54beee6f7e3541fcc583ed9d755 | |
| parent | e6d6e82e54bca88ab1144802d2b716b867934225 (diff) | |
Add an nRF Timer driver
Resolves #189
| -rw-r--r-- | embassy-nrf/src/buffered_uarte.rs | 40 | ||||
| -rw-r--r-- | embassy-nrf/src/timer.rs | 377 | ||||
| -rw-r--r-- | 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 _; | |||
| 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 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.cc0().set(timeout); |
| 138 | rt.prescaler.write(|w| unsafe { w.prescaler().bits(0) }); | 141 | timer.cc0().short_compare_clear(); |
| 139 | rt.cc[0].write(|w| unsafe { w.bits(timeout) }); | 142 | timer.cc0().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.cc0().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.cc0().set(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..3b2678a0b 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,373 @@ 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 | // TODO: These variant names are terrible, what should they be? | ||
| 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 | // Set the instance to timer mode. | ||
| 112 | regs.mode.write(|w| w.mode().timer()); | ||
| 113 | |||
| 114 | // Make the counter's max value as high as possible. | ||
| 115 | // TODO: is there a reason someone would want to set this lower? | ||
| 116 | regs.bitmode.write(|w| w.bitmode()._32bit()); | ||
| 117 | |||
| 118 | let this = Self { | ||
| 119 | phantom: PhantomData, | ||
| 120 | }; | ||
| 121 | |||
| 122 | // Initialize the timer as stopped. | ||
| 123 | this.stop(); | ||
| 124 | |||
| 125 | // Initialize the counter at 0. | ||
| 126 | this.clear(); | ||
| 127 | |||
| 128 | // Initialize all the shorts as disabled. | ||
| 129 | for n in 0..T::CCS { | ||
| 130 | let cc = Cc::<T> { | ||
| 131 | n, | ||
| 132 | phantom: PhantomData, | ||
| 133 | }; | ||
| 134 | cc.unshort_compare_clear(); | ||
| 135 | cc.unshort_compare_stop(); | ||
| 136 | } | ||
| 137 | |||
| 138 | this | ||
| 139 | } | ||
| 140 | |||
| 141 | /// Starts the timer. | ||
| 142 | pub fn start(&self) { | ||
| 143 | T::regs().tasks_start.write(|w| w.tasks_start().trigger()) | ||
| 144 | } | ||
| 145 | |||
| 146 | /// Stops the timer. | ||
| 147 | pub fn stop(&self) { | ||
| 148 | T::regs().tasks_stop.write(|w| w.tasks_stop().trigger()) | ||
| 149 | } | ||
| 150 | |||
| 151 | /// Reset the timer's counter to 0. | ||
| 152 | pub fn clear(&self) { | ||
| 153 | T::regs().tasks_clear.write(|w| w.tasks_clear().trigger()) | ||
| 154 | } | ||
| 155 | |||
| 156 | /// Returns the START task, for use with PPI. | ||
| 157 | /// | ||
| 158 | /// When triggered, this task starts the timer. | ||
| 159 | pub fn task_start(&self) -> Task { | ||
| 160 | Task::from_reg(&T::regs().tasks_start) | ||
| 161 | } | ||
| 162 | |||
| 163 | /// Returns the STOP task, for use with PPI. | ||
| 164 | /// | ||
| 165 | /// When triggered, this task stops the timer. | ||
| 166 | pub fn task_stop(&self) -> Task { | ||
| 167 | Task::from_reg(&T::regs().tasks_stop) | ||
| 168 | } | ||
| 169 | |||
| 170 | /// Returns the CLEAR task, for use with PPI. | ||
| 171 | /// | ||
| 172 | /// When triggered, this task resets the timer's counter to 0. | ||
| 173 | pub fn task_clear(&self) -> Task { | ||
| 174 | Task::from_reg(&T::regs().tasks_clear) | ||
| 175 | } | ||
| 176 | |||
| 177 | /// Change the timer's frequency. | ||
| 178 | /// | ||
| 179 | /// This will stop the timer if it isn't already stopped, | ||
| 180 | /// because the timer may exhibit 'unpredictable behaviour' if it's frequency is changed while it's running. | ||
| 181 | pub fn set_frequency(&self, frequency: Frequency) { | ||
| 182 | self.stop(); | ||
| 183 | |||
| 184 | T::regs() | ||
| 185 | .prescaler | ||
| 186 | // SAFETY: `frequency` is a variant of `Frequency`, | ||
| 187 | // whose values are all in the range of 0-9 (the valid range of `prescaler`). | ||
| 188 | .write(|w| unsafe { w.prescaler().bits(frequency as u8) }) | ||
| 189 | } | ||
| 190 | |||
| 191 | fn on_interrupt(_: *mut ()) { | ||
| 192 | let regs = T::regs(); | ||
| 193 | for n in 0..T::CCS { | ||
| 194 | if regs.events_compare[n] | ||
| 195 | .read() | ||
| 196 | .events_compare() | ||
| 197 | .is_generated() | ||
| 198 | { | ||
| 199 | T::waker(n).wake(); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | /// Returns the 0th CC register. | ||
| 205 | pub fn cc0<'a>(&'a self) -> Cc<'a, T> { | ||
| 206 | Cc { | ||
| 207 | n: 0, | ||
| 208 | phantom: PhantomData, | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | /// Returns the 1st CC register. | ||
| 213 | pub fn cc1<'a>(&'a self) -> Cc<'a, T> { | ||
| 214 | Cc { | ||
| 215 | n: 1, | ||
| 216 | phantom: PhantomData, | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | /// Returns the 2nd CC register. | ||
| 221 | pub fn cc2<'a>(&'a self) -> Cc<'a, T> { | ||
| 222 | Cc { | ||
| 223 | n: 2, | ||
| 224 | phantom: PhantomData, | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | /// Returns the 3rd CC register. | ||
| 229 | pub fn cc3<'a>(&'a self) -> Cc<'a, T> { | ||
| 230 | Cc { | ||
| 231 | n: 3, | ||
| 232 | phantom: PhantomData, | ||
| 233 | } | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | impl<'d, T: ExtendedInstance> Timer<'d, T> { | ||
| 238 | /// Returns the 4th CC register. | ||
| 239 | pub fn cc4<'a>(&'a self) -> Cc<'a, T> { | ||
| 240 | Cc { | ||
| 241 | n: 4, | ||
| 242 | phantom: PhantomData, | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | /// Returns the 5th CC register. | ||
| 247 | pub fn cc5<'a>(&'a self) -> Cc<'a, T> { | ||
| 248 | Cc { | ||
| 249 | n: 5, | ||
| 250 | phantom: PhantomData, | ||
| 251 | } | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | /// A representation of a timer's Capture/Compare (CC) register. | ||
| 256 | /// | ||
| 257 | /// A CC register holds a 32-bit value. | ||
| 258 | /// 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. | ||
| 259 | /// | ||
| 260 | /// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register. | ||
| 261 | /// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register | ||
| 262 | pub struct Cc<'a, T: Instance> { | ||
| 263 | n: usize, | ||
| 264 | phantom: PhantomData<&'a mut T>, | ||
| 265 | } | ||
| 266 | |||
| 267 | impl<'a, T: Instance> Cc<'a, T> { | ||
| 268 | /// Get the current value stored in the register. | ||
| 269 | pub fn value(&self) -> u32 { | ||
| 270 | T::regs().cc[self.n].read().cc().bits() | ||
| 271 | } | ||
| 272 | |||
| 273 | /// Set the value stored in the register. | ||
| 274 | /// | ||
| 275 | /// `event_compare` will fire when the timer's counter reaches this value. | ||
| 276 | pub fn set(&self, value: u32) { | ||
| 277 | // SAFETY: there are no invalid values for the CC register. | ||
| 278 | T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) }) | ||
| 279 | } | ||
| 280 | |||
| 281 | /// Capture the current value of the timer's counter in this register, and return it. | ||
| 282 | pub fn capture(&self) -> u32 { | ||
| 283 | T::regs().tasks_capture[self.n].write(|w| w.tasks_capture().trigger()); | ||
| 284 | self.value() | ||
| 285 | } | ||
| 286 | |||
| 287 | /// Returns this CC register's CAPTURE task, for use with PPI. | ||
| 288 | /// | ||
| 289 | /// When triggered, this task will capture the current value of the timer's counter in this register. | ||
| 290 | pub fn task_capture(&self) -> Task { | ||
| 291 | Task::from_reg(&T::regs().tasks_capture[self.n]) | ||
| 292 | } | ||
| 293 | |||
| 294 | /// Returns this CC register's COMPARE event, for use with PPI. | ||
| 295 | /// | ||
| 296 | /// This event will fire when the timer's counter reaches the value in this CC register. | ||
| 297 | pub fn event_compare(&self) -> Event { | ||
| 298 | Event::from_reg(&T::regs().events_compare) | ||
| 299 | } | ||
| 300 | |||
| 301 | /// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. | ||
| 302 | /// | ||
| 303 | /// This means that when the COMPARE event is fired, the CLEAR task will be triggered. | ||
| 304 | /// | ||
| 305 | /// So, when the timer's counter reaches the value stored in this register, the timer's counter will be reset to 0. | ||
| 306 | pub fn short_compare_clear(&self) { | ||
| 307 | T::regs().shorts.write(|w| match self.n { | ||
| 308 | 0 => w.compare0_clear().enabled(), | ||
| 309 | 1 => w.compare1_clear().enabled(), | ||
| 310 | 2 => w.compare2_clear().enabled(), | ||
| 311 | 3 => w.compare3_clear().enabled(), | ||
| 312 | 4 => w.compare4_clear().enabled(), | ||
| 313 | 5 => w.compare5_clear().enabled(), | ||
| 314 | _ => unreachable!("a `Cc` cannot be created with `n > 5`"), | ||
| 315 | }) | ||
| 316 | } | ||
| 317 | |||
| 318 | /// Disable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. | ||
| 319 | pub fn unshort_compare_clear(&self) { | ||
| 320 | T::regs().shorts.write(|w| match self.n { | ||
| 321 | 0 => w.compare0_clear().disabled(), | ||
| 322 | 1 => w.compare1_clear().disabled(), | ||
| 323 | 2 => w.compare2_clear().disabled(), | ||
| 324 | 3 => w.compare3_clear().disabled(), | ||
| 325 | 4 => w.compare4_clear().disabled(), | ||
| 326 | 5 => w.compare5_clear().disabled(), | ||
| 327 | _ => unreachable!("a `Cc` cannot be created with `n > 5`"), | ||
| 328 | }) | ||
| 329 | } | ||
| 330 | |||
| 331 | /// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task. | ||
| 332 | /// | ||
| 333 | /// This means that when the COMPARE event is fired, the STOP task will be triggered. | ||
| 334 | /// | ||
| 335 | /// So, when the timer's counter reaches the value stored in this register, the timer will stop counting up. | ||
| 336 | pub fn short_compare_stop(&self) { | ||
| 337 | T::regs().shorts.write(|w| match self.n { | ||
| 338 | 0 => w.compare0_stop().enabled(), | ||
| 339 | 1 => w.compare1_stop().enabled(), | ||
| 340 | 2 => w.compare2_stop().enabled(), | ||
| 341 | 3 => w.compare3_stop().enabled(), | ||
| 342 | 4 => w.compare4_stop().enabled(), | ||
| 343 | 5 => w.compare5_stop().enabled(), | ||
| 344 | _ => unreachable!("a `Cc` cannot be created with `n > 5`"), | ||
| 345 | }) | ||
| 346 | } | ||
| 347 | |||
| 348 | /// Disable the shortcut between this CC register's COMPARE event and the timer's STOP task. | ||
| 349 | pub fn unshort_compare_stop(&self) { | ||
| 350 | T::regs().shorts.write(|w| match self.n { | ||
| 351 | 0 => w.compare0_stop().disabled(), | ||
| 352 | 1 => w.compare1_stop().disabled(), | ||
| 353 | 2 => w.compare2_stop().disabled(), | ||
| 354 | 3 => w.compare3_stop().disabled(), | ||
| 355 | 4 => w.compare4_stop().disabled(), | ||
| 356 | 5 => w.compare5_stop().disabled(), | ||
| 357 | _ => unreachable!("a `Cc` cannot be created with `n > 5`"), | ||
| 358 | }) | ||
| 359 | } | ||
| 360 | |||
| 361 | /// Wait until the timer's counter reaches the value stored in this register. | ||
| 362 | pub async fn wait(&self) { | ||
| 363 | let regs = T::regs(); | ||
| 364 | |||
| 365 | // Enable the interrupt for this CC's COMPARE event. | ||
| 366 | regs.intenset.write(|w| match self.n { | ||
| 367 | 0 => w.compare0().set(), | ||
| 368 | 1 => w.compare1().set(), | ||
| 369 | 2 => w.compare2().set(), | ||
| 370 | 3 => w.compare3().set(), | ||
| 371 | 4 => w.compare4().set(), | ||
| 372 | 5 => w.compare5().set(), | ||
| 373 | _ => unreachable!("a `Cc` cannot be created with `n > 5`"), | ||
| 374 | }); | ||
| 375 | |||
| 376 | // Disable the interrupt if the future is dropped. | ||
| 377 | let on_drop = OnDrop::new(|| { | ||
| 378 | regs.intenclr.write(|w| match self.n { | ||
| 379 | 0 => w.compare0().clear(), | ||
| 380 | 1 => w.compare1().clear(), | ||
| 381 | 2 => w.compare2().clear(), | ||
| 382 | 3 => w.compare3().clear(), | ||
| 383 | 4 => w.compare4().clear(), | ||
| 384 | 5 => w.compare5().clear(), | ||
| 385 | _ => unreachable!("a `Cc` cannot be created with `n > 5`"), | ||
| 386 | }); | ||
| 387 | }); | ||
| 388 | |||
| 389 | poll_fn(|cx| { | ||
| 390 | T::waker(self.n).register(cx.waker()); | ||
| 391 | |||
| 392 | if regs.events_compare[self.n] | ||
| 393 | .read() | ||
| 394 | .events_compare() | ||
| 395 | .is_generated() | ||
| 396 | { | ||
| 397 | Poll::Ready(()) | ||
| 398 | } else { | ||
| 399 | Poll::Pending | ||
| 400 | } | ||
| 401 | }) | ||
| 402 | .await; | ||
| 403 | |||
| 404 | // Trigger the interrupt to be disabled. | ||
| 405 | drop(on_drop); | ||
| 406 | } | ||
| 407 | } | ||
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}; | |||
| 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 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.cc0().set(timeout); |
| 335 | rt.prescaler.write(|w| unsafe { w.prescaler().bits(0) }); | 337 | timer.cc0().short_compare_clear(); |
| 336 | rt.cc[0].write(|w| unsafe { w.bits(timeout) }); | 338 | timer.cc0().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.cc0().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(); |
