1#![doc = crate::before_snippet!()]
25#![doc = crate::before_snippet!()]
46#![doc = crate::before_snippet!()]
97use 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#[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 const ExtEvent0Trig = 1 << 0;
169 #[cfg(pm_support_ext1_wakeup)]
170 const ExtEvent1Trig = 1 << 1;
172 const GpioTrigEn = 1 << 2;
174 #[cfg(not(any(esp32c6, esp32h2)))]
175 const TimerTrigEn = 1 << 3;
177 #[cfg(any(esp32c6, esp32h2))]
178 const TimerTrigEn = 1 << 4;
180 #[cfg(pm_support_wifi_wakeup)]
181 const WifiTrigEn = 1 << 5;
183 const Uart0TrigEn = 1 << 6;
185 const Uart1TrigEn = 1 << 7;
187 #[cfg(pm_support_touch_sensor_wakeup)]
188 const TouchTrigEn = 1 << 8;
190 #[cfg(ulp_supported)]
191 const UlpTrigEn = 1 << 9;
193 #[cfg(pm_support_bt_wakeup)]
194 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)] pub(crate) enum RtcFastClock {
210 RtcFastClockXtalD4 = 0,
212 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)] pub enum RtcSlowClock {
236 RtcSlowClockRtc = 0,
238 RtcSlowClock32kXtal = 1,
240 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)] pub(crate) enum RtcCalSel {
270 RtcCalRtcMux = 0,
272 RtcCal8mD256 = 1,
274 RtcCal32kXtal = 2,
276 #[cfg(not(esp32))]
277 RtcCalInternalOsc = 3,
279}
280
281pub struct Rtc<'d> {
283 _inner: PeripheralRef<'d, crate::peripherals::LPWR>,
284 pub rwdt: Rwdt,
286 #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
287 pub swd: Swd,
289}
290
291impl<'d> Rtc<'d> {
292 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 pub fn estimate_xtal_frequency(&mut self) -> u32 {
314 RtcClock::estimate_xtal_frequency()
315 }
316
317 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 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 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 fn boot_time_us(&self) -> u64 {
363 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 l + (h << 32)
387 }
388
389 fn set_boot_time_us(&self, boot_time_us: u64) {
391 let rtc_cntl = LP_AON::regs();
395
396 let (l, h) = (rtc_cntl.store2(), rtc_cntl.store3());
397
398 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 pub fn current_time(&self) -> NaiveDateTime {
405 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 let current_time_us = if rtc_time_us > wrapped_boot_time_us {
414 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 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 let rtc_time_us = self.time_since_boot().as_micros();
442 if current_time_us < rtc_time_us {
443 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 #[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 #[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 #[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 #[cfg(any(esp32s3, esp32h2))]
493 pub fn disable_rom_message_printing(&self) {
494 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 #[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
533pub struct RtcClock;
535
536impl RtcClock {
538 const CAL_FRACT: u32 = 19;
539
540 #[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 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 #[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 #[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 #[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 .dig_xtal32k_en()
636 .bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kXtal))
637 .ck8m_force_pu()
640 .bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock8mD256))
641 });
642 };
643
644 crate::rom::ets_delay_us(300u32);
645 }
646
647 #[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 #[cfg(not(any(esp32c6, esp32h2)))]
665 fn calibrate_internal(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
666 #[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 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 #[cfg(not(esp32))]
701 if timg0
702 .rtccalicfg()
703 .read()
704 .rtc_cali_start_cycling()
705 .bit_is_set()
706 {
707 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 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 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 timg0
759 .rtccalicfg()
760 .modify(|_, w| w.rtc_cali_start().clear_bit().rtc_cali_start().set_bit());
761
762 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 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 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 #[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 #[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 #[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 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 #[cfg(not(any(esp32c6, esp32h2)))]
852 pub(crate) fn estimate_xtal_frequency() -> u32 {
853 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#[allow(unused)]
877#[derive(Debug, Clone, Copy)]
878pub enum RwdtStageAction {
879 Off = 0,
881 Interrupt = 1,
883 ResetCpu = 2,
885 ResetCore = 3,
888 ResetSystem = 4,
890}
891
892#[derive(Debug, Clone, Copy)]
897pub enum RwdtStage {
898 Stage0,
900 Stage1,
902 Stage2,
904 Stage3,
906}
907
908pub struct Rwdt;
910
911impl Default for Rwdt {
912 fn default() -> Self {
913 Self::new()
914 }
915}
916
917impl Rwdt {
919 pub fn new() -> Self {
921 Self
922 }
923
924 pub fn enable(&mut self) {
928 self.set_enabled(true);
929 }
930
931 pub fn disable(&mut self) {
933 self.set_enabled(false);
934 }
935
936 pub fn listen(&mut self) {
938 let rtc_cntl = LP_WDT::regs();
939
940 self.set_write_protection(false);
941
942 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 pub fn unlisten(&mut self) {
954 let rtc_cntl = LP_WDT::regs();
955
956 self.set_write_protection(false);
957
958 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 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 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 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 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 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 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))]
1137pub struct Swd;
1139
1140#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
1141impl Swd {
1143 pub fn new() -> Self {
1145 Self
1146 }
1147
1148 pub fn enable(&mut self) {
1150 self.set_enabled(true);
1151 }
1152
1153 pub fn disable(&mut self) {
1155 self.set_enabled(false);
1156 }
1157
1158 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
1190pub 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
1197pub 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#[no_mangle]
1272extern "C" fn rtc_clk_xtal_freq_get() -> i32 {
1273 let xtal = RtcClock::xtal_freq();
1274 xtal.mhz() as i32
1275}