esp_hal/timer/
mod.rs

1//! # General-purpose Timers
2//!
3//! ## Overview
4//! The [OneShotTimer] and [PeriodicTimer] types can be backed by any hardware
5//! peripheral which implements the [Timer] trait. This means that the same API
6//! can be used to interact with different hardware timers, like the `TIMG` and
7//! SYSTIMER.
8#![cfg_attr(
9    not(feature = "esp32"),
10    doc = "See the [timg] and [systimer] modules for more information."
11)]
12#![cfg_attr(feature = "esp32", doc = "See the [timg] module for more information.")]
13//! ## Examples
14//!
15//! ### One-shot Timer
16//!
17//! ```rust, no_run
18#![doc = crate::before_snippet!()]
19//! # use esp_hal::timer::{OneShotTimer, PeriodicTimer, timg::TimerGroup};
20//! #
21//! let timg0 = TimerGroup::new(peripherals.TIMG0);
22//! let mut one_shot = OneShotTimer::new(timg0.timer0);
23//!
24//! one_shot.delay_millis(500);
25//! # Ok(())
26//! # }
27//! ```
28//! 
29//! ### Periodic Timer
30//! ```rust, no_run
31#![doc = crate::before_snippet!()]
32//! # use esp_hal::timer::{PeriodicTimer, timg::TimerGroup};
33//! #
34//! let timg0 = TimerGroup::new(peripherals.TIMG0);
35//! let mut periodic = PeriodicTimer::new(timg0.timer0);
36//!
37//! periodic.start(Duration::from_secs(1));
38//! loop {
39//!    periodic.wait();
40//! }
41//! # }
42//! ```
43
44use core::{
45    marker::PhantomData,
46    pin::Pin,
47    task::{Context, Poll},
48};
49
50use crate::{
51    asynch::AtomicWaker,
52    interrupt::{InterruptConfigurable, InterruptHandler},
53    peripheral::{Peripheral, PeripheralRef},
54    peripherals::Interrupt,
55    system::Cpu,
56    time::{Duration, Instant},
57    Async,
58    Blocking,
59    DriverMode,
60};
61
62#[cfg(systimer)]
63pub mod systimer;
64#[cfg(any(timg0, timg1))]
65pub mod timg;
66
67/// Timer errors.
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70pub enum Error {
71    /// The timer is already active.
72    TimerActive,
73    /// The timer is not currently active.
74    TimerInactive,
75    /// The alarm is not currently active.
76    AlarmInactive,
77    /// The provided timeout is too large.
78    InvalidTimeout,
79}
80
81/// Functionality provided by any timer peripheral.
82pub trait Timer: Into<AnyTimer> + 'static + crate::private::Sealed {
83    /// Start the timer.
84    #[doc(hidden)]
85    fn start(&self);
86
87    /// Stop the timer.
88    #[doc(hidden)]
89    fn stop(&self);
90
91    /// Reset the timer value to 0.
92    #[doc(hidden)]
93    fn reset(&self);
94
95    /// Is the timer running?
96    #[doc(hidden)]
97    fn is_running(&self) -> bool;
98
99    /// The current timer value.
100    #[doc(hidden)]
101    fn now(&self) -> Instant;
102
103    /// Load a target value into the timer.
104    #[doc(hidden)]
105    fn load_value(&self, value: Duration) -> Result<(), Error>;
106
107    /// Enable auto reload of the loaded value.
108    #[doc(hidden)]
109    fn enable_auto_reload(&self, auto_reload: bool);
110
111    /// Enable or disable the timer's interrupt.
112    #[doc(hidden)]
113    fn enable_interrupt(&self, state: bool);
114
115    /// Clear the timer's interrupt.
116    fn clear_interrupt(&self);
117
118    /// Has the timer triggered?
119    fn is_interrupt_set(&self) -> bool;
120
121    /// Returns the HAL provided async interrupt handler
122    #[doc(hidden)]
123    fn async_interrupt_handler(&self) -> InterruptHandler;
124
125    /// Returns the interrupt source for the underlying timer
126    fn peripheral_interrupt(&self) -> Interrupt;
127
128    /// Configures the interrupt handler.
129    #[doc(hidden)]
130    fn set_interrupt_handler(&self, handler: InterruptHandler);
131
132    #[doc(hidden)]
133    fn waker(&self) -> &AtomicWaker;
134}
135
136/// A one-shot timer.
137pub struct OneShotTimer<'d, Dm: DriverMode> {
138    inner: PeripheralRef<'d, AnyTimer>,
139    _ph: PhantomData<Dm>,
140}
141
142impl<'d> OneShotTimer<'d, Blocking> {
143    /// Construct a new instance of [`OneShotTimer`].
144    pub fn new(inner: impl Peripheral<P = impl Timer> + 'd) -> OneShotTimer<'d, Blocking> {
145        crate::into_mapped_ref!(inner);
146        Self {
147            inner,
148            _ph: PhantomData,
149        }
150    }
151}
152
153impl<'d> OneShotTimer<'d, Blocking> {
154    /// Converts the driver to [`Async`] mode.
155    pub fn into_async(self) -> OneShotTimer<'d, Async> {
156        let handler = self.inner.async_interrupt_handler();
157        self.inner.set_interrupt_handler(handler);
158        OneShotTimer {
159            inner: self.inner,
160            _ph: PhantomData,
161        }
162    }
163}
164
165impl OneShotTimer<'_, Async> {
166    /// Converts the driver to [`Blocking`] mode.
167    pub fn into_blocking(self) -> Self {
168        crate::interrupt::disable(Cpu::current(), self.inner.peripheral_interrupt());
169        Self {
170            inner: self.inner,
171            _ph: PhantomData,
172        }
173    }
174
175    /// Delay for *at least* `ns` nanoseconds.
176    pub async fn delay_nanos_async(&mut self, ns: u32) {
177        self.delay_async(Duration::from_micros(ns.div_ceil(1000) as u64))
178            .await
179    }
180
181    /// Delay for *at least* `ms` milliseconds.
182    pub async fn delay_millis_async(&mut self, ms: u32) {
183        self.delay_async(Duration::from_millis(ms as u64)).await;
184    }
185
186    /// Delay for *at least* `us` microseconds.
187    pub async fn delay_micros_async(&mut self, us: u32) {
188        self.delay_async(Duration::from_micros(us as u64)).await;
189    }
190
191    async fn delay_async(&mut self, us: Duration) {
192        unwrap!(self.schedule(us));
193
194        WaitFuture::new(self.inner.reborrow()).await;
195
196        self.stop();
197        self.clear_interrupt();
198    }
199}
200
201#[must_use = "futures do nothing unless you `.await` or poll them"]
202struct WaitFuture<'d> {
203    timer: PeripheralRef<'d, AnyTimer>,
204}
205
206impl<'d> WaitFuture<'d> {
207    fn new(timer: impl Peripheral<P = AnyTimer> + 'd) -> Self {
208        crate::into_ref!(timer);
209        // For some reason, on the S2 we need to enable the interrupt before we
210        // read its status. Doing so in the other order causes the interrupt
211        // request to never be fired.
212        timer.enable_interrupt(true);
213        Self { timer }
214    }
215
216    fn is_done(&self) -> bool {
217        self.timer.is_interrupt_set()
218    }
219}
220
221impl core::future::Future for WaitFuture<'_> {
222    type Output = ();
223
224    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
225        // Interrupts are enabled, so we need to register the waker before we check for
226        // done. Otherwise we might miss the interrupt that would wake us.
227        self.timer.waker().register(ctx.waker());
228
229        if self.is_done() {
230            Poll::Ready(())
231        } else {
232            Poll::Pending
233        }
234    }
235}
236
237impl Drop for WaitFuture<'_> {
238    fn drop(&mut self) {
239        self.timer.enable_interrupt(false);
240    }
241}
242
243impl<Dm> OneShotTimer<'_, Dm>
244where
245    Dm: DriverMode,
246{
247    /// Delay for *at least* `ms` milliseconds.
248    pub fn delay_millis(&mut self, ms: u32) {
249        self.delay(Duration::from_millis(ms as u64));
250    }
251
252    /// Delay for *at least* `us` microseconds.
253    pub fn delay_micros(&mut self, us: u32) {
254        self.delay(Duration::from_micros(us as u64));
255    }
256
257    /// Delay for *at least* `ns` nanoseconds.
258    pub fn delay_nanos(&mut self, ns: u32) {
259        self.delay(Duration::from_micros(ns.div_ceil(1000) as u64))
260    }
261
262    fn delay(&mut self, us: Duration) {
263        self.schedule(us).unwrap();
264
265        while !self.inner.is_interrupt_set() {
266            // Wait
267        }
268
269        self.stop();
270        self.clear_interrupt();
271    }
272
273    /// Start counting until the given timeout and raise an interrupt
274    pub fn schedule(&mut self, timeout: Duration) -> Result<(), Error> {
275        if self.inner.is_running() {
276            self.inner.stop();
277        }
278
279        self.inner.clear_interrupt();
280        self.inner.reset();
281
282        self.inner.enable_auto_reload(false);
283        self.inner.load_value(timeout)?;
284        self.inner.start();
285
286        Ok(())
287    }
288
289    /// Stop the timer
290    pub fn stop(&mut self) {
291        self.inner.stop();
292    }
293
294    /// Set the interrupt handler
295    ///
296    /// Note that this will replace any previously set interrupt handler
297    #[instability::unstable]
298    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
299        self.inner.set_interrupt_handler(handler);
300    }
301
302    /// Enable listening for interrupts
303    pub fn enable_interrupt(&mut self, enable: bool) {
304        self.inner.enable_interrupt(enable);
305    }
306
307    /// Clear the interrupt flag
308    pub fn clear_interrupt(&mut self) {
309        self.inner.clear_interrupt();
310    }
311}
312
313impl<Dm> crate::private::Sealed for OneShotTimer<'_, Dm> where Dm: DriverMode {}
314
315impl<Dm> InterruptConfigurable for OneShotTimer<'_, Dm>
316where
317    Dm: DriverMode,
318{
319    fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
320        OneShotTimer::set_interrupt_handler(self, handler);
321    }
322}
323
324impl embedded_hal::delay::DelayNs for OneShotTimer<'_, Blocking> {
325    fn delay_ns(&mut self, ns: u32) {
326        self.delay_nanos(ns);
327    }
328}
329
330impl embedded_hal_async::delay::DelayNs for OneShotTimer<'_, Async> {
331    async fn delay_ns(&mut self, ns: u32) {
332        self.delay_nanos_async(ns).await
333    }
334}
335
336/// A periodic timer.
337pub struct PeriodicTimer<'d, Dm: DriverMode> {
338    inner: PeripheralRef<'d, AnyTimer>,
339    _ph: PhantomData<Dm>,
340}
341
342impl<'d> PeriodicTimer<'d, Blocking> {
343    /// Construct a new instance of [`PeriodicTimer`].
344    pub fn new(inner: impl Peripheral<P = impl Timer> + 'd) -> PeriodicTimer<'d, Blocking> {
345        crate::into_mapped_ref!(inner);
346        Self {
347            inner,
348            _ph: PhantomData,
349        }
350    }
351}
352
353impl<Dm> PeriodicTimer<'_, Dm>
354where
355    Dm: DriverMode,
356{
357    /// Start a new count down.
358    pub fn start(&mut self, period: Duration) -> Result<(), Error> {
359        if self.inner.is_running() {
360            self.inner.stop();
361        }
362
363        self.inner.clear_interrupt();
364        self.inner.reset();
365
366        self.inner.enable_auto_reload(true);
367        self.inner.load_value(period)?;
368        self.inner.start();
369
370        Ok(())
371    }
372
373    /// "Wait", by blocking, until the count down finishes.
374    pub fn wait(&mut self) {
375        while !self.inner.is_interrupt_set() {}
376        self.inner.clear_interrupt();
377    }
378
379    /// Tries to cancel the active count down.
380    pub fn cancel(&mut self) -> Result<(), Error> {
381        if !self.inner.is_running() {
382            return Err(Error::TimerInactive);
383        }
384
385        self.inner.stop();
386
387        Ok(())
388    }
389
390    /// Set the interrupt handler
391    ///
392    /// Note that this will replace any previously set interrupt handler
393    #[instability::unstable]
394    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
395        self.inner.set_interrupt_handler(handler);
396    }
397
398    /// Enable/disable listening for interrupts
399    pub fn enable_interrupt(&mut self, enable: bool) {
400        self.inner.enable_interrupt(enable);
401    }
402
403    /// Clear the interrupt flag
404    pub fn clear_interrupt(&mut self) {
405        self.inner.clear_interrupt();
406    }
407}
408
409impl<Dm> crate::private::Sealed for PeriodicTimer<'_, Dm> where Dm: DriverMode {}
410
411impl<Dm> InterruptConfigurable for PeriodicTimer<'_, Dm>
412where
413    Dm: DriverMode,
414{
415    fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
416        PeriodicTimer::set_interrupt_handler(self, handler);
417    }
418}
419
420crate::any_peripheral! {
421    /// Any Timer peripheral.
422    pub peripheral AnyTimer {
423        TimgTimer(timg::Timer),
424        #[cfg(systimer)]
425        SystimerAlarm(systimer::Alarm),
426    }
427}
428
429impl Timer for AnyTimer {
430    delegate::delegate! {
431        to match &self.0 {
432            AnyTimerInner::TimgTimer(inner) => inner,
433            #[cfg(systimer)]
434            AnyTimerInner::SystimerAlarm(inner) => inner,
435        } {
436            fn start(&self);
437            fn stop(&self);
438            fn reset(&self);
439            fn is_running(&self) -> bool;
440            fn now(&self) -> Instant;
441            fn load_value(&self, value: Duration) -> Result<(), Error>;
442            fn enable_auto_reload(&self, auto_reload: bool);
443            fn enable_interrupt(&self, state: bool);
444            fn clear_interrupt(&self);
445            fn is_interrupt_set(&self) -> bool;
446            fn async_interrupt_handler(&self) -> InterruptHandler;
447            fn peripheral_interrupt(&self) -> Interrupt;
448            fn set_interrupt_handler(&self, handler: InterruptHandler);
449            fn waker(&self) -> &AtomicWaker;
450        }
451    }
452}