2021-08-14 17:10:39 -05:00
//! Timer Peripheral
2022-07-18 15:35:21 +10:00
//!
//! The Timer peripheral on RP2040 consists of a 64-bit counter and 4 alarms.
//! 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.
//! 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.
//!
//! Each of the 4 alarms can match on the lower 32 bits of Counter and trigger an interrupt.
//!
//! See [Chapter 4 Section 6](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) of the datasheet for more details.
2021-08-14 17:10:39 -05:00
2022-08-31 21:45:08 +01:00
use fugit ::{ MicrosDurationU32 , MicrosDurationU64 , TimerInstantU64 } ;
2021-09-16 09:47:34 +01:00
2022-01-30 22:44:19 +11:00
use crate ::atomic_register_access ::{ write_bitmask_clear , write_bitmask_set } ;
2021-11-20 08:46:47 +01:00
use crate ::pac ::{ RESETS , TIMER } ;
2021-10-02 07:41:04 +02:00
use crate ::resets ::SubsystemReset ;
2021-11-14 18:46:35 +01:00
use core ::marker ::PhantomData ;
2021-08-14 17:10:39 -05:00
2022-08-31 06:54:57 +01:00
/// Instant type used by the Timer & Alarm methods.
pub type Instant = TimerInstantU64 < 1_000_000 > ;
fn get_counter ( timer : & crate ::pac ::timer ::RegisterBlock ) -> Instant {
let mut hi0 = timer . timerawh . read ( ) . bits ( ) ;
let timestamp = loop {
let low = timer . timerawl . read ( ) . bits ( ) ;
let hi1 = timer . timerawh . read ( ) . bits ( ) ;
if hi0 = = hi1 {
break ( u64 ::from ( hi0 ) < < 32 ) | u64 ::from ( low ) ;
}
hi0 = hi1 ;
} ;
TimerInstantU64 ::from_ticks ( timestamp )
}
2021-08-14 17:10:39 -05:00
/// Timer peripheral
pub struct Timer {
timer : TIMER ,
2021-11-14 18:46:35 +01:00
alarms : [ bool ; 4 ] ,
2021-08-14 17:10:39 -05:00
}
impl Timer {
/// Create a new [`Timer`]
2021-10-02 07:41:04 +02:00
pub fn new ( timer : TIMER , resets : & mut RESETS ) -> Self {
2022-08-31 06:54:57 +01:00
timer . reset_bring_down ( resets ) ;
2021-10-02 07:41:04 +02:00
timer . reset_bring_up ( resets ) ;
2021-11-14 18:46:35 +01:00
Self {
timer ,
alarms : [ true ; 4 ] ,
}
2021-08-14 17:10:39 -05:00
}
/// Get the current counter value.
2022-08-31 06:54:57 +01:00
pub fn get_counter ( & self ) -> Instant {
get_counter ( & self . timer )
2021-09-16 09:47:34 +01:00
}
/// Get the value of the least significant word of the counter.
pub fn get_counter_low ( & self ) -> u32 {
self . timer . timerawl . read ( ) . bits ( )
}
/// Initialized a Count Down instance without starting it.
pub fn count_down ( & self ) -> CountDown < '_ > {
CountDown {
timer : self ,
2022-08-18 20:14:51 +01:00
period : MicrosDurationU64 ::nanos ( 0 ) ,
2021-09-16 09:47:34 +01:00
next_end : None ,
}
}
2021-11-14 18:46:35 +01:00
/// Retrieve a reference to alarm 0. Will only return a value the first time this is called
pub fn alarm_0 ( & mut self ) -> Option < Alarm0 > {
2022-07-28 02:26:24 +02:00
if self . alarms [ 0 ] {
self . alarms [ 0 ] = false ;
Some ( Alarm0 ( PhantomData ) )
} else {
None
}
2021-11-14 18:46:35 +01:00
}
/// Retrieve a reference to alarm 1. Will only return a value the first time this is called
pub fn alarm_1 ( & mut self ) -> Option < Alarm1 > {
2022-07-28 02:26:24 +02:00
if self . alarms [ 1 ] {
self . alarms [ 1 ] = false ;
Some ( Alarm1 ( PhantomData ) )
} else {
None
}
2021-11-14 18:46:35 +01:00
}
/// Retrieve a reference to alarm 2. Will only return a value the first time this is called
pub fn alarm_2 ( & mut self ) -> Option < Alarm2 > {
2022-07-28 02:26:24 +02:00
if self . alarms [ 2 ] {
self . alarms [ 2 ] = false ;
Some ( Alarm2 ( PhantomData ) )
} else {
None
}
2021-11-14 18:46:35 +01:00
}
/// Retrieve a reference to alarm 3. Will only return a value the first time this is called
pub fn alarm_3 ( & mut self ) -> Option < Alarm3 > {
2022-07-28 02:26:24 +02:00
if self . alarms [ 3 ] {
self . alarms [ 3 ] = false ;
Some ( Alarm3 ( PhantomData ) )
} else {
None
}
2021-11-14 18:46:35 +01:00
}
2021-09-16 09:47:34 +01:00
}
2022-07-18 15:35:21 +10:00
/// Implementation of the embedded_hal::Timer traits using rp2040_hal::timer counter
///
/// ## Usage
/// ```no_run
/// use embedded_hal::timer::{CountDown, Cancel};
2022-08-18 20:14:51 +01:00
/// use fugit::ExtU32;
2022-07-18 15:35:21 +10:00
/// use rp2040_hal;
/// let mut pac = rp2040_hal::pac::Peripherals::take().unwrap();
/// // Configure the Timer peripheral in count-down mode
/// let timer = rp2040_hal::Timer::new(pac.TIMER, &mut pac.RESETS);
/// let mut count_down = timer.count_down();
/// // Create a count_down timer for 500 milliseconds
2022-08-18 20:14:51 +01:00
/// count_down.start(500.millis());
2022-07-18 15:35:21 +10:00
/// // Block until timer has elapsed
/// let _ = nb::block!(count_down.wait());
/// // Restart the count_down timer with a period of 100 milliseconds
2022-08-18 20:14:51 +01:00
/// count_down.start(100.millis());
2022-07-18 15:35:21 +10:00
/// // Cancel it immediately
/// count_down.cancel();
/// ```
2021-09-16 09:47:34 +01:00
pub struct CountDown < ' timer > {
timer : & ' timer Timer ,
2022-08-18 20:14:51 +01:00
period : MicrosDurationU64 ,
2021-09-16 09:47:34 +01:00
next_end : Option < u64 > ,
}
impl embedded_hal ::timer ::CountDown for CountDown < '_ > {
2022-08-18 20:14:51 +01:00
type Time = MicrosDurationU64 ;
2021-09-16 09:47:34 +01:00
fn start < T > ( & mut self , count : T )
where
T : Into < Self ::Time > ,
{
self . period = count . into ( ) ;
2022-08-18 20:14:51 +01:00
self . next_end = Some (
self . timer
. get_counter ( )
2022-08-31 06:54:57 +01:00
. ticks ( )
2022-08-18 20:14:51 +01:00
. wrapping_add ( self . period . to_micros ( ) ) ,
) ;
2021-09-16 09:47:34 +01:00
}
fn wait ( & mut self ) -> nb ::Result < ( ) , void ::Void > {
if let Some ( end ) = self . next_end {
2022-08-31 06:54:57 +01:00
let ts = self . timer . get_counter ( ) . ticks ( ) ;
2021-09-16 09:47:34 +01:00
if ts > = end {
2022-08-18 20:14:51 +01:00
self . next_end = Some ( end . wrapping_add ( self . period . to_micros ( ) ) ) ;
2021-09-16 09:47:34 +01:00
Ok ( ( ) )
} else {
Err ( nb ::Error ::WouldBlock )
}
} else {
panic! ( " CountDown is not running! " ) ;
}
}
}
impl embedded_hal ::timer ::Periodic for CountDown < '_ > { }
2021-10-02 07:36:40 +02:00
2021-09-16 09:47:34 +01:00
impl embedded_hal ::timer ::Cancel for CountDown < '_ > {
type Error = & 'static str ;
fn cancel ( & mut self ) -> Result < ( ) , Self ::Error > {
if self . next_end . is_none ( ) {
Err ( " CountDown is not running. " )
} else {
self . next_end = None ;
Ok ( ( ) )
}
2021-08-14 17:10:39 -05:00
}
}
2021-11-14 18:46:35 +01:00
2022-04-17 23:03:11 +01:00
/// Alarm abstraction.
pub trait Alarm {
/// Clear the interrupt flag.
///
/// The interrupt is unable to trigger a 2nd time until this interrupt is cleared.
fn clear_interrupt ( & mut self ) ;
/// Enable this alarm to trigger an interrupt.
///
/// After this interrupt is triggered, make sure to clear the interrupt with [clear_interrupt].
///
/// [clear_interrupt]: #method.clear_interrupt
fn enable_interrupt ( & mut self ) ;
/// Disable this alarm, preventing it from triggering an interrupt.
fn disable_interrupt ( & mut self ) ;
/// Schedule the alarm to be finished after `countdown`. If [enable_interrupt] is called,
/// this will trigger interrupt whenever this time elapses.
///
/// [enable_interrupt]: #method.enable_interrupt
2022-08-31 21:45:08 +01:00
fn schedule ( & mut self , countdown : MicrosDurationU32 ) -> Result < ( ) , ScheduleAlarmError > ;
2022-04-17 23:03:11 +01:00
2022-08-31 06:54:57 +01:00
/// Schedule the alarm to be finished at the given timestamp. If [enable_interrupt] is
/// called, this will trigger interrupt whenever this timestamp is reached.
///
/// The RP2040 is unable to schedule an event taking place in more than
/// `u32::max_value()` microseconds.
///
/// [enable_interrupt]: #method.enable_interrupt
fn schedule_at ( & mut self , timestamp : Instant ) -> Result < ( ) , ScheduleAlarmError > ;
2022-04-17 23:03:11 +01:00
/// Return true if this alarm is finished.
fn finished ( & self ) -> bool ;
}
2021-11-14 18:46:35 +01:00
macro_rules ! impl_alarm {
( $name :ident { rb : $timer_alarm :ident , int : $int_alarm :ident , int_name : $int_name :tt , armed_bit_mask : $armed_bit_mask : expr } ) = > {
/// An alarm that can be used to schedule events in the future. Alarms can also be configured to trigger interrupts.
pub struct $name ( PhantomData < ( ) > ) ;
2022-08-31 06:54:57 +01:00
impl $name {
fn schedule_internal (
& mut self ,
timer : & crate ::pac ::timer ::RegisterBlock ,
timestamp : Instant ,
) -> Result < ( ) , ScheduleAlarmError > {
let timestamp_low = ( timestamp . ticks ( ) & 0xFFFF_FFFF ) as u32 ;
// This lock is for time-criticality
cortex_m ::interrupt ::free ( | _ | {
let alarm = & timer . $timer_alarm ;
// safety: This is the only code in the codebase that accesses memory address $timer_alarm
alarm . write ( | w | unsafe { w . bits ( timestamp_low ) } ) ;
// If it is not set, it has already triggered.
let now = get_counter ( timer ) ;
if now > timestamp & & ( timer . armed . read ( ) . bits ( ) & $armed_bit_mask ) ! = 0 {
// timestamp was set in the past
// safety: TIMER.armed is a write-clear register, and there can only be
// 1 instance of AlarmN so we can safely atomically clear this bit.
unsafe {
timer . armed . write_with_zero ( | w | w . bits ( $armed_bit_mask ) ) ;
}
return Err ( ScheduleAlarmError ::AlarmTooSoon ) ;
}
Ok ( ( ) )
} )
}
}
2021-11-14 18:46:35 +01:00
2022-04-17 23:03:11 +01:00
impl Alarm for $name {
2021-11-14 18:46:35 +01:00
/// Clear the interrupt flag. This should be called after interrupt `
#[ doc = $int_name ]
/// ` is called.
///
/// The interrupt is unable to trigger a 2nd time until this interrupt is cleared.
2022-04-17 23:03:11 +01:00
fn clear_interrupt ( & mut self ) {
2022-01-30 22:44:19 +11:00
// safety: TIMER.intr is a write-clear register, so we can atomically clear our interrupt
// by writing its value to this field
// Only one instance of this alarm index can exist, and only this alarm interacts with this bit
// of the TIMER.inte register
unsafe {
let timer = & ( * pac ::TIMER ::ptr ( ) ) ;
timer . intr . write_with_zero ( | w | w . $int_alarm ( ) . set_bit ( ) ) ;
}
2021-11-14 18:46:35 +01:00
}
/// Enable this alarm to trigger an interrupt. This alarm will trigger `
#[ doc = $int_name ]
/// `.
///
/// After this interrupt is triggered, make sure to clear the interrupt with [clear_interrupt].
///
/// [clear_interrupt]: #method.clear_interrupt
2022-04-17 23:03:11 +01:00
fn enable_interrupt ( & mut self ) {
2022-01-30 22:44:19 +11:00
// safety: using the atomic set alias means we can atomically set our interrupt enable bit.
// Only one instance of this alarm can exist, and only this alarm interacts with this bit
// of the TIMER.inte register
unsafe {
let timer = & ( * pac ::TIMER ::ptr ( ) ) ;
let reg = ( & timer . inte ) . as_ptr ( ) ;
write_bitmask_set ( reg , $armed_bit_mask ) ;
}
2021-11-14 18:46:35 +01:00
}
2021-11-16 16:50:44 +01:00
/// Disable this alarm, preventing it from triggering an interrupt.
2022-04-17 23:03:11 +01:00
fn disable_interrupt ( & mut self ) {
2022-01-30 22:44:19 +11:00
// safety: using the atomic set alias means we can atomically clear our interrupt enable bit.
// Only one instance of this alarm can exist, and only this alarm interacts with this bit
// of the TIMER.inte register
unsafe {
let timer = & ( * pac ::TIMER ::ptr ( ) ) ;
let reg = ( & timer . inte ) . as_ptr ( ) ;
write_bitmask_clear ( reg , $armed_bit_mask ) ;
}
2021-11-16 16:50:44 +01:00
}
2022-08-31 06:54:57 +01:00
/// Schedule the alarm to be finished after `countdown`. If [enable_interrupt] is called,
/// this will trigger interrupt `
2021-11-14 18:46:35 +01:00
#[ doc = $int_name ]
/// ` whenever this time elapses.
///
/// [enable_interrupt]: #method.enable_interrupt
2022-08-31 21:45:08 +01:00
fn schedule ( & mut self , countdown : MicrosDurationU32 ) -> Result < ( ) , ScheduleAlarmError > {
2022-08-31 06:54:57 +01:00
// safety: Only read operations are made on the timer and they should not have any UB
let timer = unsafe { & * TIMER ::ptr ( ) } ;
2022-08-31 21:45:08 +01:00
let timestamp = get_counter ( timer ) + countdown ;
2022-08-31 06:54:57 +01:00
self . schedule_internal ( timer , timestamp )
}
/// Schedule the alarm to be finished at the given timestamp. If [enable_interrupt] is
/// called, this will trigger interrupt `
#[ doc = $int_name ]
/// ` whenever this timestamp is reached.
///
/// The RP2040 is unable to schedule an event taking place in more than
/// `u32::max_value()` microseconds.
///
/// [enable_interrupt]: #method.enable_interrupt
fn schedule_at ( & mut self , timestamp : Instant ) -> Result < ( ) , ScheduleAlarmError > {
// safety: Only read operations are made on the timer and they should not have any UB
let timer = unsafe { & * TIMER ::ptr ( ) } ;
let now = get_counter ( timer ) ;
let duration = timestamp . ticks ( ) . saturating_sub ( now . ticks ( ) ) ;
if duration > u32 ::max_value ( ) . into ( ) {
return Err ( ScheduleAlarmError ::AlarmTooLate ) ;
2021-11-16 16:50:44 +01:00
}
2022-08-31 06:54:57 +01:00
self . schedule_internal ( timer , timestamp )
2021-11-14 18:46:35 +01:00
}
/// Return true if this alarm is finished.
2022-04-17 23:03:11 +01:00
fn finished ( & self ) -> bool {
2021-11-20 08:46:47 +01:00
// safety: This is a read action and should not have any UB
let bits : u32 = unsafe { & * TIMER ::ptr ( ) } . armed . read ( ) . bits ( ) ;
( bits & $armed_bit_mask ) = = 0
2021-11-14 18:46:35 +01:00
}
}
} ;
}
2021-11-16 16:50:44 +01:00
/// Errors that can be returned from any of the `AlarmX::schedule` methods.
#[ non_exhaustive ]
#[ derive(Copy, Clone, Debug, PartialEq, Eq, Hash) ]
pub enum ScheduleAlarmError {
/// Alarm time is too low. Should be at least 10 microseconds.
AlarmTooSoon ,
2022-08-31 06:54:57 +01:00
/// Alarm time is too high. Should not be more than `u32::max_value()` in the future.
AlarmTooLate ,
2021-11-16 16:50:44 +01:00
}
2021-11-14 18:46:35 +01:00
impl_alarm! ( Alarm0 {
rb : alarm0 ,
int : alarm_0 ,
2022-06-23 09:19:32 +00:00
int_name : " TIMER_IRQ_0 " ,
2021-11-14 18:46:35 +01:00
armed_bit_mask : 0b0001
} ) ;
impl_alarm! ( Alarm1 {
rb : alarm1 ,
int : alarm_1 ,
2022-06-23 09:19:32 +00:00
int_name : " TIMER_IRQ_1 " ,
2021-11-14 18:46:35 +01:00
armed_bit_mask : 0b0010
} ) ;
impl_alarm! ( Alarm2 {
rb : alarm2 ,
int : alarm_2 ,
2022-06-23 09:19:32 +00:00
int_name : " TIMER_IRQ_2 " ,
2021-11-14 18:46:35 +01:00
armed_bit_mask : 0b0100
} ) ;
impl_alarm! ( Alarm3 {
rb : alarm3 ,
int : alarm_3 ,
2022-06-23 09:19:32 +00:00
int_name : " TIMER_IRQ_3 " ,
2021-11-14 18:46:35 +01:00
armed_bit_mask : 0b1000
} ) ;