1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
//! Timer driver.
//!
//! Important note! This driver is very low level. For most time-related use cases, like
//! "sleep for X seconds", "do something every X seconds", or measuring time, you should
//! use [`embassy-time`](https://crates.io/crates/embassy-time) instead!
#![macro_use]
use embassy_hal_internal::{into_ref, PeripheralRef};
use crate::ppi::{Event, Task};
use crate::{pac, Peripheral};
pub(crate) mod sealed {
use super::*;
pub trait Instance {
/// The number of CC registers this instance has.
const CCS: usize;
fn regs() -> &'static pac::timer0::RegisterBlock;
}
pub trait ExtendedInstance {}
pub trait TimerType {}
}
/// Basic Timer instance.
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
/// Interrupt for this peripheral.
type Interrupt: crate::interrupt::typelevel::Interrupt;
}
/// Extended timer instance.
pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {}
macro_rules! impl_timer {
($type:ident, $pac_type:ident, $irq:ident, $ccs:literal) => {
impl crate::timer::sealed::Instance for peripherals::$type {
const CCS: usize = $ccs;
fn regs() -> &'static pac::timer0::RegisterBlock {
unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) }
}
}
impl crate::timer::Instance for peripherals::$type {
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
($type:ident, $pac_type:ident, $irq:ident) => {
impl_timer!($type, $pac_type, $irq, 4);
};
($type:ident, $pac_type:ident, $irq:ident, extended) => {
impl_timer!($type, $pac_type, $irq, 6);
impl crate::timer::sealed::ExtendedInstance for peripherals::$type {}
impl crate::timer::ExtendedInstance for peripherals::$type {}
};
}
/// Timer frequency
#[repr(u8)]
pub enum Frequency {
/// 16MHz
F16MHz = 0,
/// 8MHz
F8MHz = 1,
/// 4MHz
F4MHz = 2,
/// 2MHz
F2MHz = 3,
/// 1MHz
F1MHz = 4,
/// 500kHz
F500kHz = 5,
/// 250kHz
F250kHz = 6,
/// 125kHz
F125kHz = 7,
/// 62500Hz
F62500Hz = 8,
/// 31250Hz
F31250Hz = 9,
}
/// nRF Timer driver.
///
/// The timer has an internal counter, which is incremented for every tick of the timer.
/// The counter is 32-bit, so it wraps back to 0 when it reaches 2^32.
///
/// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter
/// or trigger an event when the counter reaches a certain value.
/// Timer driver.
pub struct Timer<'d, T: Instance> {
_p: PeripheralRef<'d, T>,
}
impl<'d, T: Instance> Timer<'d, T> {
/// Create a new `Timer` driver.
///
/// This can be useful for triggering tasks via PPI
/// `Uarte` uses this internally.
pub fn new(timer: impl Peripheral<P = T> + 'd) -> Self {
Self::new_inner(timer, false)
}
/// Create a new `Timer` driver in counter mode.
///
/// This can be useful for triggering tasks via PPI
/// `Uarte` uses this internally.
pub fn new_counter(timer: impl Peripheral<P = T> + 'd) -> Self {
Self::new_inner(timer, true)
}
fn new_inner(timer: impl Peripheral<P = T> + 'd, is_counter: bool) -> Self {
into_ref!(timer);
let regs = T::regs();
let this = Self { _p: timer };
// Stop the timer before doing anything else,
// since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
this.stop();
if is_counter {
regs.mode.write(|w| w.mode().low_power_counter());
} else {
regs.mode.write(|w| w.mode().timer());
}
// Make the counter's max value as high as possible.
// TODO: is there a reason someone would want to set this lower?
regs.bitmode.write(|w| w.bitmode()._32bit());
// Initialize the counter at 0.
this.clear();
// Default to the max frequency of the lower power clock
this.set_frequency(Frequency::F1MHz);
for n in 0..T::CCS {
let cc = this.cc(n);
// Initialize all the shorts as disabled.
cc.unshort_compare_clear();
cc.unshort_compare_stop();
// Initialize the CC registers as 0.
cc.write(0);
}
this
}
/// Starts the timer.
pub fn start(&self) {
T::regs().tasks_start.write(|w| unsafe { w.bits(1) })
}
/// Stops the timer.
pub fn stop(&self) {
T::regs().tasks_stop.write(|w| unsafe { w.bits(1) })
}
/// Reset the timer's counter to 0.
pub fn clear(&self) {
T::regs().tasks_clear.write(|w| unsafe { w.bits(1) })
}
/// Returns the START task, for use with PPI.
///
/// When triggered, this task starts the timer.
pub fn task_start(&self) -> Task<'d> {
Task::from_reg(&T::regs().tasks_start)
}
/// Returns the STOP task, for use with PPI.
///
/// When triggered, this task stops the timer.
pub fn task_stop(&self) -> Task<'d> {
Task::from_reg(&T::regs().tasks_stop)
}
/// Returns the CLEAR task, for use with PPI.
///
/// When triggered, this task resets the timer's counter to 0.
pub fn task_clear(&self) -> Task<'d> {
Task::from_reg(&T::regs().tasks_clear)
}
/// Returns the COUNT task, for use with PPI.
///
/// When triggered, this task increments the timer's counter by 1.
/// Only works in counter mode.
pub fn task_count(&self) -> Task<'d> {
Task::from_reg(&T::regs().tasks_count)
}
/// Change the timer's frequency.
///
/// This will stop the timer if it isn't already stopped,
/// because the timer may exhibit 'unpredictable behaviour' if it's frequency is changed while it's running.
pub fn set_frequency(&self, frequency: Frequency) {
self.stop();
T::regs()
.prescaler
// SAFETY: `frequency` is a variant of `Frequency`,
// whose values are all in the range of 0-9 (the valid range of `prescaler`).
.write(|w| unsafe { w.prescaler().bits(frequency as u8) })
}
/// Returns this timer's `n`th CC register.
///
/// # Panics
/// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer).
pub fn cc(&self, n: usize) -> Cc<'d, T> {
if n >= T::CCS {
panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS);
}
Cc {
n,
_p: unsafe { self._p.clone_unchecked() },
}
}
}
/// A representation of a timer's Capture/Compare (CC) register.
///
/// A CC register holds a 32-bit value.
/// 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.
///
/// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register.
/// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register
pub struct Cc<'d, T: Instance> {
n: usize,
_p: PeripheralRef<'d, T>,
}
impl<'d, T: Instance> Cc<'d, T> {
/// Get the current value stored in the register.
pub fn read(&self) -> u32 {
T::regs().cc[self.n].read().cc().bits()
}
/// Set the value stored in the register.
///
/// `event_compare` will fire when the timer's counter reaches this value.
pub fn write(&self, value: u32) {
// SAFETY: there are no invalid values for the CC register.
T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) })
}
/// Capture the current value of the timer's counter in this register, and return it.
pub fn capture(&self) -> u32 {
T::regs().tasks_capture[self.n].write(|w| unsafe { w.bits(1) });
self.read()
}
/// Returns this CC register's CAPTURE task, for use with PPI.
///
/// When triggered, this task will capture the current value of the timer's counter in this register.
pub fn task_capture(&self) -> Task<'d> {
Task::from_reg(&T::regs().tasks_capture)
}
/// Returns this CC register's COMPARE event, for use with PPI.
///
/// This event will fire when the timer's counter reaches the value in this CC register.
pub fn event_compare(&self) -> Event<'d> {
Event::from_reg(&T::regs().events_compare[self.n])
}
/// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task.
///
/// This means that when the COMPARE event is fired, the CLEAR task will be triggered.
///
/// So, when the timer's counter reaches the value stored in this register, the timer's counter will be reset to 0.
pub fn short_compare_clear(&self) {
T::regs()
.shorts
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.n)) })
}
/// Disable the shortcut between this CC register's COMPARE event and the timer's CLEAR task.
pub fn unshort_compare_clear(&self) {
T::regs()
.shorts
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.n)) })
}
/// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task.
///
/// This means that when the COMPARE event is fired, the STOP task will be triggered.
///
/// So, when the timer's counter reaches the value stored in this register, the timer will stop counting up.
pub fn short_compare_stop(&self) {
T::regs()
.shorts
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << (8 + self.n))) })
}
/// Disable the shortcut between this CC register's COMPARE event and the timer's STOP task.
pub fn unshort_compare_stop(&self) {
T::regs()
.shorts
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << (8 + self.n))) })
}
}