Skip to main content

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}