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}