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

            
7
use core::fmt::{Debug, Display, Formatter, Result as FmtResult};
8

            
9
type InnerRate = fugit::Rate<u32, 1, 1>;
10
type InnerInstant = fugit::Instant<u64, 1, 1_000_000, fugit::kind::Monotonic>;
11
type 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)]
15
pub struct Rate(InnerRate);
16

            
17
impl 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

            
24
impl Display for Rate {
25
    #[inline]
26
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
27
        write!(f, "{} Hz", self.as_hz())
28
    }
29
}
30

            
31
impl 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")]
39
impl 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

            
46
impl Rate {
47
    #[procmacros::doc_replace]
48
    /// Creates a new rate that represents hertz.
49
    ///
50
    /// # Examples
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
    /// Creates a new rate that represents kilohertz.
65
    ///
66
    /// # Examples
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
    /// Creates a new rate that represents megahertz.
81
    ///
82
    /// # Examples
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
    /// Converts the `Rate` to an integer number of Hz.
97
    ///
98
    /// # Examples
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
    /// Converts the `Rate` to an integer number of kHz.
114
    ///
115
    /// # Examples
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
    /// Converts the `Rate` to an integer number of MHz.
131
    ///
132
    /// # Examples
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
6
        self.0.to_MHz()
144
    }
145

            
146
    #[procmacros::doc_replace]
147
    /// Converts the `Rate` to a `Duration`.
148
    ///
149
    /// # Examples
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

            
164
impl 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

            
173
impl 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

            
182
impl 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)]
193
pub struct Instant(InnerInstant);
194

            
195
impl 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

            
206
impl 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")]
218
impl 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

            
229
impl 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

            
236
impl 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 does not measure time in sleep mode.
250
    ///
251
    /// The timer has a 1 microsecond resolution and wraps after __wrap_after__.
252
    ///
253
    /// <section class="warning">
254
    /// Returns an unreliable value before <code>esp_hal::init()</code> is called.
255
    /// </section>
256
    ///
257
    /// # Examples
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
    /// # Examples
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
    /// # Examples
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

            
310
impl 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

            
319
impl core::ops::AddAssign<Duration> for Instant {
320
    #[inline]
321
    fn add_assign(&mut self, rhs: Duration) {
322
        self.0 += rhs.0;
323
    }
324
}
325

            
326
impl 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

            
335
impl 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

            
344
impl 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)]
353
pub struct Duration(InnerDuration);
354

            
355
impl Debug for Duration {
356
    #[inline]
357
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
358
        write!(f, "Duration({} µs)", self.as_micros())
359
    }
