rp235x_hal/timer.rs
1//! Timer Peripheral
2//!
3//! The Timer peripheral on rp235x consists of a 64-bit counter and 4 alarms.
4//! The Counter is incremented once per microsecond. It obtains its clock source from the watchdog peripheral, you must enable the watchdog before using this peripheral.
5//! Since it would take thousands of years for this counter to overflow you do not need to write logic for dealing with this if using get_counter.
6//!
7//! Each of the 4 alarms can match on the lower 32 bits of Counter and trigger an interrupt.
8//!
9//! See [Section 12.8](https://rptl.io/rp2350-datasheet) of the datasheet for more details.
10
11use core::sync::atomic::{AtomicU8, Ordering};
12use fugit::{MicrosDurationU32, MicrosDurationU64, TimerInstantU64};
13
14use crate::{
15 atomic_register_access::{write_bitmask_clear, write_bitmask_set},
16 clocks::ClocksManager,
17 pac,
18 resets::SubsystemReset,
19 typelevel::Sealed,
20};
21
22/// Instant type used by the Timer & Alarm methods.
23pub type Instant = TimerInstantU64<1_000_000>;
24
25static ALARMS_TIMER0: AtomicU8 = AtomicU8::new(0x00);
26static ALARMS_TIMER1: AtomicU8 = AtomicU8::new(0x00);
27
28fn take_alarm(mask: u8, alarms: &'static AtomicU8) -> bool {
29 let current_alarms = alarms.fetch_or(mask, Ordering::Relaxed);
30 (current_alarms & mask) == 0
31}
32
33fn release_alarm(mask: u8, alarms: &'static AtomicU8) {
34 alarms.fetch_and(!mask, Ordering::Relaxed);
35}
36
37/// Represents Timer0
38///
39/// But unlike the PAC object, we can copy this one when we duplicate the timer.
40#[derive(Clone, Copy)]
41pub struct CopyableTimer0 {
42 _inner: (),
43}
44
45/// Represents Timer1
46///
47/// But unlike the PAC object, we can copy this one when we duplicate the timer.
48#[derive(Clone, Copy)]
49pub struct CopyableTimer1 {
50 _inner: (),
51}
52
53/// Trait to handle both underlying devices (TIMER0 and TIMER1)
54pub trait TimerDevice: Sealed + Clone + Copy + 'static {
55 /// Index of the Timer.
56 const ID: usize;
57
58 /// Get a timer registerblock, pointing at the appropriate timer
59 fn get_perif() -> &'static pac::timer0::RegisterBlock {
60 if Self::ID == 0 {
61 unsafe { &*pac::TIMER0::ptr() }
62 } else {
63 unsafe { &*pac::TIMER1::ptr() }
64 }
65 }
66
67 /// Get the static AtomicU8 for managing alarms.
68 fn get_alarms_tracker() -> &'static AtomicU8 {
69 if Self::ID == 0 {
70 &ALARMS_TIMER0
71 } else {
72 &ALARMS_TIMER1
73 }
74 }
75}
76
77impl TimerDevice for CopyableTimer0 {
78 const ID: usize = 0;
79}
80impl Sealed for CopyableTimer0 {}
81impl TimerDevice for CopyableTimer1 {
82 const ID: usize = 1;
83}
84impl Sealed for CopyableTimer1 {}
85
86/// Timer peripheral
87//
88// This struct logically wraps a `pac::TIMERx`, but doesn't actually store it:
89// As after initialization all accesses are read-only anyways, the `pac::TIMER` can
90// be summoned unsafely instead. This allows timer to be cloned.
91//
92// (Alarms do use write operations, but they are local to the respective alarm, and
93// those are still owned singletons.)
94//
95// As the timer peripheral needs to be started first, this struct can only be
96// constructed by calling `Timer::new(...)`.
97#[derive(Copy, Clone)]
98pub struct Timer<D: TimerDevice> {
99 _device: core::marker::PhantomData<D>,
100}
101
102impl Timer<CopyableTimer0> {
103 /// Create a new [`Timer`] using `TIMER0`
104 ///
105 /// Make sure that clocks and watchdog are configured, so
106 /// that timer ticks happen at a frequency of 1MHz.
107 /// Otherwise, `Timer` won't work as expected.
108 pub fn new_timer0(
109 timer: pac::TIMER0,
110 resets: &mut pac::RESETS,
111 _clocks: &ClocksManager,
112 ) -> Self {
113 timer.reset_bring_down(resets);
114 timer.reset_bring_up(resets);
115 Self {
116 _device: core::marker::PhantomData,
117 }
118 }
119}
120
121impl Timer<CopyableTimer1> {
122 /// Create a new [`Timer`] using `TIMER1`
123 ///
124 /// Make sure that clocks and watchdog are configured, so
125 /// that timer ticks happen at a frequency of 1MHz.
126 /// Otherwise, `Timer` won't work as expected.
127 pub fn new_timer1(
128 timer: pac::TIMER1,
129 resets: &mut pac::RESETS,
130 _clocks: &ClocksManager,
131 ) -> Self {
132 timer.reset_bring_down(resets);
133 timer.reset_bring_up(resets);
134 Self {
135 _device: core::marker::PhantomData,
136 }
137 }
138}
139
140impl<D> Timer<D>
141where
142 D: TimerDevice,
143{
144 /// Get the current counter value.
145 pub fn get_counter(&self) -> Instant {
146 // Safety: Only used for reading current timer value
147 let timer = D::get_perif();
148 let mut hi0 = timer.timerawh().read().bits();
149 let timestamp = loop {
150 let low = timer.timerawl().read().bits();
151 let hi1 = timer.timerawh().read().bits();
152 if hi0 == hi1 {
153 break (u64::from(hi0) << 32) | u64::from(low);
154 }
155 hi0 = hi1;
156 };
157 TimerInstantU64::from_ticks(timestamp)
158 }
159
160 /// Get the value of the least significant word of the counter.
161 pub fn get_counter_low(&self) -> u32 {
162 // Safety: Only used for reading current timer value
163 let timer = D::get_perif();
164 timer.timerawl().read().bits()
165 }
166
167 /// Initialized a Count Down instance without starting it.
168 pub fn count_down(&self) -> CountDown<'_, D> {
169 CountDown {
170 timer: self,
171 period: MicrosDurationU64::nanos(0),
172 next_end: None,
173 }
174 }
175 /// Retrieve a reference to alarm 0. Will only return a value the first time this is called
176 pub fn alarm_0(&mut self) -> Option<Alarm0<D>> {
177 take_alarm(1 << 0, <D>::get_alarms_tracker()).then_some(Alarm0(*self))
178 }
179
180 /// Retrieve a reference to alarm 1. Will only return a value the first time this is called
181 pub fn alarm_1(&mut self) -> Option<Alarm1<D>> {
182 take_alarm(1 << 1, <D>::get_alarms_tracker()).then_some(Alarm1(*self))
183 }
184
185 /// Retrieve a reference to alarm 2. Will only return a value the first time this is called
186 pub fn alarm_2(&mut self) -> Option<Alarm2<D>> {
187 take_alarm(1 << 2, <D>::get_alarms_tracker()).then_some(Alarm2(*self))
188 }
189
190 /// Retrieve a reference to alarm 3. Will only return a value the first time this is called
191 pub fn alarm_3(&mut self) -> Option<Alarm3<D>> {
192 take_alarm(1 << 3, <D>::get_alarms_tracker()).then_some(Alarm3(*self))
193 }
194
195 /// Pauses execution for at minimum `us` microseconds.
196 fn delay_us_internal(&self, mut us: u32) {
197 let mut start = self.get_counter_low();
198 // If we knew that the loop ran at least once per timer tick,
199 // this could be simplified to:
200 // ```
201 // while timer.timelr().read().bits().wrapping_sub(start) <= us {
202 // crate::arch::nop();
203 // }
204 // ```
205 // However, due to interrupts, for `us == u32::MAX`, we could
206 // miss the moment where the loop should terminate if the loop skips
207 // a timer tick.
208 loop {
209 let now = self.get_counter_low();
210 let waited = now.wrapping_sub(start);
211 if waited >= us {
212 break;
213 }
214 start = now;
215 us -= waited;
216 }
217 }
218}
219
220macro_rules! impl_delay_traits {
221 ($($t:ty),+) => {
222 $(
223 impl<D> embedded_hal_0_2::blocking::delay::DelayUs<$t> for Timer<D> where D: TimerDevice {
224 fn delay_us(&mut self, us: $t) {
225 #![allow(unused_comparisons)]
226 assert!(us >= 0); // Only meaningful for i32
227 self.delay_us_internal(us as u32)
228 }
229 }
230 impl<D> embedded_hal_0_2::blocking::delay::DelayMs<$t> for Timer<D> where D: TimerDevice {
231 fn delay_ms(&mut self, ms: $t) {
232 #![allow(unused_comparisons)]
233 assert!(ms >= 0); // Only meaningful for i32
234 for _ in 0..ms {
235 self.delay_us_internal(1000);
236 }
237 }
238 }
239 )*
240 }
241}
242
243// The implementation for i32 is a workaround to allow `delay_ms(42)` construction without specifying a type.
244impl_delay_traits!(u8, u16, u32, i32);
245
246impl<D> embedded_hal::delay::DelayNs for Timer<D>
247where
248 D: TimerDevice,
249{
250 fn delay_ns(&mut self, ns: u32) {
251 // For now, just use microsecond delay, internally. Of course, this
252 // might cause a much longer delay than necessary. So a more advanced
253 // implementation would be desirable for sub-microsecond delays.
254 let us = ns.div_ceil(1000);
255 self.delay_us_internal(us)
256 }
257
258 fn delay_us(&mut self, us: u32) {
259 self.delay_us_internal(us)
260 }
261
262 fn delay_ms(&mut self, ms: u32) {
263 for _ in 0..ms {
264 self.delay_us_internal(1000);
265 }
266 }
267}
268
269/// Implementation of the [`embedded_hal_0_2::timer`] traits using [`rp235x_hal::timer`](crate::timer) counter.
270///
271/// There is no Embedded HAL 1.0 equivalent at this time.
272///
273/// If all you need is a delay, [`Timer`] does implement [`embedded_hal::delay::DelayNs`].
274///
275/// ## Usage
276/// ```no_run
277/// use embedded_hal_0_2::timer::{Cancel, CountDown};
278/// use fugit::ExtU32;
279/// use rp235x_hal;
280/// let mut pac = rp235x_hal::pac::Peripherals::take().unwrap();
281/// // Make sure to initialize clocks, otherwise the timer wouldn't work
282/// // properly. Omitted here for terseness.
283/// let clocks: rp235x_hal::clocks::ClocksManager = todo!();
284/// // Configure the Timer peripheral in count-down mode
285/// let timer = rp235x_hal::Timer::new_timer0(pac.TIMER0, &mut pac.RESETS, &clocks);
286/// let mut count_down = timer.count_down();
287/// // Create a count_down timer for 500 milliseconds
288/// count_down.start(500.millis());
289/// // Block until timer has elapsed
290/// let _ = nb::block!(count_down.wait());
291/// // Restart the count_down timer with a period of 100 milliseconds
292/// count_down.start(100.millis());
293/// // Cancel it immediately
294/// count_down.cancel();
295/// ```
296pub struct CountDown<'timer, D>
297where
298 D: TimerDevice,
299{
300 timer: &'timer Timer<D>,
301 period: MicrosDurationU64,
302 next_end: Option<u64>,
303}
304
305impl<D> embedded_hal_0_2::timer::CountDown for CountDown<'_, D>
306where
307 D: TimerDevice,
308{
309 type Time = MicrosDurationU64;
310
311 fn start<T>(&mut self, count: T)
312 where
313 T: Into<Self::Time>,
314 {
315 self.period = count.into();
316 self.next_end = Some(
317 self.timer
318 .get_counter()
319 .ticks()
320 .wrapping_add(self.period.to_micros()),
321 );
322 }
323
324 fn wait(&mut self) -> nb::Result<(), void::Void> {
325 if let Some(end) = self.next_end {
326 let ts = self.timer.get_counter().ticks();
327 if ts >= end {
328 self.next_end = Some(end.wrapping_add(self.period.to_micros()));
329 Ok(())
330 } else {
331 Err(nb::Error::WouldBlock)
332 }
333 } else {
334 panic!("CountDown is not running!");
335 }
336 }
337}
338
339impl<D> embedded_hal_0_2::timer::Periodic for CountDown<'_, D> where D: TimerDevice {}
340
341impl<D> embedded_hal_0_2::timer::Cancel for CountDown<'_, D>
342where
343 D: TimerDevice,
344{
345 type Error = &'static str;
346
347 fn cancel(&mut self) -> Result<(), Self::Error> {
348 if self.next_end.is_none() {
349 Err("CountDown is not running.")
350 } else {
351 self.next_end = None;
352 Ok(())
353 }
354 }
355}
356
357/// Alarm abstraction.
358pub trait Alarm: Sealed {
359 /// Clear the interrupt flag.
360 ///
361 /// The interrupt is unable to trigger a 2nd time until this interrupt is cleared.
362 fn clear_interrupt(&mut self);
363
364 /// Enable this alarm to trigger an interrupt.
365 ///
366 /// After this interrupt is triggered, make sure to clear the interrupt with [clear_interrupt].
367 ///
368 /// [clear_interrupt]: #method.clear_interrupt
369 fn enable_interrupt(&mut self);
370
371 /// Disable this alarm, preventing it from triggering an interrupt.
372 fn disable_interrupt(&mut self);
373
374 /// Schedule the alarm to be finished after `countdown`. If [enable_interrupt] is called,
375 /// this will trigger interrupt whenever this time elapses.
376 ///
377 /// [enable_interrupt]: #method.enable_interrupt
378 fn schedule(&mut self, countdown: MicrosDurationU32) -> Result<(), ScheduleAlarmError>;
379
380 /// Schedule the alarm to be finished at the given timestamp. If [enable_interrupt] is
381 /// called, this will trigger interrupt whenever this timestamp is reached.
382 ///
383 /// The rp235x is unable to schedule an event taking place in more than
384 /// `u32::MAX` microseconds.
385 ///
386 /// [enable_interrupt]: #method.enable_interrupt
387 fn schedule_at(&mut self, timestamp: Instant) -> Result<(), ScheduleAlarmError>;
388
389 /// Return true if this alarm is finished. The returned value is undefined if the alarm
390 /// has not been scheduled yet.
391 fn finished(&self) -> bool;
392
393 /// Cancel an activated alarm.
394 fn cancel(&mut self) -> Result<(), ScheduleAlarmError>;
395}
396
397macro_rules! impl_alarm {
398 ($name:ident { rb: $timer_alarm:ident, int: $int_alarm:ident, int_name: $int_name:tt, armed_bit_mask: $armed_bit_mask: expr }) => {
399 /// An alarm that can be used to schedule events in the future. Alarms can also be configured to trigger interrupts.
400 pub struct $name<D>(Timer<D>)
401 where
402 D: TimerDevice;
403 impl<D> $name<D>
404 where
405 D: TimerDevice,
406 {
407 fn schedule_internal(&mut self, timestamp: Instant) -> Result<(), ScheduleAlarmError> {
408 let timestamp_low = (timestamp.ticks() & 0xFFFF_FFFF) as u32;
409 let timer = D::get_perif();
410
411 // This lock is for time-criticality
412 crate::arch::interrupt_free(|| {
413 let alarm = timer.$timer_alarm();
414
415 // safety: This is the only code in the codebase that accesses memory address $timer_alarm
416 alarm.write(|w| unsafe { w.bits(timestamp_low) });
417
418 // If it is not set, it has already triggered.
419 let now = self.0.get_counter();
420 if now > timestamp && (timer.armed().read().bits() & $armed_bit_mask) != 0 {
421 // timestamp was set to a value in the past
422
423 // safety: TIMER.armed is a write-clear register, and there can only be
424 // 1 instance of AlarmN so we can safely atomically clear this bit.
425 unsafe {
426 timer.armed().write_with_zero(|w| w.bits($armed_bit_mask));
427 crate::atomic_register_access::write_bitmask_set(
428 timer.intf().as_ptr(),
429 $armed_bit_mask,
430 );
431 }
432 }
433 Ok(())
434 })
435 }
436 }
437
438 impl<D> Alarm for $name<D>
439 where
440 D: TimerDevice,
441 {
442 /// Clear the interrupt flag. This should be called after interrupt `
443 #[doc = $int_name]
444 /// ` is called.
445 ///
446 /// The interrupt is unable to trigger a 2nd time until this interrupt is cleared.
447 fn clear_interrupt(&mut self) {
448 // safety: TIMER.intr is a write-clear register, so we can atomically clear our interrupt
449 // by writing its value to this field
450 // Only one instance of this alarm index can exist, and only this alarm interacts with this bit
451 // of the TIMER.inte register
452 unsafe {
453 let timer = D::get_perif();
454 crate::atomic_register_access::write_bitmask_clear(
455 timer.intf().as_ptr(),
456 $armed_bit_mask,
457 );
458 timer
459 .intr()
460 .write_with_zero(|w| w.$int_alarm().clear_bit_by_one());
461 }
462 }
463
464 /// Enable this alarm to trigger an interrupt. This alarm will trigger `
465 #[doc = $int_name]
466 /// `.
467 ///
468 /// After this interrupt is triggered, make sure to clear the interrupt with [clear_interrupt].
469 ///
470 /// [clear_interrupt]: #method.clear_interrupt
471 fn enable_interrupt(&mut self) {
472 // safety: using the atomic set alias means we can atomically set our interrupt enable bit.
473 // Only one instance of this alarm can exist, and only this alarm interacts with this bit
474 // of the TIMER.inte register
475 unsafe {
476 let timer = D::get_perif();
477 let reg = timer.inte().as_ptr();
478 write_bitmask_set(reg, $armed_bit_mask);
479 }
480 }
481
482 /// Disable this alarm, preventing it from triggering an interrupt.
483 fn disable_interrupt(&mut self) {
484 // safety: using the atomic set alias means we can atomically clear our interrupt enable bit.
485 // Only one instance of this alarm can exist, and only this alarm interacts with this bit
486 // of the TIMER.inte register
487 unsafe {
488 let timer = D::get_perif();
489 let reg = timer.inte().as_ptr();
490 write_bitmask_clear(reg, $armed_bit_mask);
491 }
492 }
493
494 /// Schedule the alarm to be finished after `countdown`. If [enable_interrupt] is called,
495 /// this will trigger interrupt `
496 #[doc = $int_name]
497 /// ` whenever this time elapses.
498 ///
499 /// [enable_interrupt]: #method.enable_interrupt
500 fn schedule(&mut self, countdown: MicrosDurationU32) -> Result<(), ScheduleAlarmError> {
501 let timestamp = self.0.get_counter() + countdown;
502 self.schedule_internal(timestamp)
503 }
504
505 /// Schedule the alarm to be finished at the given timestamp. If [enable_interrupt] is
506 /// called, this will trigger interrupt `
507 #[doc = $int_name]
508 /// ` whenever this timestamp is reached.
509 ///
510 /// The rp235x is unable to schedule an event taking place in more than
511 /// `u32::MAX` microseconds.
512 ///
513 /// [enable_interrupt]: #method.enable_interrupt
514 fn schedule_at(&mut self, timestamp: Instant) -> Result<(), ScheduleAlarmError> {
515 let now = self.0.get_counter();
516 let duration = timestamp.ticks().saturating_sub(now.ticks());
517 if duration > u32::MAX.into() {
518 return Err(ScheduleAlarmError::AlarmTooLate);
519 }
520
521 self.schedule_internal(timestamp)
522 }
523
524 /// Return true if this alarm is finished. The returned value is undefined if the alarm
525 /// has not been scheduled yet.
526 fn finished(&self) -> bool {
527 // safety: This is a read action and should not have any UB
528 let timer = D::get_perif();
529 let bits: u32 = timer.armed().read().bits();
530 (bits & $armed_bit_mask) == 0
531 }
532
533 /// Cancel an activated Alarm. No negative effects if it's already disabled.
534 /// Unlike `timer::cancel` trait, this only cancels the alarm and keeps the timer running
535 /// if it's already active.
536 fn cancel(&mut self) -> Result<(), ScheduleAlarmError> {
537 unsafe {
538 let timer = D::get_perif();
539 timer.armed().write_with_zero(|w| w.bits($armed_bit_mask));
540 crate::atomic_register_access::write_bitmask_clear(
541 timer.intf().as_ptr(),
542 $armed_bit_mask,
543 );
544 }
545
546 Ok(())
547 }
548 }
549
550 impl<D> Sealed for $name<D> where D: TimerDevice {}
551
552 impl<D> Drop for $name<D>
553 where
554 D: TimerDevice,
555 {
556 fn drop(&mut self) {
557 self.disable_interrupt();
558 release_alarm($armed_bit_mask, D::get_alarms_tracker());
559 }
560 }
561 };
562}
563
564/// Errors that can be returned from any of the `AlarmX::schedule` methods.
565#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
566pub enum ScheduleAlarmError {
567 /// Alarm time is too high. Should not be more than `u32::MAX` in the future.
568 AlarmTooLate,
569}
570
571impl_alarm!(Alarm0 {
572 rb: alarm0,
573 int: alarm_0,
574 int_name: "TIMER_IRQ_0",
575 armed_bit_mask: 0b0001
576});
577
578impl_alarm!(Alarm1 {
579 rb: alarm1,
580 int: alarm_1,
581 int_name: "TIMER_IRQ_1",
582 armed_bit_mask: 0b0010
583});
584
585impl_alarm!(Alarm2 {
586 rb: alarm2,
587 int: alarm_2,
588 int_name: "TIMER_IRQ_2",
589 armed_bit_mask: 0b0100
590});
591
592impl_alarm!(Alarm3 {
593 rb: alarm3,
594 int: alarm_3,
595 int_name: "TIMER_IRQ_3",
596 armed_bit_mask: 0b1000
597});
598
599/// Support for RTIC monotonic trait.
600#[cfg(feature = "rtic-monotonic")]
601pub mod monotonic {
602 use super::{Alarm, Instant, Timer, TimerDevice};
603 use fugit::ExtU32;
604
605 /// RTIC Monotonic Implementation
606 pub struct Monotonic<D: TimerDevice, A>(pub Timer<D>, A);
607
608 impl<D: TimerDevice, A: Alarm> Monotonic<D, A> {
609 /// Creates a new monotonic.
610 pub const fn new(timer: Timer<D>, alarm: A) -> Self {
611 Self(timer, alarm)
612 }
613 }
614 impl<D: TimerDevice, A: Alarm> rtic_monotonic::Monotonic for Monotonic<D, A> {
615 type Instant = Instant;
616 type Duration = fugit::MicrosDurationU64;
617
618 const DISABLE_INTERRUPT_ON_EMPTY_QUEUE: bool = false;
619
620 fn now(&mut self) -> Instant {
621 self.0.get_counter()
622 }
623
624 fn set_compare(&mut self, instant: Instant) {
625 // The alarm can only trigger up to 2^32 - 1 ticks in the future.
626 // So, if `instant` is more than 2^32 - 2 in the future, we use `max_instant` instead.
627 let max_instant = self.0.get_counter() + 0xFFFF_FFFE.micros();
628 let wake_at = core::cmp::min(instant, max_instant);
629
630 // Cannot fail
631 let _ = self.1.schedule_at(wake_at);
632 self.1.enable_interrupt();
633 }
634
635 fn clear_compare_flag(&mut self) {
636 self.1.clear_interrupt();
637 }
638
639 fn zero() -> Self::Instant {
640 Instant::from_ticks(0)
641 }
642
643 unsafe fn reset(&mut self) {}
644 }
645}