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