2021-08-15 08:10:39 +10:00
|
|
|
//! Timer Peripheral
|
2021-01-26 07:42:43 +11:00
|
|
|
// See [Chapter 4 Section 6](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) for more details
|
2021-08-15 08:10:39 +10:00
|
|
|
|
2021-09-16 18:47:34 +10:00
|
|
|
use embedded_time::duration::Microseconds;
|
|
|
|
|
2021-11-15 04:46:35 +11:00
|
|
|
use crate::pac::{timer, RESETS, TIMER};
|
2021-10-02 15:41:04 +10:00
|
|
|
use crate::resets::SubsystemReset;
|
2021-11-15 04:46:35 +11:00
|
|
|
use core::marker::PhantomData;
|
2021-08-15 08:10:39 +10:00
|
|
|
|
|
|
|
/// Timer peripheral
|
|
|
|
pub struct Timer {
|
|
|
|
timer: TIMER,
|
2021-11-15 04:46:35 +11:00
|
|
|
alarms: [bool; 4],
|
2021-08-15 08:10:39 +10:00
|
|
|
}
|
|
|
|
|
2021-10-21 06:38:30 +11:00
|
|
|
// Safety: All access is read-only.
|
|
|
|
unsafe impl Sync for Timer {}
|
|
|
|
|
2021-08-15 08:10:39 +10:00
|
|
|
impl Timer {
|
|
|
|
/// Create a new [`Timer`]
|
2021-10-02 15:41:04 +10:00
|
|
|
pub fn new(timer: TIMER, resets: &mut RESETS) -> Self {
|
|
|
|
timer.reset_bring_up(resets);
|
2021-11-15 04:46:35 +11:00
|
|
|
Self {
|
|
|
|
timer,
|
|
|
|
alarms: [true; 4],
|
|
|
|
}
|
2021-08-15 08:10:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the current counter value.
|
|
|
|
pub fn get_counter(&self) -> u64 {
|
2021-09-16 18:47:34 +10:00
|
|
|
let mut hi0 = self.timer.timerawh.read().bits();
|
|
|
|
loop {
|
|
|
|
let low = self.timer.timerawl.read().bits();
|
|
|
|
let hi1 = self.timer.timerawh.read().bits();
|
|
|
|
if hi0 == hi1 {
|
|
|
|
break (u64::from(hi0) << 32) | u64::from(low);
|
|
|
|
}
|
|
|
|
hi0 = hi1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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,
|
|
|
|
period: Microseconds::new(0),
|
|
|
|
next_end: None,
|
|
|
|
}
|
|
|
|
}
|
2021-11-15 04:46:35 +11: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> {
|
|
|
|
if self.alarms[0] {
|
|
|
|
self.alarms[0] = false;
|
|
|
|
Some(Alarm0(PhantomData))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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> {
|
|
|
|
if self.alarms[1] {
|
|
|
|
self.alarms[1] = false;
|
|
|
|
Some(Alarm1(PhantomData))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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> {
|
|
|
|
if self.alarms[2] {
|
|
|
|
self.alarms[2] = false;
|
|
|
|
Some(Alarm2(PhantomData))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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> {
|
|
|
|
if self.alarms[3] {
|
|
|
|
self.alarms[3] = false;
|
|
|
|
Some(Alarm3(PhantomData))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2021-09-16 18:47:34 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Delay implementation
|
|
|
|
pub struct CountDown<'timer> {
|
|
|
|
timer: &'timer Timer,
|
|
|
|
period: embedded_time::duration::Microseconds<u64>,
|
|
|
|
next_end: Option<u64>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl embedded_hal::timer::CountDown for CountDown<'_> {
|
|
|
|
type Time = embedded_time::duration::Microseconds<u64>;
|
|
|
|
|
|
|
|
fn start<T>(&mut self, count: T)
|
|
|
|
where
|
|
|
|
T: Into<Self::Time>,
|
|
|
|
{
|
|
|
|
self.period = count.into();
|
|
|
|
self.next_end = Some(self.timer.get_counter().wrapping_add(self.period.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn wait(&mut self) -> nb::Result<(), void::Void> {
|
|
|
|
if let Some(end) = self.next_end {
|
|
|
|
let ts = self.timer.get_counter();
|
|
|
|
if ts >= end {
|
|
|
|
self.next_end = Some(end.wrapping_add(self.period.0));
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(nb::Error::WouldBlock)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
panic!("CountDown is not running!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-02 15:36:40 +10:00
|
|
|
#[cfg(feature = "eh1_0_alpha")]
|
|
|
|
impl eh1_0_alpha::timer::nb::CountDown for CountDown<'_> {
|
|
|
|
type Time = embedded_time::duration::Microseconds<u64>;
|
|
|
|
type Error = &'static str;
|
|
|
|
|
|
|
|
fn start<T>(&mut self, count: T) -> Result<(), Self::Error>
|
|
|
|
where
|
|
|
|
T: Into<Self::Time>,
|
|
|
|
{
|
|
|
|
self.period = count.into();
|
|
|
|
self.next_end = Some(self.timer.get_counter().wrapping_add(self.period.0));
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn wait(&mut self) -> nb::Result<(), Self::Error> {
|
|
|
|
if let Some(end) = self.next_end {
|
|
|
|
let ts = self.timer.get_counter();
|
|
|
|
if ts >= end {
|
|
|
|
self.next_end = Some(end.wrapping_add(self.period.0));
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(nb::Error::WouldBlock)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
panic!("CountDown is not running!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-16 18:47:34 +10:00
|
|
|
impl embedded_hal::timer::Periodic for CountDown<'_> {}
|
2021-10-02 15:36:40 +10:00
|
|
|
#[cfg(feature = "eh1_0_alpha")]
|
|
|
|
impl eh1_0_alpha::timer::Periodic for CountDown<'_> {}
|
|
|
|
|
2021-09-16 18:47:34 +10: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-15 08:10:39 +10:00
|
|
|
}
|
|
|
|
}
|
2021-10-02 15:36:40 +10:00
|
|
|
#[cfg(feature = "eh1_0_alpha")]
|
|
|
|
impl eh1_0_alpha::timer::nb::Cancel for CountDown<'_> {
|
|
|
|
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-11-15 04:46:35 +11: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<()>);
|
|
|
|
|
|
|
|
impl $name {
|
|
|
|
#[inline]
|
|
|
|
fn timer() -> &'static timer::RegisterBlock {
|
|
|
|
// # Safety
|
|
|
|
//
|
|
|
|
// This alarm should only have 1 instance available. This alarm
|
|
|
|
// only changes fields that are relevant to this alarm, and does
|
|
|
|
// not modify any other fields. Therefor it's safe to get a reference
|
|
|
|
// to this pointer.
|
|
|
|
unsafe { &*TIMER::ptr() }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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.
|
|
|
|
pub fn clear_interrupt(&mut self) {
|
|
|
|
Self::timer().intr.modify(|_, w| w.$int_alarm().set_bit());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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
|
|
|
|
pub fn enable_interrupt(&mut self) {
|
|
|
|
Self::timer().inte.modify(|_, w| w.$int_alarm().set_bit());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Schedule the alarm to be finished after `countdown`. If [enable_interrupt] is called, this will trigger interrupt `
|
|
|
|
#[doc = $int_name]
|
|
|
|
/// ` whenever this time elapses.
|
|
|
|
///
|
|
|
|
/// [enable_interrupt]: #method.enable_interrupt
|
|
|
|
pub fn schedule<TIME: Into<Microseconds>>(&mut self, countdown: TIME) {
|
|
|
|
let duration = countdown.into().0;
|
|
|
|
let target_time = Self::timer().timelr.read().bits().wrapping_add(duration);
|
|
|
|
Self::timer()
|
|
|
|
.$timer_alarm
|
|
|
|
.write(|w| unsafe { w.bits(target_time) });
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return true if this alarm is finished.
|
|
|
|
pub fn finished(&self) -> bool {
|
|
|
|
let bits: u32 = Self::timer().armed.read().bits();
|
|
|
|
(bits & $armed_bit_mask) > 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_alarm!(Alarm0 {
|
|
|
|
rb: alarm0,
|
|
|
|
int: alarm_0,
|
|
|
|
int_name: "IRQ_TIMER_0",
|
|
|
|
armed_bit_mask: 0b0001
|
|
|
|
});
|
|
|
|
|
|
|
|
impl_alarm!(Alarm1 {
|
|
|
|
rb: alarm1,
|
|
|
|
int: alarm_1,
|
|
|
|
int_name: "IRQ_TIMER_1",
|
|
|
|
armed_bit_mask: 0b0010
|
|
|
|
});
|
|
|
|
|
|
|
|
impl_alarm!(Alarm2 {
|
|
|
|
rb: alarm2,
|
|
|
|
int: alarm_2,
|
|
|
|
int_name: "IRQ_TIMER_2",
|
|
|
|
armed_bit_mask: 0b0100
|
|
|
|
});
|
|
|
|
|
|
|
|
impl_alarm!(Alarm3 {
|
|
|
|
rb: alarm3,
|
|
|
|
int: alarm_3,
|
|
|
|
int_name: "IRQ_TIMER_3",
|
|
|
|
armed_bit_mask: 0b1000
|
|
|
|
});
|