diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-06-29 07:37:06 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-06-29 07:37:06 +0200 |
| commit | d49adc98beebe5b7982204150ebdc0a485fefab2 (patch) | |
| tree | 4c51df41daf9b180eecbe584b50a46163aade0ce /embassy-nrf/src/timer.rs | |
| parent | f501907f9e69c1d47571b6e0980f22dde723b45d (diff) | |
| parent | c0ef40d6e9ee91ef754e90424ecd76fd80c0f125 (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.rs | 310 |
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 | ||
| 3 | use core::marker::PhantomData; | ||
| 4 | use core::task::Poll; | ||
| 5 | |||
| 3 | use embassy::interrupt::Interrupt; | 6 | use embassy::interrupt::Interrupt; |
| 7 | use embassy::interrupt::InterruptExt; | ||
| 8 | use embassy::util::OnDrop; | ||
| 4 | use embassy::util::Unborrow; | 9 | use embassy::util::Unborrow; |
| 10 | use embassy_extras::unborrow; | ||
| 11 | use futures::future::poll_fn; | ||
| 5 | 12 | ||
| 6 | use crate::pac; | 13 | use crate::pac; |
| 14 | use crate::ppi::Event; | ||
| 15 | use crate::ppi::Task; | ||
| 7 | 16 | ||
| 8 | pub(crate) mod sealed { | 17 | pub(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 { | |||
| 20 | pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} | 35 | pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} |
| 21 | 36 | ||
| 22 | macro_rules! impl_timer { | 37 | macro_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)] | ||
| 66 | pub 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. | ||
| 87 | pub struct Timer<'d, T: Instance> { | ||
| 88 | phantom: PhantomData<&'d mut T>, | ||
| 89 | } | ||
| 90 | |||
| 91 | impl<'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 | ||
| 233 | pub struct Cc<'a, T: Instance> { | ||
| 234 | n: usize, | ||
| 235 | phantom: PhantomData<&'a mut T>, | ||
| 236 | } | ||
| 237 | |||
| 238 | impl<'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 | } | ||
