esp_hal/rtc_cntl/
mod.rs

1//! # Real-Time Control and Low-power Management (RTC_CNTL)
2//!
3//! ## Overview
4//!
5//! The RTC_CNTL peripheral is responsible for managing the low-power modes on
6//! the chip.
7//!
8//! ## Configuration
9//!
10//! It also includes the necessary configurations and constants for clock
11//! sources and low-power management. The driver provides the following features
12//! and functionalities:
13//!
14//!    * Clock Configuration
15//!    * Calibration
16//!    * Low-Power Management
17//!    * Handling Watchdog Timers
18//!
19//! ## Examples
20//!
21//! ### Get time in ms from the RTC Timer
22//!
23//! ```rust, no_run
24#![doc = crate::before_snippet!()]
25//! # use core::time::Duration;
26//! # use esp_hal::{delay::Delay, rtc_cntl::Rtc};
27//!
28//! let rtc = Rtc::new(peripherals.LPWR);
29//! let delay = Delay::new();
30//!
31//! loop {
32//!     // Print the current RTC time in milliseconds
33//!     let time_ms = rtc.current_time().and_utc().timestamp_millis();
34//!     delay.delay_millis(1000);
35//!
36//!     // Set the time to half a second in the past
37//!     let new_time = rtc.current_time() - Duration::from_millis(500);
38//!     rtc.set_current_time(new_time);
39//! }
40//! # }
41//! ```
42//! 
43//! ### RWDT usage
44//! ```rust, no_run
45#![doc = crate::before_snippet!()]
46//! # use core::cell::RefCell;
47//! # use critical_section::Mutex;
48//! # use esp_hal::delay::Delay;
49//! # use esp_hal::rtc_cntl::Rtc;
50//! # use esp_hal::rtc_cntl::Rwdt;
51//! # use esp_hal::rtc_cntl::RwdtStage;
52//! static RWDT: Mutex<RefCell<Option<Rwdt>>> = Mutex::new(RefCell::new(None));
53//!
54//! let mut delay = Delay::new();
55//! let mut rtc = Rtc::new(peripherals.LPWR);
56//!
57//! rtc.set_interrupt_handler(interrupt_handler);
58//! rtc.rwdt.set_timeout(RwdtStage::Stage0, Duration::from_millis(2000));
59//! rtc.rwdt.listen();
60//!
61//! critical_section::with(|cs| RWDT.borrow_ref_mut(cs).replace(rtc.rwdt));
62//! # Ok(())
63//! # }
64//!
65//! // Where the `LP_WDT` interrupt handler is defined as:
66//! # use core::cell::RefCell;
67//! # use critical_section::Mutex;
68//! # use esp_hal::rtc_cntl::Rwdt;
69//! # use esp_hal::rtc_cntl::RwdtStage;
70//! static RWDT: Mutex<RefCell<Option<Rwdt>>> = Mutex::new(RefCell::new(None));
71//!
72//! // Handle the corresponding interrupt
73//! #[handler]
74//! fn interrupt_handler() {
75//!     critical_section::with(|cs| {
76//!         println!("RWDT Interrupt");
77//!
78//!         let mut rwdt = RWDT.borrow_ref_mut(cs);
79//!         if let Some(rwdt) = rwdt.as_mut() {
80//!             rwdt.clear_interrupt();
81//!
82//!             println!("Restarting in 5 seconds...");
83//!
84//!             rwdt.set_timeout(
85//!                 RwdtStage::Stage0,
86//!                 Duration::from_millis(5000),
87//!             );
88//!             rwdt.unlisten();
89//!         }
90//!     });
91//! }
92//! ```
93//! 
94//! ### Get time in ms from the RTC Timer
95//! ```rust, no_run
96#![doc = crate::before_snippet!()]
97//! # use core::time::Duration;
98//! # use esp_hal::{delay::Delay, rtc_cntl::Rtc};
99//!
100//! let rtc = Rtc::new(peripherals.LPWR);
101//! let delay = Delay::new();
102//!
103//! loop {
104//!     // Get the current RTC time in milliseconds
105//!     let time_ms = rtc.current_time().and_utc().timestamp_millis();
106//!     delay.delay_millis(1000);
107//!
108//!     // Set the time to half a second in the past
109//!     let new_time = rtc.current_time() - Duration::from_millis(500);
110//!     rtc.set_current_time(new_time);
111//! }
112//! # }
113//! ```
114
115use chrono::{DateTime, NaiveDateTime};
116
117pub use self::rtc::SocResetReason;
118#[cfg(not(any(esp32c6, esp32h2)))]
119use crate::clock::XtalClock;
120#[cfg(not(esp32))]
121use crate::efuse::Efuse;
122#[cfg(any(esp32, esp32s3, esp32c3, esp32c6, esp32c2))]
123use crate::rtc_cntl::sleep::{RtcSleepConfig, WakeSource, WakeTriggers};
124use crate::{
125    clock::Clock,
126    interrupt::{self, InterruptHandler},
127    peripheral::{Peripheral, PeripheralRef},
128    peripherals::Interrupt,
129    system::{Cpu, SleepSource},
130    time::Duration,
131};
132#[cfg(not(any(esp32c6, esp32h2)))]
133use crate::{
134    peripherals::{LPWR, TIMG0},
135    time::Rate,
136};
137// only include sleep where it's been implemented
138#[cfg(any(esp32, esp32s3, esp32c3, esp32c6, esp32c2))]
139pub mod sleep;
140
141#[cfg_attr(esp32, path = "rtc/esp32.rs")]
142#[cfg_attr(esp32c2, path = "rtc/esp32c2.rs")]
143#[cfg_attr(esp32c3, path = "rtc/esp32c3.rs")]
144#[cfg_attr(esp32c6, path = "rtc/esp32c6.rs")]
145#[cfg_attr(esp32h2, path = "rtc/esp32h2.rs")]
146#[cfg_attr(esp32s2, path = "rtc/esp32s2.rs")]
147#[cfg_attr(esp32s3, path = "rtc/esp32s3.rs")]
148pub(crate) mod rtc;
149
150cfg_if::cfg_if! {
151    if #[cfg(any(esp32c6, esp32h2))] {
152        use crate::peripherals::LP_WDT;
153        use crate::peripherals::LP_TIMER;
154        use crate::peripherals::LP_AON;
155    } else {
156        use crate::peripherals::LPWR as LP_WDT;
157        use crate::peripherals::LPWR as LP_TIMER;
158        use crate::peripherals::LPWR as LP_AON;
159    }
160}
161
162bitflags::bitflags! {
163    #[allow(unused)]
164    struct WakeupReason: u32 {
165        const NoSleep         = 0;
166        #[cfg(pm_support_ext0_wakeup)]
167        /// EXT0 GPIO wakeup
168        const ExtEvent0Trig   = 1 << 0;
169        #[cfg(pm_support_ext1_wakeup)]
170        /// EXT1 GPIO wakeup
171        const ExtEvent1Trig   = 1 << 1;
172        /// GPIO wakeup (light sleep only)
173        const GpioTrigEn      = 1 << 2;
174        #[cfg(not(any(esp32c6, esp32h2)))]
175        /// Timer wakeup
176        const TimerTrigEn     = 1 << 3;
177        #[cfg(any(esp32c6, esp32h2))]
178        /// Timer wakeup
179        const TimerTrigEn     = 1 << 4;
180        #[cfg(pm_support_wifi_wakeup)]
181        /// MAC wakeup (light sleep only)
182        const WifiTrigEn      = 1 << 5;
183        /// UART0 wakeup (light sleep only)
184        const Uart0TrigEn     = 1 << 6;
185        /// UART1 wakeup (light sleep only)
186        const Uart1TrigEn     = 1 << 7;
187        #[cfg(pm_support_touch_sensor_wakeup)]
188        /// Touch wakeup
189        const TouchTrigEn     = 1 << 8;
190        #[cfg(ulp_supported)]
191        /// ULP wakeup
192        const UlpTrigEn       = 1 << 9;
193        #[cfg(pm_support_bt_wakeup)]
194        /// BT wakeup (light sleep only)
195        const BtTrigEn        = 1 << 10;
196        #[cfg(riscv_coproc_supported)]
197        const CocpuTrigEn     = 1 << 11;
198        #[cfg(riscv_coproc_supported)]
199        const CocpuTrapTrigEn = 1 << 13;
200    }
201}
202
203#[cfg(not(any(esp32c6, esp32h2)))]
204#[allow(unused)]
205#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
206#[cfg_attr(feature = "defmt", derive(defmt::Format))]
207#[allow(clippy::enum_variant_names)] // FIXME: resolve this
208/// RTC SLOW_CLK frequency values
209pub(crate) enum RtcFastClock {
210    /// Main XTAL, divided by 4
211    RtcFastClockXtalD4 = 0,
212    /// Internal fast RC oscillator
213    RtcFastClock8m     = 1,
214}
215
216#[cfg(not(any(esp32c6, esp32h2)))]
217impl Clock for RtcFastClock {
218    fn frequency(&self) -> Rate {
219        match self {
220            RtcFastClock::RtcFastClockXtalD4 => Rate::from_hz(40_000_000 / 4),
221            #[cfg(any(esp32, esp32s2))]
222            RtcFastClock::RtcFastClock8m => Rate::from_hz(8_500_000),
223            #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
224            RtcFastClock::RtcFastClock8m => Rate::from_hz(17_500_000),
225        }
226    }
227}
228
229#[cfg(not(any(esp32c6, esp32h2)))]
230#[non_exhaustive]
231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
232#[cfg_attr(feature = "defmt", derive(defmt::Format))]
233#[allow(clippy::enum_variant_names)] // FIXME: resolve this
234/// RTC SLOW_CLK frequency values
235pub enum RtcSlowClock {
236    /// Internal slow RC oscillator
237    RtcSlowClockRtc     = 0,
238    /// External 32 KHz XTAL
239    RtcSlowClock32kXtal = 1,
240    /// Internal fast RC oscillator, divided by 256
241    RtcSlowClock8mD256  = 2,
242}
243
244#[cfg(not(any(esp32c6, esp32h2)))]
245impl Clock for RtcSlowClock {
246    fn frequency(&self) -> Rate {
247        match self {
248            #[cfg(esp32)]
249            RtcSlowClock::RtcSlowClockRtc => Rate::from_hz(150_000),
250            #[cfg(esp32s2)]
251            RtcSlowClock::RtcSlowClockRtc => Rate::from_hz(90_000),
252            #[cfg(any(esp32c2, esp32c3, esp32s3))]
253            RtcSlowClock::RtcSlowClockRtc => Rate::from_hz(136_000),
254            RtcSlowClock::RtcSlowClock32kXtal => Rate::from_hz(32_768),
255            #[cfg(any(esp32, esp32s2))]
256            RtcSlowClock::RtcSlowClock8mD256 => Rate::from_hz(8_500_000 / 256),
257            #[cfg(any(esp32c2, esp32c3, esp32s3))]
258            RtcSlowClock::RtcSlowClock8mD256 => Rate::from_hz(17_500_000 / 256),
259        }
260    }
261}
262
263#[allow(unused)]
264#[cfg(not(any(esp32c6, esp32h2)))]
265#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
266#[cfg_attr(feature = "defmt", derive(defmt::Format))]
267#[allow(clippy::enum_variant_names)] // FIXME: resolve this
268/// Clock source to be calibrated using rtc_clk_cal function
269pub(crate) enum RtcCalSel {
270    /// Currently selected RTC SLOW_CLK
271    RtcCalRtcMux      = 0,
272    /// Internal 8 MHz RC oscillator, divided by 256
273    RtcCal8mD256      = 1,
274    /// External 32 KHz XTAL
275    RtcCal32kXtal     = 2,
276    #[cfg(not(esp32))]
277    /// Internal 150 KHz RC oscillator
278    RtcCalInternalOsc = 3,
279}
280
281/// Low-power Management
282pub struct Rtc<'d> {
283    _inner: PeripheralRef<'d, crate::peripherals::LPWR>,
284    /// Reset Watchdog Timer.
285    pub rwdt: Rwdt,
286    #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
287    /// Super Watchdog
288    pub swd: Swd,
289}
290
291impl<'d> Rtc<'d> {
292    /// Create a new instance in [crate::Blocking] mode.
293    ///
294    /// Optionally an interrupt handler can be bound.
295    pub fn new(rtc_cntl: impl Peripheral<P = crate::peripherals::LPWR> + 'd) -> Self {
296        rtc::init();
297        rtc::configure_clock();
298
299        let this = Self {
300            _inner: rtc_cntl.into_ref(),
301            rwdt: Rwdt::new(),
302            #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
303            swd: Swd::new(),
304        };
305
306        #[cfg(any(esp32, esp32s3, esp32c3, esp32c6, esp32c2))]
307        RtcSleepConfig::base_settings(&this);
308
309        this
310    }
311
312    /// Return estimated XTAL frequency in MHz.
313    pub fn estimate_xtal_frequency(&mut self) -> u32 {
314        RtcClock::estimate_xtal_frequency()
315    }
316
317    /// Get the time since boot in the raw register units.
318    fn time_since_boot_raw(&self) -> u64 {
319        let rtc_cntl = LP_TIMER::regs();
320
321        #[cfg(esp32)]
322        let (l, h) = {
323            rtc_cntl.time_update().write(|w| w.time_update().set_bit());
324            while rtc_cntl.time_update().read().time_valid().bit_is_clear() {
325                // might take 1 RTC slowclk period, don't flood RTC bus
326                crate::rom::ets_delay_us(1);
327            }
328            let h = rtc_cntl.time1().read().time_hi().bits();
329            let l = rtc_cntl.time0().read().time_lo().bits();
330            (l, h)
331        };
332        #[cfg(any(esp32c2, esp32c3, esp32s3, esp32s2))]
333        let (l, h) = {
334            rtc_cntl.time_update().write(|w| w.time_update().set_bit());
335            let h = rtc_cntl.time_high0().read().timer_value0_high().bits();
336            let l = rtc_cntl.time_low0().read().timer_value0_low().bits();
337            (l, h)
338        };
339        #[cfg(any(esp32c6, esp32h2))]
340        let (l, h) = {
341            rtc_cntl.update().write(|w| w.main_timer_update().set_bit());
342            let h = rtc_cntl
343                .main_buf0_high()
344                .read()
345                .main_timer_buf0_high()
346                .bits();
347            let l = rtc_cntl.main_buf0_low().read().main_timer_buf0_low().bits();
348            (l, h)
349        };
350        ((h as u64) << 32) | (l as u64)
351    }
352
353    /// Get the time since boot.
354    pub fn time_since_boot(&self) -> Duration {
355        Duration::from_micros(
356            self.time_since_boot_raw() * 1_000_000
357                / RtcClock::slow_freq().frequency().as_hz() as u64,
358        )
359    }
360
361    /// Read the current value of the boot time registers in microseconds.
362    fn boot_time_us(&self) -> u64 {
363        // For more info on about how RTC setting works and what it has to do with boot time, see https://github.com/esp-rs/esp-hal/pull/1883
364
365        // In terms of registers, STORE2 and STORE3 are used on all current chips
366        // (esp32, esp32p4, esp32h2, esp32c2, esp32c3, esp32c5, esp32c6, esp32c61,
367        // esp32s2, esp32s3)
368
369        // In terms of peripherals:
370
371        // - LPWR is used on the following chips: esp32, esp32p4, esp32c2, esp32c3,
372        //   esp32s2, esp32s3
373
374        // - LP_AON is used on the following chips: esp32c5, esp32c6, esp32c61, esp32h2
375
376        // For registers and peripherals used in esp-idf, see https://github.com/search?q=repo%3Aespressif%2Fesp-idf+RTC_BOOT_TIME_LOW_REG+RTC_BOOT_TIME_HIGH_REG+path%3A**%2Frtc.h&type=code
377
378        let rtc_cntl = LP_AON::regs();
379
380        let (l, h) = (rtc_cntl.store2(), rtc_cntl.store3());
381
382        let l = l.read().bits() as u64;
383        let h = h.read().bits() as u64;
384
385        // https://github.com/espressif/esp-idf/blob/23e4823f17a8349b5e03536ff7653e3e584c9351/components/newlib/port/esp_time_impl.c#L115
386        l + (h << 32)
387    }
388
389    /// Set the current value of the boot time registers in microseconds.
390    fn set_boot_time_us(&self, boot_time_us: u64) {
391        // Please see `boot_time_us` for documentation on registers and peripherals
392        // used for certain SOCs.
393
394        let rtc_cntl = LP_AON::regs();
395
396        let (l, h) = (rtc_cntl.store2(), rtc_cntl.store3());
397
398        // https://github.com/espressif/esp-idf/blob/23e4823f17a8349b5e03536ff7653e3e584c9351/components/newlib/port/esp_time_impl.c#L102-L103
399        l.write(|w| unsafe { w.bits((boot_time_us & 0xffffffff) as u32) });
400        h.write(|w| unsafe { w.bits((boot_time_us >> 32) as u32) });
401    }
402
403    /// Get the current time.
404    pub fn current_time(&self) -> NaiveDateTime {
405        // Current time is boot time + time since boot
406
407        let rtc_time_us = self.time_since_boot().as_micros();
408        let boot_time_us = self.boot_time_us();
409        let wrapped_boot_time_us = u64::MAX - boot_time_us;
410
411        // We can detect if we wrapped the boot time by checking if rtc time is greater
412        // than the amount of time we would've wrapped.
413        let current_time_us = if rtc_time_us > wrapped_boot_time_us {
414            // We also just checked that this won't overflow
415            rtc_time_us - wrapped_boot_time_us
416        } else {
417            boot_time_us + rtc_time_us
418        };
419
420        DateTime::from_timestamp_micros(current_time_us as i64)
421            .unwrap()
422            .naive_utc()
423    }
424
425    /// Set the current time.
426    ///
427    /// # Panics
428    ///
429    /// Panics if `current_time` is before the Unix epoch (meaning the
430    /// underlying timestamp is negative).
431    pub fn set_current_time(&self, current_time: NaiveDateTime) {
432        let current_time_us: u64 = current_time
433            .and_utc()
434            .timestamp_micros()
435            .try_into()
436            .expect("current_time is negative");
437
438        // Current time is boot time + time since boot (rtc time)
439        // So boot time = current time - time since boot (rtc time)
440
441        let rtc_time_us = self.time_since_boot().as_micros();
442        if current_time_us < rtc_time_us {
443            // An overflow would happen if we subtracted rtc_time_us from current_time_us.
444            // To work around this, we can wrap around u64::MAX by subtracting the
445            // difference between the current time and the time since boot.
446            // Subtracting time since boot and adding current new time is equivalent and
447            // avoids overflow. We just checked that rtc_time_us is less than time_us
448            // so this won't overflow.
449            self.set_boot_time_us(u64::MAX - rtc_time_us + current_time_us)
450        } else {
451            self.set_boot_time_us(current_time_us - rtc_time_us)
452        }
453    }
454
455    /// Enter deep sleep and wake with the provided `wake_sources`.
456    #[cfg(any(esp32, esp32s3, esp32c3, esp32c6, esp32c2))]
457    pub fn sleep_deep(&mut self, wake_sources: &[&dyn WakeSource]) -> ! {
458        let config = RtcSleepConfig::deep();
459        self.sleep(&config, wake_sources);
460        unreachable!();
461    }
462
463    /// Enter light sleep and wake with the provided `wake_sources`.
464    #[cfg(any(esp32, esp32s3, esp32c3, esp32c6, esp32c2))]
465    pub fn sleep_light(&mut self, wake_sources: &[&dyn WakeSource]) {
466        let config = RtcSleepConfig::default();
467        self.sleep(&config, wake_sources);
468    }
469
470    /// Enter sleep with the provided `config` and wake with the provided
471    /// `wake_sources`.
472    #[cfg(any(esp32, esp32s3, esp32c3, esp32c6, esp32c2))]
473    pub fn sleep(&mut self, config: &RtcSleepConfig, wake_sources: &[&dyn WakeSource]) {
474        let mut config = *config;
475        let mut wakeup_triggers = WakeTriggers::default();
476        for wake_source in wake_sources {
477            wake_source.apply(self, &mut wakeup_triggers, &mut config)
478        }
479
480        config.apply();
481
482        config.start_sleep(wakeup_triggers);
483        config.finish_sleep();
484    }
485
486    const RTC_DISABLE_ROM_LOG: u32 = 1;
487
488    /// Temporarily disable log messages of the ROM bootloader.
489    ///
490    /// If you need to permanently disable the ROM bootloader messages, you'll
491    /// need to set the corresponding eFuse.
492    #[cfg(any(esp32s3, esp32h2))]
493    pub fn disable_rom_message_printing(&self) {
494        // Corresponding documentation:
495        // ESP32-S3: TRM v1.5 chapter 8.3
496        // ESP32-H2: TRM v0.5 chapter 8.2.3
497
498        let rtc_cntl = LP_AON::regs();
499        rtc_cntl
500            .store4()
501            .modify(|r, w| unsafe { w.bits(r.bits() | Self::RTC_DISABLE_ROM_LOG) });
502    }
503
504    /// Register an interrupt handler for the RTC.
505    ///
506    /// Note that this will replace any previously registered interrupt
507    /// handlers.
508    #[instability::unstable]
509    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
510        cfg_if::cfg_if! {
511            if #[cfg(any(esp32c6, esp32h2))] {
512                let interrupt = Interrupt::LP_WDT;
513            } else {
514                let interrupt = Interrupt::RTC_CORE;
515            }
516        }
517        for core in crate::system::Cpu::other() {
518            crate::interrupt::disable(core, interrupt);
519        }
520        unsafe { interrupt::bind_interrupt(interrupt, handler.handler()) };
521        unwrap!(interrupt::enable(interrupt, handler.priority()));
522    }
523}
524impl crate::private::Sealed for Rtc<'_> {}
525
526#[instability::unstable]
527impl crate::interrupt::InterruptConfigurable for Rtc<'_> {
528    fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
529        self.set_interrupt_handler(handler);
530    }
531}
532
533/// RTC Watchdog Timer.
534pub struct RtcClock;
535
536/// RTC Watchdog Timer driver.
537impl RtcClock {
538    const CAL_FRACT: u32 = 19;
539
540    /// Enable or disable 8 MHz internal oscillator.
541    ///
542    /// Output from 8 MHz internal oscillator is passed into a configurable
543    /// divider, which by default divides the input clock frequency by 256.
544    /// Output of the divider may be used as RTC_SLOW_CLK source.
545    /// Output of the divider is referred to in register descriptions and code
546    /// as 8md256 or simply d256. Divider values other than 256 may be
547    /// configured, but this facility is not currently needed, so is not
548    /// exposed in the code.
549    ///
550    /// When 8MHz/256 divided output is not needed, the divider should be
551    /// disabled to reduce power consumption.
552    #[cfg(not(any(esp32c6, esp32h2)))]
553    fn enable_8m(clk_8m_en: bool, d256_en: bool) {
554        let rtc_cntl = LPWR::regs();
555
556        if clk_8m_en {
557            rtc_cntl.clk_conf().modify(|_, w| w.enb_ck8m().clear_bit());
558            unsafe {
559                rtc_cntl.timer1().modify(|_, w| w.ck8m_wait().bits(5));
560            }
561            crate::rom::ets_delay_us(50);
562        } else {
563            rtc_cntl.clk_conf().modify(|_, w| w.enb_ck8m().set_bit());
564            rtc_cntl
565                .timer1()
566                .modify(|_, w| unsafe { w.ck8m_wait().bits(20) });
567        }
568
569        if d256_en {
570            rtc_cntl
571                .clk_conf()
572                .modify(|_, w| w.enb_ck8m_div().clear_bit());
573        } else {
574            rtc_cntl
575                .clk_conf()
576                .modify(|_, w| w.enb_ck8m_div().set_bit());
577        }
578    }
579
580    pub(crate) fn read_xtal_freq_mhz() -> Option<u32> {
581        let xtal_freq_reg = LP_AON::regs().store4().read().bits();
582
583        // RTC_XTAL_FREQ is stored as two copies in lower and upper 16-bit halves
584        // need to mask out the RTC_DISABLE_ROM_LOG bit which is also stored in the same
585        // register
586        let xtal_freq = (xtal_freq_reg & !Rtc::RTC_DISABLE_ROM_LOG) as u16;
587        let xtal_freq_copy = (xtal_freq_reg >> 16) as u16;
588
589        if xtal_freq == xtal_freq_copy && xtal_freq != 0 && xtal_freq != u16::MAX {
590            Some(xtal_freq as u32)
591        } else {
592            None
593        }
594    }
595
596    /// Get main XTAL frequency.
597    /// This is the value stored in RTC register RTC_XTAL_FREQ_REG by the
598    /// bootloader, as passed to rtc_clk_init function.
599    #[cfg(not(any(esp32c6, esp32h2)))]
600    pub fn xtal_freq() -> XtalClock {
601        match Self::read_xtal_freq_mhz() {
602            None | Some(40) => XtalClock::_40M,
603            #[cfg(any(esp32c3, esp32s3))]
604            Some(32) => XtalClock::_32M,
605            #[cfg(any(esp32, esp32c2))]
606            Some(26) => XtalClock::_26M,
607            Some(other) => XtalClock::Other(other),
608        }
609    }
610
611    /// Get the RTC_SLOW_CLK source.
612    #[cfg(not(any(esp32c6, esp32h2)))]
613    pub fn slow_freq() -> RtcSlowClock {
614        let rtc_cntl = LPWR::regs();
615        let slow_freq = rtc_cntl.clk_conf().read().ana_clk_rtc_sel().bits();
616        match slow_freq {
617            0 => RtcSlowClock::RtcSlowClockRtc,
618            1 => RtcSlowClock::RtcSlowClock32kXtal,
619            2 => RtcSlowClock::RtcSlowClock8mD256,
620            _ => unreachable!(),
621        }
622    }
623
624    /// Select source for RTC_SLOW_CLK.
625    #[cfg(not(any(esp32c6, esp32h2)))]
626    fn set_slow_freq(slow_freq: RtcSlowClock) {
627        unsafe {
628            let rtc_cntl = LPWR::regs();
629            rtc_cntl.clk_conf().modify(|_, w| {
630                w.ana_clk_rtc_sel()
631                    .bits(slow_freq as u8)
632                    // Why we need to connect this clock to digital?
633                    // Or maybe this clock should be connected to digital when
634                    // XTAL 32k clock is enabled instead?
635                    .dig_xtal32k_en()
636                    .bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kXtal))
637                    // The clk_8m_d256 will be closed when rtc_state in SLEEP,
638                    // so if the slow_clk is 8md256, clk_8m must be force power on
639                    .ck8m_force_pu()
640                    .bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock8mD256))
641            });
642        };
643
644        crate::rom::ets_delay_us(300u32);
645    }
646
647    /// Select source for RTC_FAST_CLK.
648    #[cfg(not(any(esp32c6, esp32h2)))]
649    fn set_fast_freq(fast_freq: RtcFastClock) {
650        let rtc_cntl = LPWR::regs();
651        rtc_cntl.clk_conf().modify(|_, w| {
652            w.fast_clk_rtc_sel().bit(match fast_freq {
653                RtcFastClock::RtcFastClock8m => true,
654                RtcFastClock::RtcFastClockXtalD4 => false,
655            })
656        });
657
658        crate::rom::ets_delay_us(3u32);
659    }
660
661    /// Calibration of RTC_SLOW_CLK is performed using a special feature of
662    /// TIMG0. This feature counts the number of XTAL clock cycles within a
663    /// given number of RTC_SLOW_CLK cycles.
664    #[cfg(not(any(esp32c6, esp32h2)))]
665    fn calibrate_internal(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
666        // Except for ESP32, choosing RTC_CAL_RTC_MUX results in calibration of
667        // the 150k RTC clock (90k on ESP32-S2) regardless of the currently selected
668        // SLOW_CLK. On the ESP32, it uses the currently selected SLOW_CLK.
669        // The following code emulates ESP32 behavior for the other chips:
670        #[cfg(not(esp32))]
671        let cal_clk = match cal_clk {
672            RtcCalSel::RtcCalRtcMux => match RtcClock::slow_freq() {
673                RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
674                RtcSlowClock::RtcSlowClock8mD256 => RtcCalSel::RtcCal8mD256,
675                _ => cal_clk,
676            },
677            RtcCalSel::RtcCalInternalOsc => RtcCalSel::RtcCalRtcMux,
678            _ => cal_clk,
679        };
680        let rtc_cntl = LPWR::regs();
681        let timg0 = TIMG0::regs();
682
683        // Enable requested clock (150k clock is always on)
684        let dig_32k_xtal_enabled = rtc_cntl.clk_conf().read().dig_xtal32k_en().bit_is_set();
685
686        if matches!(cal_clk, RtcCalSel::RtcCal32kXtal) && !dig_32k_xtal_enabled {
687            rtc_cntl
688                .clk_conf()
689                .modify(|_, w| w.dig_xtal32k_en().set_bit());
690        }
691
692        if matches!(cal_clk, RtcCalSel::RtcCal8mD256) {
693            rtc_cntl
694                .clk_conf()
695                .modify(|_, w| w.dig_clk8m_d256_en().set_bit());
696        }
697
698        // There may be another calibration process already running during we
699        // call this function, so we should wait the last process is done.
700        #[cfg(not(esp32))]
701        if timg0
702            .rtccalicfg()
703            .read()
704            .rtc_cali_start_cycling()
705            .bit_is_set()
706        {
707            // Set a small timeout threshold to accelerate the generation of timeout.
708            // The internal circuit will be reset when the timeout occurs and will not
709            // affect the next calibration.
710            timg0
711                .rtccalicfg2()
712                .modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(1) });
713
714            while timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_clear()
715                && timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_clear()
716            {}
717        }
718
719        // Prepare calibration
720        timg0.rtccalicfg().modify(|_, w| unsafe {
721            w.rtc_cali_clk_sel()
722                .bits(cal_clk as u8)
723                .rtc_cali_start_cycling()
724                .clear_bit()
725                .rtc_cali_max()
726                .bits(slowclk_cycles as u16)
727        });
728
729        // Figure out how long to wait for calibration to finish
730        // Set timeout reg and expect time delay
731        let expected_freq = match cal_clk {
732            RtcCalSel::RtcCal32kXtal => {
733                #[cfg(not(esp32))]
734                timg0.rtccalicfg2().modify(|_, w| unsafe {
735                    w.rtc_cali_timeout_thres().bits(slowclk_cycles << 12)
736                });
737                RtcSlowClock::RtcSlowClock32kXtal
738            }
739            RtcCalSel::RtcCal8mD256 => {
740                #[cfg(not(esp32))]
741                timg0.rtccalicfg2().modify(|_, w| unsafe {
742                    w.rtc_cali_timeout_thres().bits(slowclk_cycles << 12)
743                });
744                RtcSlowClock::RtcSlowClock8mD256
745            }
746            _ => {
747                #[cfg(not(esp32))]
748                timg0.rtccalicfg2().modify(|_, w| unsafe {
749                    w.rtc_cali_timeout_thres().bits(slowclk_cycles << 10)
750                });
751                RtcSlowClock::RtcSlowClockRtc
752            }
753        };
754
755        let us_time_estimate = Rate::from_mhz(slowclk_cycles) / expected_freq.frequency();
756
757        // Start calibration
758        timg0
759            .rtccalicfg()
760            .modify(|_, w| w.rtc_cali_start().clear_bit().rtc_cali_start().set_bit());
761
762        // Wait for calibration to finish up to another us_time_estimate
763        crate::rom::ets_delay_us(us_time_estimate);
764
765        #[cfg(esp32)]
766        let mut timeout_us = us_time_estimate;
767
768        let cal_val = loop {
769            if timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_set() {
770                break timg0.rtccalicfg1().read().rtc_cali_value().bits();
771            }
772
773            #[cfg(not(esp32))]
774            if timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_set() {
775                // Timed out waiting for calibration
776                break 0;
777            }
778
779            #[cfg(esp32)]
780            if timeout_us > 0 {
781                timeout_us -= 1;
782                crate::rom::ets_delay_us(1);
783            } else {
784                // Timed out waiting for calibration
785                break 0;
786            }
787        };
788
789        timg0
790            .rtccalicfg()
791            .modify(|_, w| w.rtc_cali_start().clear_bit());
792        rtc_cntl
793            .clk_conf()
794            .modify(|_, w| w.dig_xtal32k_en().bit(dig_32k_xtal_enabled));
795
796        if matches!(cal_clk, RtcCalSel::RtcCal8mD256) {
797            rtc_cntl
798                .clk_conf()
799                .modify(|_, w| w.dig_clk8m_d256_en().clear_bit());
800        }
801
802        cal_val
803    }
804
805    /// Measure ratio between XTAL frequency and RTC slow clock frequency.
806    #[cfg(not(any(esp32c6, esp32h2)))]
807    fn calibration_ratio(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
808        let xtal_cycles = RtcClock::calibrate_internal(cal_clk, slowclk_cycles) as u64;
809        let ratio = (xtal_cycles << RtcClock::CAL_FRACT) / slowclk_cycles as u64;
810
811        (ratio & (u32::MAX as u64)) as u32
812    }
813
814    /// Measure RTC slow clock's period, based on main XTAL frequency.
815    ///
816    /// This function will time out and return 0 if the time for the given
817    /// number of cycles to be counted exceeds the expected time twice. This
818    /// may happen if 32k XTAL is being calibrated, but the oscillator has
819    /// not started up (due to incorrect loading capacitance, board design
820    /// issue, or lack of 32 XTAL on board).
821    #[cfg(not(any(esp32c6, esp32h2)))]
822    fn calibrate(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
823        let xtal_freq = RtcClock::xtal_freq();
824        let xtal_cycles = RtcClock::calibrate_internal(cal_clk, slowclk_cycles) as u64;
825        let divider = xtal_freq.mhz() as u64 * slowclk_cycles as u64;
826        let period_64 = ((xtal_cycles << RtcClock::CAL_FRACT) + divider / 2u64 - 1u64) / divider;
827
828        (period_64 & u32::MAX as u64) as u32
829    }
830
831    /// Calculate the necessary RTC_SLOW_CLK cycles to complete 1 millisecond.
832    #[cfg(not(any(esp32c6, esp32h2)))]
833    fn cycles_to_1ms() -> u16 {
834        let period_13q19 = RtcClock::calibrate(
835            match RtcClock::slow_freq() {
836                RtcSlowClock::RtcSlowClockRtc => RtcCalSel::RtcCalRtcMux,
837                RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
838                #[cfg(not(any(esp32c6, esp32h2)))]
839                RtcSlowClock::RtcSlowClock8mD256 => RtcCalSel::RtcCal8mD256,
840            },
841            1024,
842        );
843
844        // 100_000_000 is used to get rid of `float` calculations
845        let period = (100_000_000 * period_13q19 as u64) / (1 << RtcClock::CAL_FRACT);
846
847        (100_000_000 * 1000 / period) as u16
848    }
849
850    /// Return estimated XTAL frequency in MHz.
851    #[cfg(not(any(esp32c6, esp32h2)))]
852    pub(crate) fn estimate_xtal_frequency() -> u32 {
853        // Number of 8M/256 clock cycles to use for XTAL frequency estimation.
854        const XTAL_FREQ_EST_CYCLES: u32 = 10;
855
856        let rtc_cntl = LPWR::regs();
857        let clk_8m_enabled = rtc_cntl.clk_conf().read().enb_ck8m().bit_is_clear();
858        let clk_8md256_enabled = rtc_cntl.clk_conf().read().enb_ck8m_div().bit_is_clear();
859
860        if !clk_8md256_enabled {
861            RtcClock::enable_8m(true, true);
862        }
863
864        let ratio = RtcClock::calibration_ratio(RtcCalSel::RtcCal8mD256, XTAL_FREQ_EST_CYCLES);
865        let freq_mhz =
866            ((ratio as u64 * RtcFastClock::RtcFastClock8m.hz() as u64 / 1_000_000u64 / 256u64)
867                >> RtcClock::CAL_FRACT) as u32;
868
869        RtcClock::enable_8m(clk_8m_enabled, clk_8md256_enabled);
870
871        freq_mhz
872    }
873}
874
875/// Behavior of the RWDT stage if it times out.
876#[allow(unused)]
877#[derive(Debug, Clone, Copy)]
878pub enum RwdtStageAction {
879    /// No effect on the system.
880    Off         = 0,
881    /// Trigger an interrupt.
882    Interrupt   = 1,
883    /// Reset the CPU core.
884    ResetCpu    = 2,
885    /// Reset the main system.
886    /// The power management unit and RTC peripherals will not be reset.
887    ResetCore   = 3,
888    /// Reset the main system, power management unit and RTC peripherals.
889    ResetSystem = 4,
890}
891
892/// RWDT stages.
893///
894/// Timer stages allow for a timer to have a series of different timeout values
895/// and corresponding expiry action.
896#[derive(Debug, Clone, Copy)]
897pub enum RwdtStage {
898    /// RWDT stage 0.
899    Stage0,
900    /// RWDT stage 1.
901    Stage1,
902    /// RWDT stage 2.
903    Stage2,
904    /// RWDT stage 3.
905    Stage3,
906}
907
908/// RTC Watchdog Timer.
909pub struct Rwdt;
910
911impl Default for Rwdt {
912    fn default() -> Self {
913        Self::new()
914    }
915}
916
917/// RTC Watchdog Timer driver.
918impl Rwdt {
919    /// Create a new RTC watchdog timer instance
920    pub fn new() -> Self {
921        Self
922    }
923
924    /// Enable the watchdog timer instance.
925    /// Watchdog starts with default settings (`stage 0` resets the system, the
926    /// others are deactivated)
927    pub fn enable(&mut self) {
928        self.set_enabled(true);
929    }
930
931    /// Disable the watchdog timer instance.
932    pub fn disable(&mut self) {
933        self.set_enabled(false);
934    }
935
936    /// Listen for interrupts on stage 0.
937    pub fn listen(&mut self) {
938        let rtc_cntl = LP_WDT::regs();
939
940        self.set_write_protection(false);
941
942        // Configure STAGE0 to trigger an interrupt upon expiration
943        rtc_cntl
944            .wdtconfig0()
945            .modify(|_, w| unsafe { w.wdt_stg0().bits(RwdtStageAction::Interrupt as u8) });
946
947        rtc_cntl.int_ena().modify(|_, w| w.wdt().set_bit());
948
949        self.set_write_protection(true);
950    }
951
952    /// Stop listening for interrupts on stage 0.
953    pub fn unlisten(&mut self) {
954        let rtc_cntl = LP_WDT::regs();
955
956        self.set_write_protection(false);
957
958        // Configure STAGE0 to reset the main system and the RTC upon expiration.
959        rtc_cntl
960            .wdtconfig0()
961            .modify(|_, w| unsafe { w.wdt_stg0().bits(RwdtStageAction::ResetSystem as u8) });
962
963        rtc_cntl.int_ena().modify(|_, w| w.wdt().clear_bit());
964
965        self.set_write_protection(true);
966    }
967
968    /// Clear interrupt.
969    pub fn clear_interrupt(&mut self) {
970        let rtc_cntl = LP_WDT::regs();
971
972        self.set_write_protection(false);
973
974        rtc_cntl.int_clr().write(|w| w.wdt().clear_bit_by_one());
975
976        self.set_write_protection(true);
977    }
978
979    /// Check if the interrupt is set.
980    pub fn is_interrupt_set(&self) -> bool {
981        let rtc_cntl = LP_WDT::regs();
982
983        rtc_cntl.int_st().read().wdt().bit_is_set()
984    }
985
986    /// Feed the watchdog timer.
987    pub fn feed(&mut self) {
988        let rtc_cntl = LP_WDT::regs();
989
990        self.set_write_protection(false);
991        rtc_cntl.wdtfeed().write(|w| w.wdt_feed().set_bit());
992        self.set_write_protection(true);
993    }
994
995    fn set_write_protection(&mut self, enable: bool) {
996        let rtc_cntl = LP_WDT::regs();
997
998        let wkey = if enable { 0u32 } else { 0x50D8_3AA1 };
999
1000        rtc_cntl.wdtwprotect().write(|w| unsafe { w.bits(wkey) });
1001    }
1002
1003    fn set_enabled(&mut self, enable: bool) {
1004        let rtc_cntl = LP_WDT::regs();
1005
1006        self.set_write_protection(false);
1007
1008        if !enable {
1009            rtc_cntl.wdtconfig0().modify(|_, w| unsafe { w.bits(0) });
1010        } else {
1011            rtc_cntl
1012                .wdtconfig0()
1013                .write(|w| w.wdt_flashboot_mod_en().bit(false));
1014
1015            rtc_cntl
1016                .wdtconfig0()
1017                .modify(|_, w| w.wdt_en().bit(enable).wdt_pause_in_slp().bit(enable));
1018
1019            // Apply default settings for WDT
1020            unsafe {
1021                rtc_cntl.wdtconfig0().modify(|_, w| {
1022                    w.wdt_stg0()
1023                        .bits(RwdtStageAction::ResetSystem as u8)
1024                        .wdt_cpu_reset_length()
1025                        .bits(7)
1026                        .wdt_sys_reset_length()
1027                        .bits(7)
1028                        .wdt_stg1()
1029                        .bits(RwdtStageAction::Off as u8)
1030                        .wdt_stg2()
1031                        .bits(RwdtStageAction::Off as u8)
1032                        .wdt_stg3()
1033                        .bits(RwdtStageAction::Off as u8)
1034                        .wdt_en()
1035                        .set_bit()
1036                });
1037            }
1038        }
1039
1040        self.set_write_protection(true);
1041    }
1042
1043    /// Configure timeout value in ms for the selected stage.
1044    pub fn set_timeout(&mut self, stage: RwdtStage, timeout: Duration) {
1045        let rtc_cntl = LP_WDT::regs();
1046
1047        let timeout_raw = (timeout.as_millis() * (RtcClock::cycles_to_1ms() as u64)) as u32;
1048        self.set_write_protection(false);
1049
1050        unsafe {
1051            #[cfg(esp32)]
1052            match stage {
1053                RwdtStage::Stage0 => rtc_cntl
1054                    .wdtconfig1()
1055                    .modify(|_, w| w.wdt_stg0_hold().bits(timeout_raw)),
1056                RwdtStage::Stage1 => rtc_cntl
1057                    .wdtconfig2()
1058                    .modify(|_, w| w.wdt_stg1_hold().bits(timeout_raw)),
1059                RwdtStage::Stage2 => rtc_cntl
1060                    .wdtconfig3()
1061                    .modify(|_, w| w.wdt_stg2_hold().bits(timeout_raw)),
1062                RwdtStage::Stage3 => rtc_cntl
1063                    .wdtconfig4()
1064                    .modify(|_, w| w.wdt_stg3_hold().bits(timeout_raw)),
1065            };
1066
1067            #[cfg(any(esp32c6, esp32h2))]
1068            match stage {
1069                RwdtStage::Stage0 => rtc_cntl.config1().modify(|_, w| {
1070                    w.wdt_stg0_hold()
1071                        .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier()))
1072                }),
1073                RwdtStage::Stage1 => rtc_cntl.config2().modify(|_, w| {
1074                    w.wdt_stg1_hold()
1075                        .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier()))
1076                }),
1077                RwdtStage::Stage2 => rtc_cntl.config3().modify(|_, w| {
1078                    w.wdt_stg2_hold()
1079                        .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier()))
1080                }),
1081                RwdtStage::Stage3 => rtc_cntl.config4().modify(|_, w| {
1082                    w.wdt_stg3_hold()
1083                        .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier()))
1084                }),
1085            };
1086
1087            #[cfg(not(any(esp32, esp32c6, esp32h2)))]
1088            match stage {
1089                RwdtStage::Stage0 => rtc_cntl.wdtconfig1().modify(|_, w| {
1090                    w.wdt_stg0_hold()
1091                        .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier()))
1092                }),
1093                RwdtStage::Stage1 => rtc_cntl.wdtconfig2().modify(|_, w| {
1094                    w.wdt_stg1_hold()
1095                        .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier()))
1096                }),
1097                RwdtStage::Stage2 => rtc_cntl.wdtconfig3().modify(|_, w| {
1098                    w.wdt_stg2_hold()
1099                        .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier()))
1100                }),
1101                RwdtStage::Stage3 => rtc_cntl.wdtconfig4().modify(|_, w| {
1102                    w.wdt_stg3_hold()
1103                        .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier()))
1104                }),
1105            };
1106        }
1107
1108        self.set_write_protection(true);
1109    }
1110
1111    /// Set the action for a specific stage.
1112    pub fn set_stage_action(&mut self, stage: RwdtStage, action: RwdtStageAction) {
1113        let rtc_cntl = LP_WDT::regs();
1114
1115        self.set_write_protection(false);
1116
1117        match stage {
1118            RwdtStage::Stage0 => rtc_cntl
1119                .wdtconfig0()
1120                .modify(|_, w| unsafe { w.wdt_stg0().bits(action as u8) }),
1121            RwdtStage::Stage1 => rtc_cntl
1122                .wdtconfig0()
1123                .modify(|_, w| unsafe { w.wdt_stg1().bits(action as u8) }),
1124            RwdtStage::Stage2 => rtc_cntl
1125                .wdtconfig0()
1126                .modify(|_, w| unsafe { w.wdt_stg2().bits(action as u8) }),
1127            RwdtStage::Stage3 => rtc_cntl
1128                .wdtconfig0()
1129                .modify(|_, w| unsafe { w.wdt_stg3().bits(action as u8) }),
1130        };
1131
1132        self.set_write_protection(true);
1133    }
1134}
1135
1136#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
1137/// Super Watchdog
1138pub struct Swd;
1139
1140#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
1141/// Super Watchdog driver
1142impl Swd {
1143    /// Create a new super watchdog timer instance
1144    pub fn new() -> Self {
1145        Self
1146    }
1147
1148    /// Enable the watchdog timer instance
1149    pub fn enable(&mut self) {
1150        self.set_enabled(true);
1151    }
1152
1153    /// Disable the watchdog timer instance
1154    pub fn disable(&mut self) {
1155        self.set_enabled(false);
1156    }
1157
1158    /// Enable/disable write protection for WDT registers
1159    fn set_write_protection(&mut self, enable: bool) {
1160        let rtc_cntl = LP_WDT::regs();
1161
1162        #[cfg(not(any(esp32c6, esp32h2)))]
1163        let wkey = if enable { 0u32 } else { 0x8F1D_312A };
1164        #[cfg(any(esp32c6, esp32h2))]
1165        let wkey = if enable { 0u32 } else { 0x50D8_3AA1 };
1166
1167        rtc_cntl
1168            .swd_wprotect()
1169            .write(|w| unsafe { w.swd_wkey().bits(wkey) });
1170    }
1171
1172    fn set_enabled(&mut self, enable: bool) {
1173        let rtc_cntl = LP_WDT::regs();
1174
1175        self.set_write_protection(false);
1176        rtc_cntl
1177            .swd_conf()
1178            .write(|w| w.swd_auto_feed_en().bit(!enable));
1179        self.set_write_protection(true);
1180    }
1181}
1182
1183#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
1184impl Default for Swd {
1185    fn default() -> Self {
1186        Self::new()
1187    }
1188}
1189
1190/// Return reset reason.
1191pub fn reset_reason(cpu: Cpu) -> Option<SocResetReason> {
1192    let reason = crate::rom::rtc_get_reset_reason(cpu as u32);
1193
1194    SocResetReason::from_repr(reason as usize)
1195}
1196
1197/// Return wakeup reason.
1198pub fn wakeup_cause() -> SleepSource {
1199    if reset_reason(Cpu::ProCpu) != Some(SocResetReason::CoreDeepSleep) {
1200        return SleepSource::Undefined;
1201    }
1202
1203    #[cfg(any(esp32c6, esp32h2))]
1204    let wakeup_cause = WakeupReason::from_bits_retain(
1205        crate::peripherals::PMU::regs()
1206            .slp_wakeup_status0()
1207            .read()
1208            .wakeup_cause()
1209            .bits(),
1210    );
1211    #[cfg(not(any(esp32, esp32c6, esp32h2)))]
1212    let wakeup_cause = WakeupReason::from_bits_retain(
1213        LPWR::regs().slp_wakeup_cause().read().wakeup_cause().bits(),
1214    );
1215    #[cfg(esp32)]
1216    let wakeup_cause = WakeupReason::from_bits_retain(
1217        LPWR::regs().wakeup_state().read().wakeup_cause().bits() as u32,
1218    );
1219
1220    if wakeup_cause.contains(WakeupReason::TimerTrigEn) {
1221        return SleepSource::Timer;
1222    }
1223    if wakeup_cause.contains(WakeupReason::GpioTrigEn) {
1224        return SleepSource::Gpio;
1225    }
1226    if wakeup_cause.intersects(WakeupReason::Uart0TrigEn | WakeupReason::Uart1TrigEn) {
1227        return SleepSource::Uart;
1228    }
1229
1230    #[cfg(pm_support_ext0_wakeup)]
1231    if wakeup_cause.contains(WakeupReason::ExtEvent0Trig) {
1232        return SleepSource::Ext0;
1233    }
1234    #[cfg(pm_support_ext1_wakeup)]
1235    if wakeup_cause.contains(WakeupReason::ExtEvent1Trig) {
1236        return SleepSource::Ext1;
1237    }
1238
1239    #[cfg(pm_support_touch_sensor_wakeup)]
1240    if wakeup_cause.contains(WakeupReason::TouchTrigEn) {
1241        return SleepSource::TouchPad;
1242    }
1243
1244    #[cfg(ulp_supported)]
1245    if wakeup_cause.contains(WakeupReason::UlpTrigEn) {
1246        return SleepSource::Ulp;
1247    }
1248
1249    #[cfg(pm_support_wifi_wakeup)]
1250    if wakeup_cause.contains(WakeupReason::WifiTrigEn) {
1251        return SleepSource::Wifi;
1252    }
1253
1254    #[cfg(pm_support_bt_wakeup)]
1255    if wakeup_cause.contains(WakeupReason::BtTrigEn) {
1256        return SleepSource::BT;
1257    }
1258
1259    #[cfg(riscv_coproc_supported)]
1260    if wakeup_cause.contains(WakeupReason::CocpuTrigEn) {
1261        return SleepSource::Ulp;
1262    } else if wakeup_cause.contains(WakeupReason::CocpuTrapTrigEn) {
1263        return SleepSource::CocpuTrapTrig;
1264    }
1265
1266    SleepSource::Undefined
1267}
1268
1269// libphy.a can pull this in on some chips, we provide it here in the hal
1270// so that either ieee or esp-wifi gets it for free without duplicating in both
1271#[no_mangle]
1272extern "C" fn rtc_clk_xtal_freq_get() -> i32 {
1273    let xtal = RtcClock::xtal_freq();
1274    xtal.mhz() as i32
1275}