360
}
361

            
362
impl 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")]
370
impl 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

            
377
impl 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

            
384
impl Default for Duration {
385
    #[inline]
386
    fn default() -> Self {
387
        Self::ZERO
388
    }
389
}
390

            
391
impl Duration {
392
    /// A duration of zero time.
393
    pub const ZERO: Self = Self(InnerDuration::from_ticks(0));
394

            
395
    /// A duration representing the maximum possible time.
396
    pub const MAX: Self = Self(InnerDuration::from_ticks(u64::MAX));
397

            
398
    #[procmacros::doc_replace]
399
    /// Creates a new duration that represents microseconds.
400
    ///
401
    /// # Examples
402
    ///
403
    /// ```rust, no_run
404
    /// # {before_snippet}
405
    /// use esp_hal::time::Duration;
406
    /// let duration = Duration::from_micros(1000);
407
    /// # {after_snippet}
408
    /// ```
409
    #[inline]
410
    pub const fn from_micros(val: u64) -> Self {
411
        Self(InnerDuration::from_micros(val))
412
    }
413

            
414
    #[procmacros::doc_replace]
415
    /// Creates a new duration that represents milliseconds.
416
    ///
417
    /// # Examples
418
    ///
419
    /// ```rust, no_run
420
    /// # {before_snippet}
421
    /// use esp_hal::time::Duration;
422
    /// let duration = Duration::from_millis(100);
423
    /// # {after_snippet}
424
    /// ```
425
    #[inline]
426
    pub const fn from_millis(val: u64) -> Self {
427
        Self(InnerDuration::from_millis(val))
428
    }
429

            
430
    #[procmacros::doc_replace]
431
    /// Creates a new duration that represents seconds.
432
    ///
433
    /// # Examples
434
    ///
435
    /// ```rust, no_run
436
    /// # {before_snippet}
437
    /// use esp_hal::time::Duration;
438
    /// let duration = Duration::from_secs(1);
439
    /// # {after_snippet}
440
    /// ```
441
    #[inline]
442
    pub const fn from_secs(val: u64) -> Self {
443
        Self(InnerDuration::from_secs(val))
444
    }
445

            
446
    #[procmacros::doc_replace]
447
    /// Creates a new duration that represents minutes.
448
    ///
449
    /// # Examples
450
    ///
451
    /// ```rust, no_run
452
    /// # {before_snippet}
453
    /// use esp_hal::time::Duration;
454
    /// let duration = Duration::from_minutes(1);
455
    /// # {after_snippet}
456
    /// ```
457
    #[inline]
458
    pub const fn from_minutes(val: u64) -> Self {
459
        Self(InnerDuration::from_minutes(val))
460
    }
461

            
462
    #[procmacros::doc_replace]
463
    /// Creates a new duration that represents hours.
464
    ///
465
    /// # Examples
466
    ///
467
    /// ```rust, no_run
468
    /// # {before_snippet}
469
    /// use esp_hal::time::Duration;
470
    /// let duration = Duration::from_hours(1);
471
    /// # {after_snippet}
472
    /// ```
473
    #[inline]
474
    pub const fn from_hours(val: u64) -> Self {
475
        Self(InnerDuration::from_hours(val))
476
    }
477

            
478
    delegate::delegate! {
479
        #[inline]
480
        to self.0 {
481
            #[procmacros::doc_replace]
482
            /// Converts the `Duration` to an integer number of microseconds.
483
            ///
484
            /// # Examples
485
            ///
486
            /// ```rust, no_run
487
            /// # {before_snippet}
488
            /// use esp_hal::time::Duration;
489
            /// let duration = Duration::from_micros(1000);
490
            /// let micros = duration.as_micros();
491
            /// # {after_snippet}
492
            /// ```
493
            pub const fn as_micros(&self) -> u64;
494

            
495
            #[procmacros::doc_replace]
496
            /// Converts the `Duration` to an integer number of milliseconds.
497
            ///
498
            /// # Examples
499
            ///
500
            /// ```rust, no_run
501
            /// # {before_snippet}
502
            /// use esp_hal::time::Duration;
503
            /// let duration = Duration::from_millis(100);
504
            /// let millis = duration.as_millis();
505
            /// # {after_snippet}
506
            /// ```
507
            pub const fn as_millis(&self) -> u64;
508

            
509
            #[procmacros::doc_replace]
510
            /// Converts the `Duration` to an integer number of seconds.
511
            ///
512
            /// # Examples
513
            ///
514
            /// ```rust, no_run
515
            /// # {before_snippet}
516
            /// use esp_hal::time::Duration;
517
            /// let duration = Duration::from_secs(1);
518
            /// let secs = duration.as_secs();
519
            /// # {after_snippet}
520
            /// ```
521
            pub const fn as_secs(&self) -> u64;
522

            
523
            #[procmacros::doc_replace]
524
            /// Converts the `Duration` to an integer number of minutes.
525
            ///
526
            /// # Examples
527
            ///
528
            /// ```rust, no_run
529
            /// # {before_snippet}
530
            /// use esp_hal::time::Duration;
531
            /// let duration = Duration::from_minutes(1);
532
            /// let minutes = duration.as_minutes();
533
            /// # {after_snippet}
534
            /// ```
535
            pub const fn as_minutes(&self) -> u64;
536

            
537
            #[procmacros::doc_replace]
538
            /// Converts the `Duration` to an integer number of hours.
539
            ///
540
            /// # Examples
541
            ///
542
            /// ```rust, no_run
543
            /// # {before_snippet}
544
            /// use esp_hal::time::Duration;
545
            /// let duration = Duration::from_hours(1);
546
            /// let hours = duration.as_hours();
547
            /// # {after_snippet}
548
            /// ```
549
            pub const fn as_hours(&self) -> u64;
550
        }
551
    }
552

            
553
    #[procmacros::doc_replace]
554
    /// Adds two durations while checking for overflow.
555
    ///
556
    /// # Examples
557
    ///
558
    /// ```rust, no_run
559
    /// # {before_snippet}
560
    /// use esp_hal::time::Duration;
561
    /// let duration = Duration::from_secs(1);
562
    /// let duration2 = Duration::from_secs(2);
563
    ///
564
    /// if let Some(sum) = duration.checked_add(duration2) {
565
    ///     println!("Sum: {}", sum);
566
    /// } else {
567
    ///     println!("Overflow occurred");
568
    /// }
569
    /// # {after_snippet}
570
    /// ```
571
    #[inline]
572
    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
573
        if let Some(val) = self.0.checked_add(rhs.0) {
574
            Some(Duration(val))
575
        } else {
576
            None
577
        }
578
    }
