aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-nrf')
-rw-r--r--embassy-nrf/src/timer.rs134
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
9use core::future::poll_fn;
10use core::marker::PhantomData;
11use core::task::Poll;
12
13use embassy_hal_common::drop::OnDrop;
14use embassy_hal_common::{into_ref, PeripheralRef}; 9use embassy_hal_common::{into_ref, PeripheralRef};
15use embassy_sync::waitqueue::AtomicWaker;
16 10
17use crate::interrupt::{Interrupt, InterruptExt}; 11use crate::interrupt::Interrupt;
18use crate::ppi::{Event, Task}; 12use crate::ppi::{Event, Task};
19use crate::{pac, Peripheral}; 13use 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
107pub trait TimerType: sealed::TimerType {}
108
109/// Marker type indicating the timer driver can await expiration (it owns the timer interrupt).
110pub enum Awaitable {}
111
112/// Marker type indicating the timer driver cannot await expiration (it does not own the timer interrupt).
113pub enum NotAwaitable {}
114
115impl sealed::TimerType for Awaitable {}
116impl sealed::TimerType for NotAwaitable {}
117impl TimerType for Awaitable {}
118impl TimerType for NotAwaitable {}
119
120/// Timer driver. 93/// Timer driver.
121pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> { 94pub struct Timer<'d, T: Instance> {
122 _p: PeripheralRef<'d, T>, 95 _p: PeripheralRef<'d, T>,
123 _i: PhantomData<I>,
124}
125
126impl<'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
153impl<'d, T: Instance> Timer<'d, T, NotAwaitable> { 98impl<'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
171impl<'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
311pub struct Cc<'d, T: Instance, I: TimerType = NotAwaitable> { 234pub 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
317impl<'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}
351impl<'d, T: Instance> Cc<'d, T, NotAwaitable> {}
352 238
353impl<'d, T: Instance, I: TimerType> Cc<'d, T, I> { 239impl<'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()