aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf/src/timer.rs
diff options
context:
space:
mode:
authorMatteo Meluzzi <[email protected]>2025-10-02 10:53:31 +0200
committerMatteo Meluzzi <[email protected]>2025-10-02 10:53:31 +0200
commit828a8df18d04877df1f55f04354980b28ff2f2f8 (patch)
treec4fa405f5eba7a14b6d435d6cc746c9e0dc52632 /embassy-nrf/src/timer.rs
parent176649e71ad442ca9856af6c11989b0b2f228c4b (diff)
parent194a721d0eab929a2af0a2a4e45ca8e70e0d3f0a (diff)
Merge branch 'main' into 17-add-support-for-boot-protocol
Diffstat (limited to 'embassy-nrf/src/timer.rs')
-rw-r--r--embassy-nrf/src/timer.rs110
1 files changed, 73 insertions, 37 deletions
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs
index 5b58b0a50..0b0bb9780 100644
--- a/embassy-nrf/src/timer.rs
+++ b/embassy-nrf/src/timer.rs
@@ -6,6 +6,8 @@
6 6
7#![macro_use] 7#![macro_use]
8 8
9use core::marker::PhantomData;
10
9use embassy_hal_internal::{Peri, PeripheralType}; 11use embassy_hal_internal::{Peri, PeripheralType};
10 12
11use crate::pac; 13use crate::pac;
@@ -81,40 +83,44 @@ pub enum Frequency {
81/// 83///
82/// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter 84/// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter
83/// or trigger an event when the counter reaches a certain value. 85/// or trigger an event when the counter reaches a certain value.
84 86pub struct Timer<'d> {
85/// Timer driver. 87 r: pac::timer::Timer,
86pub struct Timer<'d, T: Instance> { 88 ccs: usize,
87 _p: Peri<'d, T>, 89 _p: PhantomData<&'d ()>,
88} 90}
89 91
90impl<'d, T: Instance> Timer<'d, T> { 92impl<'d> Timer<'d> {
91 /// Create a new `Timer` driver. 93 /// Create a new `Timer` driver.
92 /// 94 ///
93 /// This can be useful for triggering tasks via PPI 95 /// This can be useful for triggering tasks via PPI.
94 /// `Uarte` uses this internally. 96 /// `Uarte` uses this internally.
95 pub fn new(timer: Peri<'d, T>) -> Self { 97 pub fn new<T: Instance>(timer: Peri<'d, T>) -> Self {
96 Self::new_inner(timer, false) 98 Self::new_inner(timer, false)
97 } 99 }
98 100
99 /// Create a new `Timer` driver in counter mode. 101 /// Create a new `Timer` driver in counter mode.
100 /// 102 ///
101 /// This can be useful for triggering tasks via PPI 103 /// This can be useful for triggering tasks via PPI.
102 /// `Uarte` uses this internally. 104 /// `Uarte` uses this internally.
103 pub fn new_counter(timer: Peri<'d, T>) -> Self { 105 pub fn new_counter<T: Instance>(timer: Peri<'d, T>) -> Self {
104 Self::new_inner(timer, true) 106 Self::new_inner(timer, true)
105 } 107 }
106 108
107 fn new_inner(timer: Peri<'d, T>, _is_counter: bool) -> Self { 109 fn new_inner<T: Instance>(_timer: Peri<'d, T>, is_counter: bool) -> Self {
108 let regs = T::regs(); 110 let regs = T::regs();
109 111
110 let this = Self { _p: timer }; 112 let this = Self {
113 r: regs,
114 ccs: T::CCS,
115 _p: PhantomData,
116 };
111 117
112 // Stop the timer before doing anything else, 118 // Stop the timer before doing anything else,
113 // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. 119 // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
114 this.stop(); 120 this.stop();
115 121
116 regs.mode().write(|w| { 122 regs.mode().write(|w| {
117 w.set_mode(match _is_counter { 123 w.set_mode(match is_counter {
118 #[cfg(not(feature = "_nrf51"))] 124 #[cfg(not(feature = "_nrf51"))]
119 true => vals::Mode::LOW_POWER_COUNTER, 125 true => vals::Mode::LOW_POWER_COUNTER,
120 #[cfg(feature = "_nrf51")] 126 #[cfg(feature = "_nrf51")]
@@ -133,7 +139,7 @@ impl<'d, T: Instance> Timer<'d, T> {
133 // Default to the max frequency of the lower power clock 139 // Default to the max frequency of the lower power clock
134 this.set_frequency(Frequency::F1MHz); 140 this.set_frequency(Frequency::F1MHz);
135 141
136 for n in 0..T::CCS { 142 for n in 0..this.ccs {
137 let cc = this.cc(n); 143 let cc = this.cc(n);
138 // Initialize all the shorts as disabled. 144 // Initialize all the shorts as disabled.
139 cc.unshort_compare_clear(); 145 cc.unshort_compare_clear();
@@ -145,40 +151,47 @@ impl<'d, T: Instance> Timer<'d, T> {
145 this 151 this
146 } 152 }
147 153
154 /// Direct access to the register block.
155 #[cfg(feature = "unstable-pac")]
156 #[inline]
157 pub fn regs(&mut self) -> pac::timer::Timer {
158 self.r
159 }
160
148 /// Starts the timer. 161 /// Starts the timer.
149 pub fn start(&self) { 162 pub fn start(&self) {
150 T::regs().tasks_start().write_value(1) 163 self.r.tasks_start().write_value(1)
151 } 164 }
152 165
153 /// Stops the timer. 166 /// Stops the timer.
154 pub fn stop(&self) { 167 pub fn stop(&self) {
155 T::regs().tasks_stop().write_value(1) 168 self.r.tasks_stop().write_value(1)
156 } 169 }
157 170
158 /// Reset the timer's counter to 0. 171 /// Reset the timer's counter to 0.
159 pub fn clear(&self) { 172 pub fn clear(&self) {
160 T::regs().tasks_clear().write_value(1) 173 self.r.tasks_clear().write_value(1)
161 } 174 }
162 175
163 /// Returns the START task, for use with PPI. 176 /// Returns the START task, for use with PPI.
164 /// 177 ///
165 /// When triggered, this task starts the timer. 178 /// When triggered, this task starts the timer.
166 pub fn task_start(&self) -> Task<'d> { 179 pub fn task_start(&self) -> Task<'d> {
167 Task::from_reg(T::regs().tasks_start()) 180 Task::from_reg(self.r.tasks_start())
168 } 181 }
169 182
170 /// Returns the STOP task, for use with PPI. 183 /// Returns the STOP task, for use with PPI.
171 /// 184 ///
172 /// When triggered, this task stops the timer. 185 /// When triggered, this task stops the timer.
173 pub fn task_stop(&self) -> Task<'d> { 186 pub fn task_stop(&self) -> Task<'d> {
174 Task::from_reg(T::regs().tasks_stop()) 187 Task::from_reg(self.r.tasks_stop())
175 } 188 }
176 189
177 /// Returns the CLEAR task, for use with PPI. 190 /// Returns the CLEAR task, for use with PPI.
178 /// 191 ///
179 /// When triggered, this task resets the timer's counter to 0. 192 /// When triggered, this task resets the timer's counter to 0.
180 pub fn task_clear(&self) -> Task<'d> { 193 pub fn task_clear(&self) -> Task<'d> {
181 Task::from_reg(T::regs().tasks_clear()) 194 Task::from_reg(self.r.tasks_clear())
182 } 195 }
183 196
184 /// Returns the COUNT task, for use with PPI. 197 /// Returns the COUNT task, for use with PPI.
@@ -186,7 +199,7 @@ impl<'d, T: Instance> Timer<'d, T> {
186 /// When triggered, this task increments the timer's counter by 1. 199 /// When triggered, this task increments the timer's counter by 1.
187 /// Only works in counter mode. 200 /// Only works in counter mode.
188 pub fn task_count(&self) -> Task<'d> { 201 pub fn task_count(&self) -> Task<'d> {
189 Task::from_reg(T::regs().tasks_count()) 202 Task::from_reg(self.r.tasks_count())
190 } 203 }
191 204
192 /// Change the timer's frequency. 205 /// Change the timer's frequency.
@@ -196,7 +209,7 @@ impl<'d, T: Instance> Timer<'d, T> {
196 pub fn set_frequency(&self, frequency: Frequency) { 209 pub fn set_frequency(&self, frequency: Frequency) {
197 self.stop(); 210 self.stop();
198 211
199 T::regs() 212 self.r
200 .prescaler() 213 .prescaler()
201 // SAFETY: `frequency` is a variant of `Frequency`, 214 // SAFETY: `frequency` is a variant of `Frequency`,
202 // whose values are all in the range of 0-9 (the valid range of `prescaler`). 215 // whose values are all in the range of 0-9 (the valid range of `prescaler`).
@@ -207,17 +220,33 @@ impl<'d, T: Instance> Timer<'d, T> {
207 /// 220 ///
208 /// # Panics 221 /// # Panics
209 /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer). 222 /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer).
210 pub fn cc(&self, n: usize) -> Cc<'d, T> { 223 pub fn cc(&self, n: usize) -> Cc<'d> {
211 if n >= T::CCS { 224 if n >= self.ccs {
212 panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS); 225 panic!("Cannot get CC register {} of timer with {} CC registers.", n, self.ccs);
213 } 226 }
214 Cc { 227 Cc {
215 n, 228 n,
216 _p: unsafe { self._p.clone_unchecked() }, 229 r: self.r,
230 _p: PhantomData,
217 } 231 }
218 } 232 }
219} 233}
220 234
235impl Timer<'static> {
236 /// Persist the timer's configuration for the rest of the program's lifetime. This method
237 /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents
238 /// accidental reuse of the underlying peripheral.
239 pub fn persist(self) {
240 core::mem::forget(self);
241 }
242}
243
244impl<'d> Drop for Timer<'d> {
245 fn drop(&mut self) {
246 self.stop();
247 }
248}
249
221/// A representation of a timer's Capture/Compare (CC) register. 250/// A representation of a timer's Capture/Compare (CC) register.
222/// 251///
223/// A CC register holds a 32-bit value. 252/// A CC register holds a 32-bit value.
@@ -225,27 +254,28 @@ impl<'d, T: Instance> Timer<'d, T> {
225/// 254///
226/// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register. 255/// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register.
227/// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register 256/// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register
228pub struct Cc<'d, T: Instance> { 257pub struct Cc<'d> {
229 n: usize, 258 n: usize,
230 _p: Peri<'d, T>, 259 r: pac::timer::Timer,
260 _p: PhantomData<&'d ()>,
231} 261}
232 262
233impl<'d, T: Instance> Cc<'d, T> { 263impl<'d> Cc<'d> {
234 /// Get the current value stored in the register. 264 /// Get the current value stored in the register.
235 pub fn read(&self) -> u32 { 265 pub fn read(&self) -> u32 {
236 return T::regs().cc(self.n).read(); 266 self.r.cc(self.n).read()
237 } 267 }
238 268
239 /// Set the value stored in the register. 269 /// Set the value stored in the register.
240 /// 270 ///
241 /// `event_compare` will fire when the timer's counter reaches this value. 271 /// `event_compare` will fire when the timer's counter reaches this value.
242 pub fn write(&self, value: u32) { 272 pub fn write(&self, value: u32) {
243 T::regs().cc(self.n).write_value(value); 273 self.r.cc(self.n).write_value(value);
244 } 274 }
245 275
246 /// Capture the current value of the timer's counter in this register, and return it. 276 /// Capture the current value of the timer's counter in this register, and return it.
247 pub fn capture(&self) -> u32 { 277 pub fn capture(&self) -> u32 {
248 T::regs().tasks_capture(self.n).write_value(1); 278 self.r.tasks_capture(self.n).write_value(1);
249 self.read() 279 self.read()
250 } 280 }
251 281
@@ -253,14 +283,20 @@ impl<'d, T: Instance> Cc<'d, T> {
253 /// 283 ///
254 /// When triggered, this task will capture the current value of the timer's counter in this register. 284 /// When triggered, this task will capture the current value of the timer's counter in this register.
255 pub fn task_capture(&self) -> Task<'d> { 285 pub fn task_capture(&self) -> Task<'d> {
256 Task::from_reg(T::regs().tasks_capture(self.n)) 286 Task::from_reg(self.r.tasks_capture(self.n))
257 } 287 }
258 288
259 /// Returns this CC register's COMPARE event, for use with PPI. 289 /// Returns this CC register's COMPARE event, for use with PPI.
260 /// 290 ///
261 /// This event will fire when the timer's counter reaches the value in this CC register. 291 /// This event will fire when the timer's counter reaches the value in this CC register.
262 pub fn event_compare(&self) -> Event<'d> { 292 pub fn event_compare(&self) -> Event<'d> {
263 Event::from_reg(T::regs().events_compare(self.n)) 293 Event::from_reg(self.r.events_compare(self.n))
294 }
295
296 /// Clear the COMPARE event for this CC register.
297 #[inline]
298 pub fn clear_events(&self) {
299 self.r.events_compare(self.n).write_value(0);
264 } 300 }
265 301
266 /// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. 302 /// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task.
@@ -269,12 +305,12 @@ impl<'d, T: Instance> Cc<'d, T> {
269 /// 305 ///
270 /// So, when the timer's counter reaches the value stored in this register, the timer's counter will be reset to 0. 306 /// So, when the timer's counter reaches the value stored in this register, the timer's counter will be reset to 0.
271 pub fn short_compare_clear(&self) { 307 pub fn short_compare_clear(&self) {
272 T::regs().shorts().modify(|w| w.set_compare_clear(self.n, true)) 308 self.r.shorts().modify(|w| w.set_compare_clear(self.n, true))
273 } 309 }
274 310
275 /// Disable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. 311 /// Disable the shortcut between this CC register's COMPARE event and the timer's CLEAR task.
276 pub fn unshort_compare_clear(&self) { 312 pub fn unshort_compare_clear(&self) {
277 T::regs().shorts().modify(|w| w.set_compare_clear(self.n, false)) 313 self.r.shorts().modify(|w| w.set_compare_clear(self.n, false))
278 } 314 }
279 315
280 /// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task. 316 /// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task.
@@ -283,11 +319,11 @@ impl<'d, T: Instance> Cc<'d, T> {
283 /// 319 ///
284 /// So, when the timer's counter reaches the value stored in this register, the timer will stop counting up. 320 /// So, when the timer's counter reaches the value stored in this register, the timer will stop counting up.
285 pub fn short_compare_stop(&self) { 321 pub fn short_compare_stop(&self) {
286 T::regs().shorts().modify(|w| w.set_compare_stop(self.n, true)) 322 self.r.shorts().modify(|w| w.set_compare_stop(self.n, true))
287 } 323 }
288 324
289 /// Disable the shortcut between this CC register's COMPARE event and the timer's STOP task. 325 /// Disable the shortcut between this CC register's COMPARE event and the timer's STOP task.
290 pub fn unshort_compare_stop(&self) { 326 pub fn unshort_compare_stop(&self) {
291 T::regs().shorts().modify(|w| w.set_compare_stop(self.n, false)) 327 self.r.shorts().modify(|w| w.set_compare_stop(self.n, false))
292 } 328 }
293} 329}