579

            
580
    #[procmacros::doc_replace]
581
    /// Subtract two durations while checking for overflow.
582
    ///
583
    /// # Examples
584
    ///
585
    /// ```rust, no_run
586
    /// # {before_snippet}
587
    /// use esp_hal::time::Duration;
588
    /// let duration = Duration::from_secs(3);
589
    /// let duration2 = Duration::from_secs(1);
590
    ///
591
    /// if let Some(diff) = duration.checked_sub(duration2) {
592
    ///     println!("Difference: {}", diff);
593
    /// } else {
594
    ///     println!("Underflow occurred");
595
    /// }
596
    /// # {after_snippet}
597
    /// ```
598
    #[inline]
599
    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
600
        if let Some(val) = self.0.checked_sub(rhs.0) {
601
            Some(Duration(val))
602
        } else {
603
            None
604
        }
605
    }
606

            
607
    #[procmacros::doc_replace]
608
    /// Adds two durations, returning the maximum value if overflow occurred.
609
    ///
610
    /// # Examples
611
    ///
612
    /// ```rust, no_run
613
    /// # {before_snippet}
614
    /// use esp_hal::time::Duration;
615
    /// let duration = Duration::from_secs(1);
616
    /// let duration2 = Duration::from_secs(2);
617
    ///
618
    /// let sum = duration.saturating_add(duration2);
619
    /// # {after_snippet}
620
    /// ```
621
    #[inline]
622
    pub const fn saturating_add(self, rhs: Self) -> Self {
623
        if let Some(val) = self.checked_add(rhs) {
624
            val
625
        } else {
626
            Self::MAX
627
        }
628
    }
629

            
630
    #[procmacros::doc_replace]
631
    /// Subtract two durations, returning the minimum value if the result would
632
    /// be negative.
633
    ///
634
    /// # Examples
635
    ///
636
    /// ```rust, no_run
637
    /// # {before_snippet}
638
    /// use esp_hal::time::Duration;
639
    /// let duration = Duration::from_secs(3);
640
    /// let duration2 = Duration::from_secs(1);
641
    ///
642
    /// let diff = duration.saturating_sub(duration2);
643
    /// # {after_snippet}
644
    /// ```
645
    #[inline]
646
    pub const fn saturating_sub(self, rhs: Self) -> Self {
647
        if let Some(val) = self.checked_sub(rhs) {
648
            val
649
        } else {
650
            Self::ZERO
651
        }
652
    }
