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