1#![doc = crate::before_snippet!()]
25#![doc = crate::before_snippet!()]
46#![doc = crate::before_snippet!()]
97pub 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#[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 const ExtEvent0Trig = 1 << 0;
166 #[cfg(pm_support_ext1_wakeup)]
167 const ExtEvent1Trig = 1 << 1;
169 const GpioTrigEn = 1 << 2;
171 #[cfg(not(any(esp32c6, esp32h2)))]
172 const TimerTrigEn = 1 << 3;
174 #[cfg(any(esp32c6, esp32h2))]
175 const TimerTrigEn = 1 << 4;
177 #[cfg(pm_support_wifi_wakeup)]
178 const WifiTrigEn = 1 << 5;
180 const Uart0TrigEn = 1 << 6;
182 const Uart1TrigEn = 1 << 7;
184 #[cfg(pm_support_touch_sensor_wakeup)]
185 const TouchTrigEn = 1 << 8;
187 #[cfg(ulp_supported)]
188 const UlpTrigEn = 1 << 9;
190 #[cfg(pm_support_bt_wakeup)]
191 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)] pub(crate) enum RtcFastClock {
207 RtcFastClockXtalD4 = 0,
209 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)] pub enum RtcSlowClock {
233 RtcSlowClockRtc = 0,
235 RtcSlowClock32kXtal = 1,
237 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)] pub(crate) enum RtcCalSel {
267 RtcCalRtcMux = 0,
269 RtcCal8mD256 = 1,
271 RtcCal32kXtal = 2,
273 #[cfg(not(esp32))]
274 RtcCalInternalOsc = 3,
276}
277
278pub struct Rtc<'d> {
280 _inner: crate::peripherals::LPWR<'d>,
281 pub rwdt: Rwdt,
283 #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
284 pub swd: Swd,
286}
287
288impl<'d> Rtc<'d> {
289 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 pub fn estimate_xtal_frequency(&mut self) -> u32 {
311 RtcClock::estimate_xtal_frequency()
312 }
313
314 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 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 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 fn boot_time_us(&self) -> u64 {
360 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 l + (h << 32)
384 }
385
386 fn set_boot_time_us(&self, boot_time_us: u64) {
388 let rtc_cntl = LP_AON::regs();
392
393 let (l, h) = (rtc_cntl.store2(), rtc_cntl.store3());
394
395 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 #[doc = crate::before_snippet!()]
410 pub fn current_time_us(&self) -> u64 {
424 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 if rtc_time_us > wrapped_boot_time_us {
433 rtc_time_us - wrapped_boot_time_us
435 } else {
436 boot_time_us + rtc_time_us
437 }
438 }
439
440 pub fn set_current_time_us(&self, current_time_us: u64) {
442 let rtc_time_us = self.time_since_boot().as_micros();
446 if current_time_us < rtc_time_us {
447 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 #[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 #[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 #[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 #[cfg(any(esp32s3, esp32h2))]
497 pub fn disable_rom_message_printing(&self) {
498 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 #[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
537pub struct RtcClock;
539
540impl RtcClock {
542 const CAL_FRACT: u32 = 19;
543
544 #[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 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 #[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 #[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 #[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 .dig_xtal32k_en()
640 .bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kXtal))
641 .ck8m_force_pu()
644 .bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock8mD256))
645 });
646 };
647
648 crate::rom::ets_delay_us(300u32);
649 }
650
651 #[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 #[cfg(not(any(esp32c6, esp32h2)))]
669 fn calibrate_internal(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
670 #[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 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 #[cfg(not(esp32))]
705 if timg0
706 .rtccalicfg()
707 .read()
708 .rtc_cali_start_cycling()
709 .bit_is_set()
710 {
711 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 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 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 timg0
763 .rtccalicfg()
764 .modify(|_, w| w.rtc_cali_start().clear_bit().rtc_cali_start().set_bit());
765
766 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 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 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 #[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 #[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 #[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 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 #[cfg(not(any(esp32c6, esp32h2)))]
856 pub(crate) fn estimate_xtal_frequency() -> u32 {
857 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#[allow(unused)]
881#[derive(Debug, Clone, Copy)]
882pub enum RwdtStageAction {
883 Off = 0,
885 Interrupt = 1,
887 ResetCpu = 2,
889 ResetCore = 3,
892 ResetSystem = 4,
894}
895
896#[derive(Debug, Clone, Copy)]
901pub enum RwdtStage {
902 Stage0,
904 Stage1,
906 Stage2,
908 Stage3,
910}
911
912pub struct Rwdt;
914
915impl Default for Rwdt {
916 fn default() -> Self {
917 Self::new()
918 }
919}
920
921impl Rwdt {
923 pub fn new() -> Self {
925 Self
926 }
927
928 pub fn enable(&mut self) {
932 self.set_enabled(true);
933 }
934
935 pub fn disable(&mut self) {
937 self.set_enabled(false);
938 }
939
940 pub fn listen(&mut self) {
942 let rtc_cntl = LP_WDT::regs();
943
944 self.set_write_protection(false);
945
946 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 pub fn unlisten(&mut self) {
958 let rtc_cntl = LP_WDT::regs();
959
960 self.set_write_protection(false);
961
962 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 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 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 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 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 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 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))]
1141pub struct Swd;
1143
1144#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
1145impl Swd {
1147 pub fn new() -> Self {
1149 Self
1150 }
1151
1152 pub fn enable(&mut self) {
1154 self.set_enabled(true);
1155 }
1156
1157 pub fn disable(&mut self) {
1159 self.set_enabled(false);
1160 }
1161
1162 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
1194pub 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
1201pub 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#[unsafe(no_mangle)]
1276extern "C" fn rtc_clk_xtal_freq_get() -> i32 {
1277 let xtal = RtcClock::xtal_freq();
1278 xtal.mhz() as i32
1279}