653
}
654

            
655
impl core::ops::Add for Duration {
656
    type Output = Self;
657

            
658
    #[inline]
659
    fn add(self, rhs: Self) -> Self::Output {
660
        Duration(self.0 + rhs.0)
661
    }
662
}
663

            
664
impl core::ops::AddAssign for Duration {
665
    #[inline]
666
    fn add_assign(&mut self, rhs: Self) {
667
        self.0 += rhs.0;
668
    }
669
}
670

            
671
impl core::ops::Sub for Duration {
672
    type Output = Self;
673

            
674
    #[inline]
675
    fn sub(self, rhs: Self) -> Self::Output {
676
1
        Duration(self.0 - rhs.0)
677
    }
678
}
679

            
680
impl core::ops::SubAssign for Duration {
681
    #[inline]
682
    fn sub_assign(&mut self, rhs: Self) {
683
        self.0 -= rhs.0;
684
    }
685
}
686

            
687
impl core::ops::Mul<u32> for Duration {
688
    type Output = Self;
689

            
690
    #[inline]
691
    fn mul(self, rhs: u32) -> Self::Output {
692
        Duration(self.0 * rhs)
693
    }
694
}
695

            
696
impl core::ops::Div<u32> for Duration {
697
    type Output = Self;
698

            
699
    #[inline]
700
    fn div(self, rhs: u32) -> Self::Output {
701
        Duration(self.0 / rhs)
702
    }
703
}
704

            
705
impl core::ops::Div<Duration> for Duration {
706
    type Output = u64;
707

            
708
    #[inline]
709
    fn div(self, rhs: Duration) -> Self::Output {
710
        self.0 / rhs.0
711
    }
712
}
713

            
714
#[inline]
715
pub(crate) fn now() -> Instant {
716
    let ticks = implem::raw_counter();
717
    let micros = implem::ticks_to_us(ticks);
718

            
719
    Instant::from_ticks(micros)
720
}
721

            
722
#[cfg(esp32)]
723
pub(crate) mod implem {
724
    use esp_sync::RawMutex;
725

            
726
    use crate::peripherals::TIMG0;
727

            
728
    #[cfg(feature = "rt")]
729
    pub(crate) fn time_init() {
730
        // FIXME: does this imply that clock management needs to be "rt", too?
731
        let apb = crate::soc::clocks::apb_clk_frequency();
732

            
733
        let tg0 = TIMG0::regs();
734

            
735
        tg0.lactconfig().write(|w| unsafe { w.bits(0) });
736
        tg0.lactalarmhi().write(|w| unsafe { w.bits(u32::MAX) });
737
        tg0.lactalarmlo().write(|w| unsafe { w.bits(u32::MAX) });
738
        tg0.lactload().write(|w| unsafe { w.load().bits(1) });
739

            
740
        // 16 MHz counter
741
        tg0.lactconfig().write(|w| {
742
            unsafe { w.divider().bits((apb / 16_000_000u32) as u16) };
743
            w.increase().bit(true);
744
            w.autoreload().bit(true);
745
            w.en().bit(true)
746
        });
747
    }
748

            
749
    #[inline]
750
    pub(crate) fn raw_counter() -> u64 {
751
        // The latch is shared between cores, so we need additional locking
752
        static LACT_LOCK: RawMutex = RawMutex::new();
753

            
754
        // on ESP32 use LACT
755
        let tg0 = TIMG0::regs();
756
        let (hi, lo) = LACT_LOCK.lock(|| {
757
            tg0.lactupdate().write(|w| unsafe { w.update().bits(1) });
758

            
759
            // The peripheral doesn't have a bit to indicate that the update is done, so we
760
            // poll the lower 32 bit part of the counter until it changes, or a timeout
761
            // expires.
762
            let lo_initial = tg0.lactlo().read().bits();
763
            let mut div = tg0.lactconfig().read().divider().bits();
764
            let lo = loop {
765
                let lo = tg0.lactlo().read().bits();
766
                if lo != lo_initial || div == 0 {
767
                    break lo;
768
                }
769
                div -= 1;
770
            };
771
            let hi = tg0.lacthi().read().bits();
772

            
773
            (hi, lo)
774
        });
775

            
776
        ((hi as u64) << 32u64) | lo as u64
777
    }
778

            
779
    #[inline]
780
    pub(crate) fn ticks_to_us(ticks: u64) -> u64 {
781
        ticks / 16
782
    }
783

            
784
    #[inline]
785
    #[cfg(all(sleep_light_sleep, feature = "rt"))]
786
    pub(crate) fn us_to_ticks(counter: u64) -> u64 {
787
        counter * 16
788
    }
789

            
790
    /// Callers must ensure this function is not called concurrently.
791
    #[inline]
792
    #[cfg(all(sleep_light_sleep, feature = "rt"))]
793
    pub(crate) unsafe fn update_counter(counter: u64) {
794
        // On ESP32 the monotonic counter is the LACT timer of TIMG0. To set its
795
        // value we stage the new 64-bit count in the load registers and then
796
        // trigger a software reload, which copies the staged value into the
797
        // counter immediately.
798
        //
799
        // A manual `LACTLOAD` while the timer is running (`en = 1`) is silently
800
        // dropped when executed from the AppCpu, leaving the monotonic clock stuck
801
        // (this is why the post-light-sleep time correction is lost on AppCpu). We
802
        // therefore disable the timer around the load (preserving the divider) and
803
        // re-enable it afterwards, mirroring `time_init`. Callers run this with
804
        // interrupts disabled and the other core parked, so the brief disable is
805
        // safe from concurrent reads.
806
        let tg0 = TIMG0::regs();
807

            
808
        let divider = tg0.lactconfig().read().divider().bits();
809
        tg0.lactconfig().write(|w| unsafe { w.bits(0) });
810

            
811
        tg0.lactloadhi()
812
            .write(|w| unsafe { w.load_hi().bits((counter >> 32) as u32) });
813
        tg0.lactloadlo()
814
            .write(|w| unsafe { w.load_lo().bits(counter as u32) });
815
        tg0.lactload().write(|w| unsafe { w.load().bits(1) });
816

            
817
        tg0.lactconfig().write(|w| {
818
            unsafe { w.divider().bits(divider) };
819
            w.increase().bit(true);
820
            w.autoreload().bit(true);
821
            w.en().bit(true)
822
        });
823
    }
824
}
825

            
826
#[cfg(systimer_driver_supported)]
827
pub(crate) mod implem {
828
    use crate::timer::systimer::{SystemTimer, Unit};
829

            
830
    #[cfg(feature = "rt")]
831
    pub(crate) fn time_init() {
832
        SystemTimer::init_timestamp_scaler();
833
    }
834

            
835
    #[inline]
836
    pub(crate) fn raw_counter() -> u64 {
837
        SystemTimer::unit_value(Unit::Unit0)
838
    }
839

            
840
    #[inline]
841
    pub(crate) fn ticks_to_us(ticks: u64) -> u64 {
842
        SystemTimer::ticks_to_us(ticks)
843
    }
844

            
845
    #[inline]
846
    #[cfg(all(sleep_light_sleep, feature = "rt"))]
847
    pub(crate) fn us_to_ticks(counter: u64) -> u64 {
848
        SystemTimer::us_to_ticks(counter)
849
    }
850

            
851
    /// Callers must ensure this function is not called concurrently.
852
    #[inline]
853
    #[cfg(all(sleep_light_sleep, feature = "rt"))]
854
    pub(crate) unsafe fn update_counter(counter: u64) {
855
        unsafe {
856
            SystemTimer::set_unit_value(Unit::Unit0, counter);
857
        }
858
    }
859
}