aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf/src/timer.rs
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-06-29 07:37:06 +0200
committerGitHub <[email protected]>2021-06-29 07:37:06 +0200
commitd49adc98beebe5b7982204150ebdc0a485fefab2 (patch)
tree4c51df41daf9b180eecbe584b50a46163aade0ce /embassy-nrf/src/timer.rs
parentf501907f9e69c1d47571b6e0980f22dde723b45d (diff)
parentc0ef40d6e9ee91ef754e90424ecd76fd80c0f125 (diff)
Merge pull request #260 from Liamolucko/nrf-timer
Add an nRF Timer driver
Diffstat (limited to 'embassy-nrf/src/timer.rs')
-rw-r--r--embassy-nrf/src/timer.rs310
1 files changed, 306 insertions, 4 deletions
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
3use core::marker::PhantomData;
4use core::task::Poll;
5
3use embassy::interrupt::Interrupt; 6use embassy::interrupt::Interrupt;
7use embassy::interrupt::InterruptExt;
8use embassy::util::OnDrop;
4use embassy::util::Unborrow; 9use embassy::util::Unborrow;
10use embassy_extras::unborrow;
11use futures::future::poll_fn;
5 12
6use crate::pac; 13use crate::pac;
14use crate::ppi::Event;
15use crate::ppi::Task;
7 16
8pub(crate) mod sealed { 17pub(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 {
20pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} 35pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {}
21 36
22macro_rules! impl_timer { 37macro_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)]
66pub 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.
87pub struct Timer<'d, T: Instance> {
88 phantom: PhantomData<&'d mut T>,
89}
90
91impl<'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
233pub struct Cc<'a, T: Instance> {
234 n: usize,
235 phantom: PhantomData<&'a mut T>,
236}
237
238impl<'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}