diff options
| author | Matteo Meluzzi <[email protected]> | 2025-10-02 10:53:31 +0200 |
|---|---|---|
| committer | Matteo Meluzzi <[email protected]> | 2025-10-02 10:53:31 +0200 |
| commit | 828a8df18d04877df1f55f04354980b28ff2f2f8 (patch) | |
| tree | c4fa405f5eba7a14b6d435d6cc746c9e0dc52632 /embassy-nrf/src/timer.rs | |
| parent | 176649e71ad442ca9856af6c11989b0b2f228c4b (diff) | |
| parent | 194a721d0eab929a2af0a2a4e45ca8e70e0d3f0a (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.rs | 110 |
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 | ||
| 9 | use core::marker::PhantomData; | ||
| 10 | |||
| 9 | use embassy_hal_internal::{Peri, PeripheralType}; | 11 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 10 | 12 | ||
| 11 | use crate::pac; | 13 | use 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 | 86 | pub struct Timer<'d> { | |
| 85 | /// Timer driver. | 87 | r: pac::timer::Timer, |
| 86 | pub struct Timer<'d, T: Instance> { | 88 | ccs: usize, |
| 87 | _p: Peri<'d, T>, | 89 | _p: PhantomData<&'d ()>, |
| 88 | } | 90 | } |
| 89 | 91 | ||
| 90 | impl<'d, T: Instance> Timer<'d, T> { | 92 | impl<'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 | ||
| 235 | impl 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 | |||
| 244 | impl<'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 |
| 228 | pub struct Cc<'d, T: Instance> { | 257 | pub 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 | ||
| 233 | impl<'d, T: Instance> Cc<'d, T> { | 263 | impl<'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 | } |
