#![cfg_attr(
not(feature = "esp32"),
doc = "See the [timg] and [systimer] modules for more information."
)]
#![cfg_attr(feature = "esp32", doc = "See the [timg] module for more information.")]
#![doc = crate::before_snippet!()]
#![doc = crate::before_snippet!()]
use fugit::{ExtU64, Instant, MicrosDurationU64};
use crate::{
interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef},
Blocking,
InterruptConfigurable,
};
#[cfg(systimer)]
pub mod systimer;
#[cfg(any(timg0, timg1))]
pub mod timg;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
TimerActive,
TimerInactive,
AlarmInactive,
InvalidTimeout,
}
pub trait Timer: crate::private::Sealed {
fn start(&self);
fn stop(&self);
fn reset(&self);
fn is_running(&self) -> bool;
fn now(&self) -> Instant<u64, 1, 1_000_000>;
fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error>;
fn enable_auto_reload(&self, auto_reload: bool);
fn enable_interrupt(&self, state: bool);
fn clear_interrupt(&self);
fn set_interrupt_handler(&self, handler: InterruptHandler);
fn is_interrupt_set(&self) -> bool;
#[doc(hidden)]
fn set_alarm_active(&self, state: bool);
}
pub struct OneShotTimer<'d, T> {
inner: PeripheralRef<'d, T>,
}
impl<'d, T> OneShotTimer<'d, T>
where
T: Timer,
{
pub fn new(inner: impl Peripheral<P = T> + 'd) -> Self {
crate::into_ref!(inner);
Self { inner }
}
pub fn delay_millis(&self, ms: u32) {
self.delay((ms as u64).millis());
}
pub fn delay_micros(&self, us: u32) {
self.delay((us as u64).micros());
}
pub fn delay_nanos(&self, ns: u32) {
self.delay((ns.div_ceil(1000) as u64).micros())
}
fn delay(&self, us: MicrosDurationU64) {
if self.inner.is_running() {
self.inner.stop();
}
self.inner.clear_interrupt();
self.inner.reset();
self.inner.enable_auto_reload(false);
self.inner.load_value(us).unwrap();
self.inner.start();
while !self.inner.is_interrupt_set() {
}
self.inner.stop();
self.inner.clear_interrupt();
}
pub fn schedule(&mut self, timeout: MicrosDurationU64) -> Result<(), Error> {
if self.inner.is_running() {
self.inner.stop();
}
self.inner.clear_interrupt();
self.inner.reset();
self.inner.enable_auto_reload(false);
self.inner.load_value(timeout)?;
self.inner.start();
Ok(())
}
pub fn stop(&mut self) {
self.inner.stop();
}
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.inner.set_interrupt_handler(handler);
}
pub fn enable_interrupt(&mut self, enable: bool) {
self.inner.enable_interrupt(enable);
}
pub fn clear_interrupt(&mut self) {
self.inner.clear_interrupt();
self.inner.set_alarm_active(false);
}
}
impl<T> crate::private::Sealed for OneShotTimer<'_, T> where T: Timer {}
impl<T> InterruptConfigurable for OneShotTimer<'_, T>
where
T: Timer,
{
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
OneShotTimer::set_interrupt_handler(self, handler);
}
}
impl<T, UXX> embedded_hal_02::blocking::delay::DelayMs<UXX> for OneShotTimer<'_, T>
where
T: Timer,
UXX: Into<u32>,
{
fn delay_ms(&mut self, ms: UXX) {
self.delay_millis(ms.into());
}
}
impl<T, UXX> embedded_hal_02::blocking::delay::DelayUs<UXX> for OneShotTimer<'_, T>
where
T: Timer,
UXX: Into<u32>,
{
fn delay_us(&mut self, us: UXX) {
self.delay_micros(us.into());
}
}
impl<T> embedded_hal::delay::DelayNs for OneShotTimer<'_, T>
where
T: Timer,
{
fn delay_ns(&mut self, ns: u32) {
self.delay_nanos(ns);
}
}
pub struct PeriodicTimer<'d, T> {
inner: PeripheralRef<'d, T>,
}
impl<'d, T> PeriodicTimer<'d, T>
where
T: Timer,
{
pub fn new(inner: impl Peripheral<P = T> + 'd) -> Self {
crate::into_ref!(inner);
Self { inner }
}
pub fn start(&mut self, timeout: MicrosDurationU64) -> Result<(), Error> {
if self.inner.is_running() {
self.inner.stop();
}
self.inner.clear_interrupt();
self.inner.reset();
self.inner.enable_auto_reload(true);
self.inner.load_value(timeout)?;
self.inner.start();
Ok(())
}
pub fn wait(&mut self) -> nb::Result<(), void::Void> {
if self.inner.is_interrupt_set() {
self.inner.clear_interrupt();
self.inner.set_alarm_active(true);
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
pub fn cancel(&mut self) -> Result<(), Error> {
if !self.inner.is_running() {
return Err(Error::TimerInactive);
}
self.inner.stop();
Ok(())
}
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.inner.set_interrupt_handler(handler);
}
pub fn enable_interrupt(&mut self, enable: bool) {
self.inner.enable_interrupt(enable);
}
pub fn clear_interrupt(&mut self) {
self.inner.clear_interrupt();
self.inner.set_alarm_active(true);
}
}
impl<T> crate::private::Sealed for PeriodicTimer<'_, T> where T: Timer {}
impl<T> InterruptConfigurable for PeriodicTimer<'_, T>
where
T: Timer,
{
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
PeriodicTimer::set_interrupt_handler(self, handler);
}
}
impl<T> embedded_hal_02::timer::CountDown for PeriodicTimer<'_, T>
where
T: Timer,
{
type Time = MicrosDurationU64;
fn start<Time>(&mut self, timeout: Time)
where
Time: Into<Self::Time>,
{
self.start(timeout.into()).unwrap();
}
fn wait(&mut self) -> nb::Result<(), void::Void> {
self.wait()
}
}
impl<T> embedded_hal_02::timer::Cancel for PeriodicTimer<'_, T>
where
T: Timer,
{
type Error = Error;
fn cancel(&mut self) -> Result<(), Self::Error> {
self.cancel()
}
}
impl<T> embedded_hal_02::timer::Periodic for PeriodicTimer<'_, T> where T: Timer {}
enum AnyTimerInner {
Timg0Timer0(timg::Timer<timg::Timer0<crate::peripherals::TIMG0>, Blocking>),
#[cfg(timg_timer1)]
Timg0Timer1(timg::Timer<timg::Timer1<crate::peripherals::TIMG0>, Blocking>),
#[cfg(timg1)]
Timg1Timer0(timg::Timer<timg::Timer0<crate::peripherals::TIMG1>, Blocking>),
#[cfg(all(timg1, timg_timer1))]
Timg1Timer1(timg::Timer<timg::Timer1<crate::peripherals::TIMG1>, Blocking>),
#[cfg(systimer)]
SystimerAlarmPeriodic(systimer::Alarm<'static, systimer::Periodic, Blocking>),
#[cfg(systimer)]
SystimerAlarmTarget(systimer::Alarm<'static, systimer::Target, Blocking>),
}
pub struct AnyTimer(AnyTimerInner);
impl crate::private::Sealed for AnyTimer {}
impl From<timg::Timer<timg::Timer0<crate::peripherals::TIMG0>, Blocking>> for AnyTimer {
fn from(value: timg::Timer<timg::Timer0<crate::peripherals::TIMG0>, Blocking>) -> Self {
Self(AnyTimerInner::Timg0Timer0(value))
}
}
#[cfg(timg_timer1)]
impl From<timg::Timer<timg::Timer1<crate::peripherals::TIMG0>, Blocking>> for AnyTimer {
fn from(value: timg::Timer<timg::Timer1<crate::peripherals::TIMG0>, Blocking>) -> Self {
Self(AnyTimerInner::Timg0Timer1(value))
}
}
#[cfg(timg1)]
impl From<timg::Timer<timg::Timer0<crate::peripherals::TIMG1>, Blocking>> for AnyTimer {
fn from(value: timg::Timer<timg::Timer0<crate::peripherals::TIMG1>, Blocking>) -> Self {
Self(AnyTimerInner::Timg1Timer0(value))
}
}
#[cfg(all(timg1, timg_timer1))]
impl From<timg::Timer<timg::Timer1<crate::peripherals::TIMG1>, Blocking>> for AnyTimer {
fn from(value: timg::Timer<timg::Timer1<crate::peripherals::TIMG1>, Blocking>) -> Self {
Self(AnyTimerInner::Timg1Timer1(value))
}
}
#[cfg(systimer)]
impl From<systimer::Alarm<'static, systimer::Periodic, Blocking>> for AnyTimer {
fn from(value: systimer::Alarm<'static, systimer::Periodic, Blocking>) -> Self {
Self(AnyTimerInner::SystimerAlarmPeriodic(value))
}
}
#[cfg(systimer)]
impl From<systimer::Alarm<'static, systimer::Target, Blocking>> for AnyTimer {
fn from(value: systimer::Alarm<'static, systimer::Target, Blocking>) -> Self {
Self(AnyTimerInner::SystimerAlarmTarget(value))
}
}
impl Timer for AnyTimer {
delegate::delegate! {
to match &self.0 {
AnyTimerInner::Timg0Timer0(inner) => inner,
#[cfg(timg_timer1)]
AnyTimerInner::Timg0Timer1(inner) => inner,
#[cfg(timg1)]
AnyTimerInner::Timg1Timer0(inner) => inner,
#[cfg(all(timg1,timg_timer1))]
AnyTimerInner::Timg1Timer1(inner) => inner,
#[cfg(systimer)]
AnyTimerInner::SystimerAlarmPeriodic(inner) => inner,
#[cfg(systimer)]
AnyTimerInner::SystimerAlarmTarget(inner) => inner,
} {
fn start(&self);
fn stop(&self);
fn reset(&self);
fn is_running(&self) -> bool;
fn now(&self) -> Instant<u64, 1, 1_000_000>;
fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error>;
fn enable_auto_reload(&self, auto_reload: bool);
fn enable_interrupt(&self, state: bool);
fn clear_interrupt(&self);
fn set_interrupt_handler(&self, handler: InterruptHandler);
fn is_interrupt_set(&self) -> bool;
fn set_alarm_active(&self, state: bool);
}
}
}
impl Peripheral for AnyTimer {
type P = Self;
#[inline]
unsafe fn clone_unchecked(&self) -> Self::P {
core::ptr::read(self as *const _)
}
}