Skip to main content

esp_hal/
time.rs

1//! # Timekeeping
2//!
3//! This module provides types for representing frequency and duration, as well
4//! as an instant in time. Time is measured since boot, and can be accessed
5//! by the [`Instant::now`] function.
6
7use core::fmt::{Debug, Display, Formatter, Result as FmtResult};
8
9type InnerRate = fugit::Rate<u32, 1, 1>;
10type InnerInstant = fugit::Instant<u64, 1, 1_000_000>;
11type InnerDuration = fugit::Duration<u64, 1, 1_000_000>;
12
13/// Represents a rate or frequency of events.
14#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
15pub struct Rate(InnerRate);
16
17impl core::hash::Hash for Rate {
18    #[inline]
19    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
20        self.as_hz().hash(state);
21    }
22}
23
24impl Display for Rate {
25    #[inline]
26    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
27        write!(f, "{} Hz", self.as_hz())
28    }
29}
30
31impl Debug for Rate {
32    #[inline]
33    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
34        write!(f, "Rate({} Hz)", self.as_hz())
35    }
36}
37
38#[cfg(feature = "defmt")]
39impl defmt::Format for Rate {
40    #[inline]
41    fn format(&self, f: defmt::Formatter<'_>) {
42        defmt::write!(f, "{=u32} Hz", self.as_hz())
43    }
44}
45
46impl Rate {
47    #[procmacros::doc_replace]
48    /// Shorthand for creating a rate which represents hertz.
49    ///
50    /// ## Example
51    ///
52    /// ```rust, no_run
53    /// # {before_snippet}
54    /// use esp_hal::time::Rate;
55    /// let rate = Rate::from_hz(1000);
56    /// # {after_snippet}
57    /// ```
58    #[inline]
59    pub const fn from_hz(val: u32) -> Self {
60        Self(InnerRate::Hz(val))
61    }
62
63    #[procmacros::doc_replace]
64    /// Shorthand for creating a rate which represents kilohertz.
65    ///
66    /// ## Example
67    ///
68    /// ```rust, no_run
69    /// # {before_snippet}
70    /// use esp_hal::time::Rate;
71    /// let rate = Rate::from_khz(1000);
72    /// # {after_snippet}
73    /// ```
74    #[inline]
75    pub const fn from_khz(val: u32) -> Self {
76        Self(InnerRate::kHz(val))
77    }
78
79    #[procmacros::doc_replace]
80    /// Shorthand for creating a rate which represents megahertz.
81    ///
82    /// ## Example
83    ///
84    /// ```rust, no_run
85    /// # {before_snippet}
86    /// use esp_hal::time::Rate;
87    /// let rate = Rate::from_mhz(1000);
88    /// # {after_snippet}
89    /// ```
90    #[inline]
91    pub const fn from_mhz(val: u32) -> Self {
92        Self(InnerRate::MHz(val))
93    }
94
95    #[procmacros::doc_replace]
96    /// Convert the `Rate` to an integer number of Hz.
97    ///
98    /// ## Example
99    ///
100    /// ```rust, no_run
101    /// # {before_snippet}
102    /// use esp_hal::time::Rate;
103    /// let rate = Rate::from_hz(1000);
104    /// let hz = rate.as_hz();
105    /// # {after_snippet}
106    /// ```
107    #[inline]
108    pub const fn as_hz(&self) -> u32 {
109        self.0.to_Hz()
110    }
111
112    #[procmacros::doc_replace]
113    /// Convert the `Rate` to an integer number of kHz.
114    ///
115    /// ## Example
116    ///
117    /// ```rust, no_run
118    /// # {before_snippet}
119    /// use esp_hal::time::Rate;
120    /// let rate = Rate::from_khz(1000);
121    /// let khz = rate.as_khz();
122    /// # {after_snippet}
123    /// ```
124    #[inline]
125    pub const fn as_khz(&self) -> u32 {
126        self.0.to_kHz()
127    }
128
129    #[procmacros::doc_replace]
130    /// Convert the `Rate` to an integer number of MHz.
131    ///
132    /// ## Example
133    ///
134    /// ```rust, no_run
135    /// # {before_snippet}
136    /// use esp_hal::time::Rate;
137    /// let rate = Rate::from_mhz(1000);
138    /// let mhz = rate.as_mhz();
139    /// # {after_snippet}
140    /// ```
141    #[inline]
142    pub const fn as_mhz(&self) -> u32 {
143        self.0.to_MHz()
144    }
145
146    #[procmacros::doc_replace]
147    /// Convert the `Rate` to a `Duration`.
148    ///
149    /// ## Example
150    ///
151    /// ```rust, no_run
152    /// # {before_snippet}
153    /// use esp_hal::time::Rate;
154    /// let rate = Rate::from_hz(1000);
155    /// let duration = rate.as_duration();
156    /// # {after_snippet}
157    /// ```
158    #[inline]
159    pub const fn as_duration(&self) -> Duration {
160        Duration::from_micros(1_000_000 / self.as_hz() as u64)
161    }
162}
163
164impl core::ops::Div for Rate {
165    type Output = u32;
166
167    #[inline]
168    fn div(self, rhs: Self) -> Self::Output {
169        self.0 / rhs.0
170    }
171}
172
173impl core::ops::Mul<u32> for Rate {
174    type Output = Rate;
175
176    #[inline]
177    fn mul(self, rhs: u32) -> Self::Output {
178        Rate(self.0 * rhs)
179    }
180}
181
182impl core::ops::Div<u32> for Rate {
183    type Output = Rate;
184
185    #[inline]
186    fn div(self, rhs: u32) -> Self::Output {
187        Rate(self.0 / rhs)
188    }
189}
190
191/// Represents an instant in time.
192#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
193pub struct Instant(InnerInstant);
194
195impl Debug for Instant {
196    #[inline]
197    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
198        write!(
199            f,
200            "Instant({} µs since epoch)",
201            self.duration_since_epoch().as_micros()
202        )
203    }
204}
205
206impl Display for Instant {
207    #[inline]
208    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
209        write!(
210            f,
211            "{} µs since epoch",
212            self.duration_since_epoch().as_micros()
213        )
214    }
215}
216
217#[cfg(feature = "defmt")]
218impl defmt::Format for Instant {
219    #[inline]
220    fn format(&self, f: defmt::Formatter<'_>) {
221        defmt::write!(
222            f,
223            "{=u64} µs since epoch",
224            self.duration_since_epoch().as_micros()
225        )
226    }
227}
228
229impl core::hash::Hash for Instant {
230    #[inline]
231    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
232        self.duration_since_epoch().hash(state);
233    }
234}
235
236impl Instant {
237    /// Represents the moment the system booted.
238    pub const EPOCH: Instant = Instant(InnerInstant::from_ticks(0));
239
240    #[procmacros::doc_replace(
241        "wrap_after" => {
242            cfg(esp32) => "36_558 years",
243            cfg(esp32s2) => "7_311 years",
244            _ => "more than 7 years"
245        }
246    )]
247    /// Returns the current instant.
248    ///
249    /// The counter won’t measure time in sleep-mode.
250    ///
251    /// The timer has a 1 microsecond resolution and will wrap after __wrap_after__.
252    ///
253    /// <section class="warning">
254    /// Note that this function returns an unreliable value before <code>esp_hal::init()</code> is
255    /// called. </section>
256    ///
257    /// ## Example
258    ///
259    /// ```rust, no_run
260    /// # {before_snippet}
261    /// use esp_hal::time::Instant;
262    /// let now = Instant::now();
263    /// # {after_snippet}
264    /// ```
265    #[inline]
266    pub fn now() -> Self {
267        implem::now()
268    }
269
270    #[inline]
271    pub(crate) fn from_ticks(ticks: u64) -> Self {
272        Instant(InnerInstant::from_ticks(ticks))
273    }
274
275    #[procmacros::doc_replace]
276    /// Returns the elapsed `Duration` since boot.
277    ///
278    /// ## Example
279    ///
280    /// ```rust, no_run
281    /// # {before_snippet}
282    /// use esp_hal::time::Instant;
283    /// let now = Instant::now();
284    /// let duration = now.duration_since_epoch();
285    /// # {after_snippet}
286    /// ```
287    #[inline]
288    pub fn duration_since_epoch(&self) -> Duration {
289        *self - Self::EPOCH
290    }
291
292    #[procmacros::doc_replace]
293    /// Returns the elapsed `Duration` since this `Instant` was created.
294    ///
295    /// ## Example
296    ///
297    /// ```rust, no_run
298    /// # {before_snippet}
299    /// use esp_hal::time::Instant;
300    /// let now = Instant::now();
301    /// let duration = now.elapsed();
302    /// # {after_snippet}
303    /// ```
304    #[inline]
305    pub fn elapsed(&self) -> Duration {
306        Self::now() - *self
307    }
308}
309
310impl core::ops::Add<Duration> for Instant {
311    type Output = Self;
312
313    #[inline]
314    fn add(self, rhs: Duration) -> Self::Output {
315        Instant(self.0 + rhs.0)
316    }
317}
318
319impl core::ops::AddAssign<Duration> for Instant {
320    #[inline]
321    fn add_assign(&mut self, rhs: Duration) {
322        self.0 += rhs.0;
323    }
324}
325
326impl core::ops::Sub for Instant {
327    type Output = Duration;
328
329    #[inline]
330    fn sub(self, rhs: Self) -> Self::Output {
331        // Avoid "Sub failed! Other > self" panics
332        Duration::from_micros(self.0.ticks().wrapping_sub(rhs.0.ticks()))
333    }
334}
335
336impl core::ops::Sub<Duration> for Instant {
337    type Output = Self;
338
339    #[inline]
340    fn sub(self, rhs: Duration) -> Self::Output {
341        Instant(self.0 - rhs.0)
342    }
343}
344
345impl core::ops::SubAssign<Duration> for Instant {
346    #[inline]
347    fn sub_assign(&mut self, rhs: Duration) {
348        self.0 -= rhs.0;
349    }
350}
351
352/// Represents a duration of time.
353#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
354pub struct Duration(InnerDuration);
355
356impl Debug for Duration {
357    #[inline]
358    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
359        write!(f, "Duration({} µs)", self.as_micros())
360    }
361}
362
363impl Display for Duration {
364    #[inline]
365    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
366        write!(f, "{} µs", self.as_micros())
367    }
368}
369
370#[cfg(feature = "defmt")]
371impl defmt::Format for Duration {
372    #[inline]
373    fn format(&self, f: defmt::Formatter<'_>) {
374        defmt::write!(f, "{=u64} µs", self.as_micros())
375    }
376}
377
378impl core::hash::Hash for Duration {
379    #[inline]
380    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
381        self.as_micros().hash(state);
382    }
383}
384
385impl Duration {
386    /// A duration of zero time.
387    pub const ZERO: Self = Self(InnerDuration::from_ticks(0));
388
389    /// A duration representing the maximum possible time.
390    pub const MAX: Self = Self(InnerDuration::from_ticks(u64::MAX));
391
392    #[procmacros::doc_replace]
393    /// Creates a duration which represents microseconds.
394    ///
395    /// ## Example
396    ///
397    /// ```rust, no_run
398    /// # {before_snippet}
399    /// use esp_hal::time::Duration;
400    /// let duration = Duration::from_micros(1000);
401    /// # {after_snippet}
402    /// ```
403    #[inline]
404    pub const fn from_micros(val: u64) -> Self {
405        Self(InnerDuration::micros(val))
406    }
407
408    #[procmacros::doc_replace]
409    /// Creates a duration which represents milliseconds.
410    ///
411    /// ## Example
412    ///
413    /// ```rust, no_run
414    /// # {before_snippet}
415    /// use esp_hal::time::Duration;
416    /// let duration = Duration::from_millis(100);
417    /// # {after_snippet}
418    /// ```
419    #[inline]
420    pub const fn from_millis(val: u64) -> Self {
421        Self(InnerDuration::millis(val))
422    }
423
424    #[procmacros::doc_replace]
425    /// Creates a duration which represents seconds.
426    ///
427    /// ## Example
428    ///
429    /// ```rust, no_run
430    /// # {before_snippet}
431    /// use esp_hal::time::Duration;
432    /// let duration = Duration::from_secs(1);
433    /// # {after_snippet}
434    /// ```
435    #[inline]
436    pub const fn from_secs(val: u64) -> Self {
437        Self(InnerDuration::secs(val))
438    }
439
440    #[procmacros::doc_replace]
441    /// Creates a duration which represents minutes.
442    ///
443    /// ## Example
444    ///
445    /// ```rust, no_run
446    /// # {before_snippet}
447    /// use esp_hal::time::Duration;
448    /// let duration = Duration::from_minutes(1);
449    /// # {after_snippet}
450    /// ```
451    #[inline]
452    pub const fn from_minutes(val: u64) -> Self {
453        Self(InnerDuration::minutes(val))
454    }
455
456    #[procmacros::doc_replace]
457    /// Creates a duration which represents hours.
458    ///
459    /// ## Example
460    ///
461    /// ```rust, no_run
462    /// # {before_snippet}
463    /// use esp_hal::time::Duration;
464    /// let duration = Duration::from_hours(1);
465    /// # {after_snippet}
466    /// ```
467    #[inline]
468    pub const fn from_hours(val: u64) -> Self {
469        Self(InnerDuration::hours(val))
470    }
471
472    delegate::delegate! {
473        #[inline]
474        to self.0 {
475            #[procmacros::doc_replace]
476            /// Convert the `Duration` to an integer number of microseconds.
477            ///
478            /// ## Example
479            ///
480            /// ```rust, no_run
481            /// # {before_snippet}
482            /// use esp_hal::time::Duration;
483            /// let duration = Duration::from_micros(1000);
484            /// let micros = duration.as_micros();
485            /// # {after_snippet}
486            /// ```
487            #[call(to_micros)]
488            pub const fn as_micros(&self) -> u64;
489
490            #[procmacros::doc_replace]
491            /// Convert the `Duration` to an integer number of milliseconds.
492            ///
493            /// ## Example
494            ///
495            /// ```rust, no_run
496            /// # {before_snippet}
497            /// use esp_hal::time::Duration;
498            /// let duration = Duration::from_millis(100);
499            /// let millis = duration.as_millis();
500            /// # {after_snippet}
501            /// ```
502            #[call(to_millis)]
503            pub const fn as_millis(&self) -> u64;
504
505            #[procmacros::doc_replace]
506            /// Convert the `Duration` to an integer number of seconds.
507            ///
508            /// ## Example
509            ///
510            /// ```rust, no_run
511            /// # {before_snippet}
512            /// use esp_hal::time::Duration;
513            /// let duration = Duration::from_secs(1);
514            /// let secs = duration.as_secs();
515            /// # {after_snippet}
516            /// ```
517            #[call(to_secs)]
518            pub const fn as_secs(&self) -> u64;
519
520            #[procmacros::doc_replace]
521            /// Convert the `Duration` to an integer number of minutes.
522            ///
523            /// ## Example
524            ///
525            /// ```rust, no_run
526            /// # {before_snippet}
527            /// use esp_hal::time::Duration;
528            /// let duration = Duration::from_minutes(1);
529            /// let minutes = duration.as_minutes();
530            /// # {after_snippet}
531            /// ```
532            #[call(to_minutes)]
533            pub const fn as_minutes(&self) -> u64;
534
535            #[procmacros::doc_replace]
536            /// Convert the `Duration` to an integer number of hours.
537            ///
538            /// ## Example
539            ///
540            /// ```rust, no_run
541            /// # {before_snippet}
542            /// use esp_hal::time::Duration;
543            /// let duration = Duration::from_hours(1);
544            /// let hours = duration.as_hours();
545            /// # {after_snippet}
546            /// ```
547            #[call(to_hours)]
548            pub const fn as_hours(&self) -> u64;
549        }
550    }
551
552    #[procmacros::doc_replace]
553    /// Add two durations while checking for overflow.
554    ///
555    /// ## Example
556    ///
557    /// ```rust, no_run
558    /// # {before_snippet}
559    /// use esp_hal::time::Duration;
560    /// let duration = Duration::from_secs(1);
561    /// let duration2 = Duration::from_secs(2);
562    ///
563    /// if let Some(sum) = duration.checked_add(duration2) {
564    ///     println!("Sum: {}", sum);
565    /// } else {
566    ///     println!("Overflow occurred");
567    /// }
568    /// # {after_snippet}
569    /// ```
570    #[inline]
571    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
572        if let Some(val) = self.0.checked_add(rhs.0) {
573            Some(Duration(val))
574        } else {
575            None
576        }
577    }
578
579    #[procmacros::doc_replace]
580    /// Subtract two durations while checking for overflow.
581    ///
582    /// ## Example
583    ///
584    /// ```rust, no_run
585    /// # {before_snippet}
586    /// use esp_hal::time::Duration;
587    /// let duration = Duration::from_secs(3);
588    /// let duration2 = Duration::from_secs(1);
589    ///
590    /// if let Some(diff) = duration.checked_sub(duration2) {
591    ///     println!("Difference: {}", diff);
592    /// } else {
593    ///     println!("Underflow occurred");
594    /// }
595    /// # {after_snippet}
596    /// ```
597    #[inline]
598    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
599        if let Some(val) = self.0.checked_sub(rhs.0) {
600            Some(Duration(val))
601        } else {
602            None
603        }
604    }
605
606    #[procmacros::doc_replace]
607    /// Add two durations, returning the maximum value if overflow occurred.
608    ///
609    /// ## Example
610    ///
611    /// ```rust, no_run
612    /// # {before_snippet}
613    /// use esp_hal::time::Duration;
614    /// let duration = Duration::from_secs(1);
615    /// let duration2 = Duration::from_secs(2);
616    ///
617    /// let sum = duration.saturating_add(duration2);
618    /// # {after_snippet}
619    /// ```
620    #[inline]
621    pub const fn saturating_add(self, rhs: Self) -> Self {
622        if let Some(val) = self.checked_add(rhs) {
623            val
624        } else {
625            Self::MAX
626        }
627    }
628
629    #[procmacros::doc_replace]
630    /// Subtract two durations, returning the minimum value if the result would
631    /// be negative.
632    ///
633    /// ## Example
634    ///
635    /// ```rust, no_run
636    /// # {before_snippet}
637    /// use esp_hal::time::Duration;
638    /// let duration = Duration::from_secs(3);
639    /// let duration2 = Duration::from_secs(1);
640    ///
641    /// let diff = duration.saturating_sub(duration2);
642    /// # {after_snippet}
643    /// ```
644    #[inline]
645    pub const fn saturating_sub(self, rhs: Self) -> Self {
646        if let Some(val) = self.checked_sub(rhs) {
647            val
648        } else {
649            Self::ZERO
650        }
651    }
652}
653
654impl core::ops::Add for Duration {
655    type Output = Self;
656
657    #[inline]
658    fn add(self, rhs: Self) -> Self::Output {
659        Duration(self.0 + rhs.0)
660    }
661}
662
663impl core::ops::AddAssign for Duration {
664    #[inline]
665    fn add_assign(&mut self, rhs: Self) {
666        self.0 += rhs.0;
667    }
668}
669
670impl core::ops::Sub for Duration {
671    type Output = Self;
672
673    #[inline]
674    fn sub(self, rhs: Self) -> Self::Output {
675        Duration(self.0 - rhs.0)
676    }
677}
678
679impl core::ops::SubAssign for Duration {
680    #[inline]
681    fn sub_assign(&mut self, rhs: Self) {
682        self.0 -= rhs.0;
683    }
684}
685
686impl core::ops::Mul<u32> for Duration {
687    type Output = Self;
688
689    #[inline]
690    fn mul(self, rhs: u32) -> Self::Output {
691        Duration(self.0 * rhs)
692    }
693}
694
695impl core::ops::Div<u32> for Duration {
696    type Output = Self;
697
698    #[inline]
699    fn div(self, rhs: u32) -> Self::Output {
700        Duration(self.0 / rhs)
701    }
702}
703
704impl core::ops::Div<Duration> for Duration {
705    type Output = u64;
706
707    #[inline]
708    fn div(self, rhs: Duration) -> Self::Output {
709        self.0 / rhs.0
710    }
711}
712
713#[cfg(esp32)]
714pub(crate) mod implem {
715    use super::Instant;
716    use crate::peripherals::TIMG0;
717
718    #[cfg(feature = "rt")]
719    pub(crate) fn time_init() {
720        let apb = crate::Clocks::get().apb_clock.as_hz();
721
722        let tg0 = TIMG0::regs();
723
724        tg0.lactconfig().write(|w| unsafe { w.bits(0) });
725        tg0.lactalarmhi().write(|w| unsafe { w.bits(u32::MAX) });
726        tg0.lactalarmlo().write(|w| unsafe { w.bits(u32::MAX) });
727        tg0.lactload().write(|w| unsafe { w.load().bits(1) });
728
729        // 16 MHz counter
730        tg0.lactconfig().write(|w| {
731            unsafe { w.divider().bits((apb / 16_000_000u32) as u16) };
732            w.increase().bit(true);
733            w.autoreload().bit(true);
734            w.en().bit(true)
735        });
736    }
737
738    #[inline]
739    pub(super) fn now() -> Instant {
740        // on ESP32 use LACT
741        let tg0 = TIMG0::regs();
742        tg0.lactupdate().write(|w| unsafe { w.update().bits(1) });
743
744        // The peripheral doesn't have a bit to indicate that the update is done, so we
745        // poll the lower 32 bit part of the counter until it changes, or a timeout
746        // expires.
747        let lo_initial = tg0.lactlo().read().bits();
748        let mut div = tg0.lactconfig().read().divider().bits();
749        let lo = loop {
750            let lo = tg0.lactlo().read().bits();
751            if lo != lo_initial || div == 0 {
752                break lo;
753            }
754            div -= 1;
755        };
756        let hi = tg0.lacthi().read().bits();
757
758        let ticks = ((hi as u64) << 32u64) | lo as u64;
759
760        Instant::from_ticks(ticks / 16)
761    }
762}
763
764#[cfg(systimer_driver_supported)]
765pub(crate) mod implem {
766    use super::Instant;
767    use crate::timer::systimer::{SystemTimer, Unit};
768
769    #[cfg(feature = "rt")]
770    pub(crate) fn time_init() {
771        SystemTimer::init_timestamp_scaler();
772    }
773
774    #[inline]
775    pub(super) fn now() -> Instant {
776        let ticks = SystemTimer::unit_value(Unit::Unit0);
777
778        let micros = SystemTimer::ticks_to_us(ticks);
779
780        Instant::from_ticks(micros)
781    }
782}