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