diff options
Diffstat (limited to 'embassy-nrf')
| -rw-r--r-- | embassy-nrf/src/timer.rs | 134 |
1 files changed, 10 insertions, 124 deletions
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 3b0d2f1ca..a9487a9fd 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs | |||
| @@ -6,15 +6,9 @@ | |||
| 6 | 6 | ||
| 7 | #![macro_use] | 7 | #![macro_use] |
| 8 | 8 | ||
| 9 | use core::future::poll_fn; | ||
| 10 | use core::marker::PhantomData; | ||
| 11 | use core::task::Poll; | ||
| 12 | |||
| 13 | use embassy_hal_common::drop::OnDrop; | ||
| 14 | use embassy_hal_common::{into_ref, PeripheralRef}; | 9 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 15 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 16 | 10 | ||
| 17 | use crate::interrupt::{Interrupt, InterruptExt}; | 11 | use crate::interrupt::Interrupt; |
| 18 | use crate::ppi::{Event, Task}; | 12 | use crate::ppi::{Event, Task}; |
| 19 | use crate::{pac, Peripheral}; | 13 | use crate::{pac, Peripheral}; |
| 20 | 14 | ||
| @@ -26,8 +20,6 @@ pub(crate) mod sealed { | |||
| 26 | /// The number of CC registers this instance has. | 20 | /// The number of CC registers this instance has. |
| 27 | const CCS: usize; | 21 | const CCS: usize; |
| 28 | fn regs() -> &'static pac::timer0::RegisterBlock; | 22 | fn regs() -> &'static pac::timer0::RegisterBlock; |
| 29 | /// Storage for the waker for CC register `n`. | ||
| 30 | fn waker(n: usize) -> &'static AtomicWaker; | ||
| 31 | } | 23 | } |
| 32 | pub trait ExtendedInstance {} | 24 | pub trait ExtendedInstance {} |
| 33 | 25 | ||
| @@ -50,12 +42,6 @@ macro_rules! impl_timer { | |||
| 50 | fn regs() -> &'static pac::timer0::RegisterBlock { | 42 | fn regs() -> &'static pac::timer0::RegisterBlock { |
| 51 | unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } | 43 | unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } |
| 52 | } | 44 | } |
| 53 | fn waker(n: usize) -> &'static ::embassy_sync::waitqueue::AtomicWaker { | ||
| 54 | use ::embassy_sync::waitqueue::AtomicWaker; | ||
| 55 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | ||
| 56 | static WAKERS: [AtomicWaker; $ccs] = [NEW_AW; $ccs]; | ||
| 57 | &WAKERS[n] | ||
| 58 | } | ||
| 59 | } | 45 | } |
| 60 | impl crate::timer::Instance for peripherals::$type { | 46 | impl crate::timer::Instance for peripherals::$type { |
| 61 | type Interrupt = crate::interrupt::$irq; | 47 | type Interrupt = crate::interrupt::$irq; |
| @@ -99,59 +85,18 @@ pub enum Frequency { | |||
| 99 | /// nRF Timer driver. | 85 | /// nRF Timer driver. |
| 100 | /// | 86 | /// |
| 101 | /// The timer has an internal counter, which is incremented for every tick of the timer. | 87 | /// The timer has an internal counter, which is incremented for every tick of the timer. |
| 102 | /// The counter is 32-bit, so it wraps back to 0 at 4294967296. | 88 | /// The counter is 32-bit, so it wraps back to 0 when it reaches 2^32. |
| 103 | /// | 89 | /// |
| 104 | /// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter | 90 | /// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter |
| 105 | /// or trigger an event when the counter reaches a certain value. | 91 | /// or trigger an event when the counter reaches a certain value. |
| 106 | 92 | ||
| 107 | pub trait TimerType: sealed::TimerType {} | ||
| 108 | |||
| 109 | /// Marker type indicating the timer driver can await expiration (it owns the timer interrupt). | ||
| 110 | pub enum Awaitable {} | ||
| 111 | |||
| 112 | /// Marker type indicating the timer driver cannot await expiration (it does not own the timer interrupt). | ||
| 113 | pub enum NotAwaitable {} | ||
| 114 | |||
| 115 | impl sealed::TimerType for Awaitable {} | ||
| 116 | impl sealed::TimerType for NotAwaitable {} | ||
| 117 | impl TimerType for Awaitable {} | ||
| 118 | impl TimerType for NotAwaitable {} | ||
| 119 | |||
| 120 | /// Timer driver. | 93 | /// Timer driver. |
| 121 | pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> { | 94 | pub struct Timer<'d, T: Instance> { |
| 122 | _p: PeripheralRef<'d, T>, | 95 | _p: PeripheralRef<'d, T>, |
| 123 | _i: PhantomData<I>, | ||
| 124 | } | ||
| 125 | |||
| 126 | impl<'d, T: Instance> Timer<'d, T, Awaitable> { | ||
| 127 | /// Create a new async-capable timer driver. | ||
| 128 | pub fn new_awaitable(timer: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd) -> Self { | ||
| 129 | into_ref!(irq); | ||
| 130 | |||
| 131 | irq.set_handler(Self::on_interrupt); | ||
| 132 | irq.unpend(); | ||
| 133 | irq.enable(); | ||
| 134 | |||
| 135 | Self::new_inner(timer, false) | ||
| 136 | } | ||
| 137 | |||
| 138 | /// Create a new async-capable timer driver in counter mode. | ||
| 139 | pub fn new_awaitable_counter( | ||
| 140 | timer: impl Peripheral<P = T> + 'd, | ||
| 141 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 142 | ) -> Self { | ||
| 143 | into_ref!(irq); | ||
| 144 | |||
| 145 | irq.set_handler(Self::on_interrupt); | ||
| 146 | irq.unpend(); | ||
| 147 | irq.enable(); | ||
| 148 | |||
| 149 | Self::new_inner(timer, true) | ||
| 150 | } | ||
| 151 | } | 96 | } |
| 152 | 97 | ||
| 153 | impl<'d, T: Instance> Timer<'d, T, NotAwaitable> { | 98 | impl<'d, T: Instance> Timer<'d, T> { |
| 154 | /// Create a `Timer` driver without an interrupt, meaning `Cc::wait` won't work. | 99 | /// Create a new `Timer` driver. |
| 155 | /// | 100 | /// |
| 156 | /// This can be useful for triggering tasks via PPI | 101 | /// This can be useful for triggering tasks via PPI |
| 157 | /// `Uarte` uses this internally. | 102 | /// `Uarte` uses this internally. |
| @@ -159,28 +104,20 @@ impl<'d, T: Instance> Timer<'d, T, NotAwaitable> { | |||
| 159 | Self::new_inner(timer, false) | 104 | Self::new_inner(timer, false) |
| 160 | } | 105 | } |
| 161 | 106 | ||
| 162 | /// Create a `Timer` driver in counter mode without an interrupt, meaning `Cc::wait` won't work. | 107 | /// Create a new `Timer` driver in counter mode. |
| 163 | /// | 108 | /// |
| 164 | /// This can be useful for triggering tasks via PPI | 109 | /// This can be useful for triggering tasks via PPI |
| 165 | /// `Uarte` uses this internally. | 110 | /// `Uarte` uses this internally. |
| 166 | pub fn new_counter(timer: impl Peripheral<P = T> + 'd) -> Self { | 111 | pub fn new_counter(timer: impl Peripheral<P = T> + 'd) -> Self { |
| 167 | Self::new_inner(timer, true) | 112 | Self::new_inner(timer, true) |
| 168 | } | 113 | } |
| 169 | } | ||
| 170 | 114 | ||
| 171 | impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { | ||
| 172 | /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work. | ||
| 173 | /// | ||
| 174 | /// This is used by the public constructors. | ||
| 175 | fn new_inner(timer: impl Peripheral<P = T> + 'd, is_counter: bool) -> Self { | 115 | fn new_inner(timer: impl Peripheral<P = T> + 'd, is_counter: bool) -> Self { |
| 176 | into_ref!(timer); | 116 | into_ref!(timer); |
| 177 | 117 | ||
| 178 | let regs = T::regs(); | 118 | let regs = T::regs(); |
| 179 | 119 | ||
| 180 | let mut this = Self { | 120 | let mut this = Self { _p: timer }; |
| 181 | _p: timer, | ||
| 182 | _i: PhantomData, | ||
| 183 | }; | ||
| 184 | 121 | ||
| 185 | // Stop the timer before doing anything else, | 122 | // Stop the timer before doing anything else, |
| 186 | // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. | 123 | // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. |
| @@ -272,31 +209,17 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { | |||
| 272 | .write(|w| unsafe { w.prescaler().bits(frequency as u8) }) | 209 | .write(|w| unsafe { w.prescaler().bits(frequency as u8) }) |
| 273 | } | 210 | } |
| 274 | 211 | ||
| 275 | fn on_interrupt(_: *mut ()) { | ||
| 276 | let regs = T::regs(); | ||
| 277 | for n in 0..T::CCS { | ||
| 278 | if regs.events_compare[n].read().bits() != 0 { | ||
| 279 | // Clear the interrupt, otherwise the interrupt will be repeatedly raised as soon as the interrupt handler exits. | ||
| 280 | // We can't clear the event, because it's used to poll whether the future is done or still pending. | ||
| 281 | regs.intenclr | ||
| 282 | .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + n))) }); | ||
| 283 | T::waker(n).wake(); | ||
| 284 | } | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | /// Returns this timer's `n`th CC register. | 212 | /// Returns this timer's `n`th CC register. |
| 289 | /// | 213 | /// |
| 290 | /// # Panics | 214 | /// # Panics |
| 291 | /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer). | 215 | /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer). |
| 292 | pub fn cc(&mut self, n: usize) -> Cc<T, I> { | 216 | pub fn cc(&mut self, n: usize) -> Cc<T> { |
| 293 | if n >= T::CCS { | 217 | if n >= T::CCS { |
| 294 | panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS); | 218 | panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS); |
| 295 | } | 219 | } |
| 296 | Cc { | 220 | Cc { |
| 297 | n, | 221 | n, |
| 298 | _p: self._p.reborrow(), | 222 | _p: self._p.reborrow(), |
| 299 | _i: PhantomData, | ||
| 300 | } | 223 | } |
| 301 | } | 224 | } |
| 302 | } | 225 | } |
| @@ -308,49 +231,12 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { | |||
| 308 | /// | 231 | /// |
| 309 | /// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register. | 232 | /// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register. |
| 310 | /// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register | 233 | /// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register |
| 311 | pub struct Cc<'d, T: Instance, I: TimerType = NotAwaitable> { | 234 | pub struct Cc<'d, T: Instance> { |
| 312 | n: usize, | 235 | n: usize, |
| 313 | _p: PeripheralRef<'d, T>, | 236 | _p: PeripheralRef<'d, T>, |
| 314 | _i: PhantomData<I>, | ||
| 315 | } | ||
| 316 | |||
| 317 | impl<'d, T: Instance> Cc<'d, T, Awaitable> { | ||
| 318 | /// Wait until the timer's counter reaches the value stored in this register. | ||
| 319 | /// | ||
| 320 | /// This requires a mutable reference so that this task's waker cannot be overwritten by a second call to `wait`. | ||
| 321 | pub async fn wait(&mut self) { | ||
| 322 | let regs = T::regs(); | ||
| 323 | |||
| 324 | // Enable the interrupt for this CC's COMPARE event. | ||
| 325 | regs.intenset | ||
| 326 | .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) }); | ||
| 327 | |||
| 328 | // Disable the interrupt if the future is dropped. | ||
| 329 | let on_drop = OnDrop::new(|| { | ||
| 330 | regs.intenclr | ||
| 331 | .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) }); | ||
| 332 | }); | ||
| 333 | |||
| 334 | poll_fn(|cx| { | ||
| 335 | T::waker(self.n).register(cx.waker()); | ||
| 336 | |||
| 337 | if regs.events_compare[self.n].read().bits() != 0 { | ||
| 338 | // Reset the register for next time | ||
| 339 | regs.events_compare[self.n].reset(); | ||
| 340 | Poll::Ready(()) | ||
| 341 | } else { | ||
| 342 | Poll::Pending | ||
| 343 | } | ||
| 344 | }) | ||
| 345 | .await; | ||
| 346 | |||
| 347 | // The interrupt was already disabled in the interrupt handler, so there's no need to disable it again. | ||
| 348 | on_drop.defuse(); | ||
| 349 | } | ||
| 350 | } | 237 | } |
| 351 | impl<'d, T: Instance> Cc<'d, T, NotAwaitable> {} | ||
| 352 | 238 | ||
| 353 | impl<'d, T: Instance, I: TimerType> Cc<'d, T, I> { | 239 | impl<'d, T: Instance> Cc<'d, T> { |
| 354 | /// Get the current value stored in the register. | 240 | /// Get the current value stored in the register. |
| 355 | pub fn read(&self) -> u32 { | 241 | pub fn read(&self) -> u32 { |
| 356 | T::regs().cc[self.n].read().cc().bits() | 242 | T::regs().cc[self.n].read().cc().bits() |
