More clock refactor (#3993)

* Remove duplicate constants

* Metadata-ify some clock frequencies

* Changelog
This commit is contained in:
Dániel Buga 2025-08-27 10:50:34 +02:00 committed by GitHub
parent e6cdd8eb3c
commit e42f7d2e06
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 524 additions and 836 deletions

View File

@ -47,6 +47,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `ShaDigest::finish` has been reimplemented to be properly non-blocking (#3948)
- Replace Timer's `pub fn enable_interrupt(&mut self, enable: bool)` with `pub fn listen(&mut self)` and `pub fn unlisten(&mut self)` (#3933)
- ESP32-S3: `PsramConfig::core_clock` is now an `Option` (#3974)
- `RtcSlowClock::RtcFastClock8m` has been renamed to `RtcFastClock::RtcFastClockRcFast` (#3993)
- `RtcSlowClock::RtcSlowClockRtc` has been renamed to `RtcSlowClock::RtcSlowClockRcSlow` (#3993)
### Fixed

View File

@ -120,12 +120,10 @@ use crate::rtc_cntl::sleep::{RtcSleepConfig, WakeSource, WakeTriggers};
use crate::{
clock::{Clock, XtalClock},
interrupt::{self, InterruptHandler},
peripherals::{Interrupt, TIMG0},
peripherals::{Interrupt, LPWR, TIMG0},
system::{Cpu, SleepSource},
time::Duration,
time::{Duration, Rate},
};
#[cfg(not(any(esp32c6, esp32h2)))]
use crate::{peripherals::LPWR, time::Rate};
// only include sleep where it's been implemented
#[cfg(any(esp32, esp32s2, esp32s3, esp32c3, esp32c6, esp32c2))]
pub mod sleep;
@ -144,8 +142,6 @@ cfg_if::cfg_if! {
use crate::peripherals::LP_WDT;
use crate::peripherals::LP_TIMER;
use crate::peripherals::LP_AON;
use rtc::{RtcSlowClock, RtcCalSel}; // TODO: bring the types into this module
} else {
use crate::peripherals::LPWR as LP_WDT;
use crate::peripherals::LPWR as LP_TIMER;
@ -194,28 +190,35 @@ bitflags::bitflags! {
}
}
#[cfg(not(any(esp32c6, esp32h2)))]
#[allow(unused)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[allow(clippy::enum_variant_names)] // FIXME: resolve this
/// RTC SLOW_CLK frequency values
/// RTC FAST_CLK frequency values
pub(crate) enum RtcFastClock {
/// Main XTAL, divided by 4
RtcFastClockXtalD4 = 0,
#[cfg(not(any(esp32c6, esp32h2)))]
#[expect(unused)]
RtcFastClockXtalD4,
/// Select XTAL_D2_CLK as RTC_FAST_CLK source
#[cfg(any(esp32c6, esp32h2))]
#[expect(unused)]
RtcFastClockXtalD2,
/// Internal fast RC oscillator
RtcFastClock8m = 1,
RtcFastClockRcFast,
}
#[cfg(not(any(esp32c6, esp32h2)))]
impl Clock for RtcFastClock {
fn frequency(&self) -> Rate {
match self {
#[cfg(not(any(esp32c6, esp32h2)))]
RtcFastClock::RtcFastClockXtalD4 => Rate::from_hz(40_000_000 / 4),
#[cfg(any(esp32, esp32s2))]
RtcFastClock::RtcFastClock8m => Rate::from_hz(8_500_000),
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
RtcFastClock::RtcFastClock8m => Rate::from_hz(17_500_000),
#[cfg(any(esp32c6, esp32h2))]
RtcFastClock::RtcFastClockXtalD2 => Rate::from_hz(property!("soc.xtal_frequency") / 2),
RtcFastClock::RtcFastClockRcFast => Rate::from_hz(property!("soc.rc_fast_clk_default")),
}
}
}
@ -228,28 +231,44 @@ impl Clock for RtcFastClock {
/// RTC SLOW_CLK frequency values
pub enum RtcSlowClock {
/// Internal slow RC oscillator
RtcSlowClockRtc = 0,
RtcSlowClockRcSlow = 0,
/// External 32 KHz XTAL
RtcSlowClock32kXtal = 1,
/// Internal fast RC oscillator, divided by 256
RtcSlowClock8mD256 = 2,
}
#[cfg(not(any(esp32c6, esp32h2)))]
/// RTC SLOW_CLK frequency values
#[allow(clippy::enum_variant_names)]
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
#[cfg(any(esp32c6, esp32h2))]
pub enum RtcSlowClock {
/// Select RC_SLOW_CLK as RTC_SLOW_CLK source
RtcSlowClockRcSlow = 0,
/// Select XTAL32K_CLK as RTC_SLOW_CLK source
RtcSlowClock32kXtal = 1,
/// Select RC32K_CLK as RTC_SLOW_CLK source
RtcSlowClock32kRc = 2,
/// Select OSC_SLOW_CLK (external slow clock) as RTC_SLOW_CLK source
RtcSlowOscSlow = 3,
}
impl Clock for RtcSlowClock {
fn frequency(&self) -> Rate {
match self {
#[cfg(esp32)]
RtcSlowClock::RtcSlowClockRtc => Rate::from_hz(150_000),
#[cfg(esp32s2)]
RtcSlowClock::RtcSlowClockRtc => Rate::from_hz(90_000),
#[cfg(any(esp32c2, esp32c3, esp32s3))]
RtcSlowClock::RtcSlowClockRtc => Rate::from_hz(136_000),
RtcSlowClock::RtcSlowClockRcSlow => Rate::from_hz(property!("soc.rc_slow_clock")),
RtcSlowClock::RtcSlowClock32kXtal => Rate::from_hz(32_768),
#[cfg(any(esp32, esp32s2))]
RtcSlowClock::RtcSlowClock8mD256 => Rate::from_hz(8_500_000 / 256),
#[cfg(any(esp32c2, esp32c3, esp32s3))]
RtcSlowClock::RtcSlowClock8mD256 => Rate::from_hz(17_500_000 / 256),
#[cfg(not(any(esp32c6, esp32h2)))]
RtcSlowClock::RtcSlowClock8mD256 => RtcFastClock::RtcFastClockRcFast.frequency() / 256,
#[cfg(any(esp32c6, esp32h2))]
RtcSlowClock::RtcSlowClock32kRc => Rate::from_hz(32_768),
#[cfg(any(esp32c6, esp32h2))]
RtcSlowClock::RtcSlowOscSlow => Rate::from_hz(32_768),
}
}
}
@ -272,6 +291,25 @@ pub(crate) enum RtcCalSel {
RtcCalInternalOsc = 3,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg(any(esp32c6, esp32h2))]
/// Clock source to be calibrated using rtc_clk_cal function
pub(crate) enum RtcCalSel {
/// Currently selected RTC SLOW_CLK
RtcCalRtcMux = -1,
/// Internal 150kHz RC oscillator
RtcCalRcSlow = 0,
/// External 32kHz XTAL, as one type of 32k clock
RtcCal32kXtal = 1,
/// Internal 32kHz RC oscillator, as one type of 32k clock
RtcCal32kRc = 2,
/// External slow clock signal input by lp_pad_gpio0, as one type of 32k
/// clock
RtcCal32kOscSlow = 3,
/// Internal MHz-range RC oscillator
RtcCalRcFast,
}
/// Low-power Management
pub struct Rtc<'d> {
_inner: crate::peripherals::LPWR<'d>,
@ -537,7 +575,8 @@ impl crate::interrupt::InterruptConfigurable for Rtc<'_> {
}
}
/// RTC Watchdog Timer.
/// Clocks.
// TODO: this type belongs in `esp_hal::clock`.
pub struct RtcClock;
/// RTC Watchdog Timer driver.
@ -588,7 +627,7 @@ impl RtcClock {
#[cfg(not(any(esp32c6, esp32h2)))]
pub fn slow_freq() -> RtcSlowClock {
match LPWR::regs().clk_conf().read().ana_clk_rtc_sel().bits() {
0 => RtcSlowClock::RtcSlowClockRtc,
0 => RtcSlowClock::RtcSlowClockRcSlow,
1 => RtcSlowClock::RtcSlowClock32kXtal,
2 => RtcSlowClock::RtcSlowClock8mD256,
_ => unreachable!(),
@ -623,7 +662,7 @@ impl RtcClock {
fn set_fast_freq(fast_freq: RtcFastClock) {
LPWR::regs().clk_conf().modify(|_, w| {
w.fast_clk_rtc_sel().bit(match fast_freq {
RtcFastClock::RtcFastClock8m => true,
RtcFastClock::RtcFastClockRcFast => true,
RtcFastClock::RtcFastClockXtalD4 => false,
})
});
@ -631,6 +670,56 @@ impl RtcClock {
crate::rom::ets_delay_us(3u32);
}
// TODO: IDF-5781 Some of esp32c6 SOC_RTC_FAST_CLK_SRC_XTAL_D2 rtc_fast clock
// has timing issue. Force to use SOC_RTC_FAST_CLK_SRC_RC_FAST since 2nd
// stage bootloader https://github.com/espressif/esp-idf/blob/master/components/bootloader_support/src/bootloader_clock_init.c#L65-L67
#[cfg(any(esp32h2, esp32c6))]
fn set_fast_freq(fast_freq: RtcFastClock) {
#[cfg(esp32h2)]
LPWR::regs().lp_clk_conf().modify(|_, w| unsafe {
w.fast_clk_sel().bits(match fast_freq {
RtcFastClock::RtcFastClockRcFast => 0b00,
RtcFastClock::RtcFastClockXtalD2 => 0b01,
})
});
#[cfg(esp32c6)]
LPWR::regs().lp_clk_conf().modify(|_, w| {
w.fast_clk_sel().bit(match fast_freq {
RtcFastClock::RtcFastClockRcFast => false,
RtcFastClock::RtcFastClockXtalD2 => true,
})
});
crate::rom::ets_delay_us(3);
}
#[cfg(any(esp32h2, esp32c6))]
fn set_slow_freq(slow_freq: RtcSlowClock) {
LPWR::regs()
.lp_clk_conf()
.modify(|_, w| unsafe { w.slow_clk_sel().bits(slow_freq as u8) });
LPWR::regs().clk_to_hp().modify(|_, w| {
w.icg_hp_xtal32k()
.bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kXtal));
w.icg_hp_osc32k()
.bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kRc))
});
}
/// Get the RTC_SLOW_CLK source
#[cfg(any(esp32h2, esp32c6))]
pub fn slow_freq() -> RtcSlowClock {
match LPWR::regs().lp_clk_conf().read().slow_clk_sel().bits() {
0 => RtcSlowClock::RtcSlowClockRcSlow,
1 => RtcSlowClock::RtcSlowClock32kXtal,
2 => RtcSlowClock::RtcSlowClock32kRc,
3 => RtcSlowClock::RtcSlowOscSlow,
_ => unreachable!(),
}
}
/// Calibration of RTC_SLOW_CLK is performed using a special feature of
/// TIMG0. This feature counts the number of XTAL clock cycles within a
/// given number of RTC_SLOW_CLK cycles.
@ -719,7 +808,7 @@ impl RtcClock {
timg0.rtccalicfg2().modify(|_, w| unsafe {
w.rtc_cali_timeout_thres().bits(slowclk_cycles << 10)
});
RtcSlowClock::RtcSlowClockRtc
RtcSlowClock::RtcSlowClockRcSlow
}
};
@ -768,6 +857,290 @@ impl RtcClock {
cal_val
}
/// Calibration of RTC_SLOW_CLK is performed using a special feature of
/// TIMG0. This feature counts the number of XTAL clock cycles within a
/// given number of RTC_SLOW_CLK cycles.
#[cfg(any(esp32c6, esp32h2))]
pub(crate) fn calibrate_internal(mut cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
use crate::peripherals::{LP_CLKRST, PCR, PMU};
#[derive(Clone, Copy)]
enum RtcCaliClkSel {
CaliClkRcSlow = 0,
CaliClkRcFast = 1,
CaliClk32k = 2,
}
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match cal_clk {
RtcCalSel::RtcCalRtcMux => match RtcClock::slow_freq() {
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
_ => cal_clk,
},
RtcCalSel::RtcCal32kOscSlow => RtcCalSel::RtcCalRtcMux,
_ => cal_clk,
};
}
let clk_src = RtcClock::slow_freq();
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match clk_src {
RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCal32kOscSlow,
};
}
let cali_clk_sel;
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match clk_src {
RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCalRcSlow,
}
}
if cal_clk == RtcCalSel::RtcCalRcFast {
cali_clk_sel = RtcCaliClkSel::CaliClkRcFast;
} else if cal_clk == RtcCalSel::RtcCalRcSlow {
cali_clk_sel = RtcCaliClkSel::CaliClkRcSlow;
} else {
cali_clk_sel = RtcCaliClkSel::CaliClk32k;
match cal_clk {
RtcCalSel::RtcCalRtcMux | RtcCalSel::RtcCalRcSlow | RtcCalSel::RtcCalRcFast => {}
RtcCalSel::RtcCal32kRc => {
PCR::regs()
.ctrl_32k_conf()
.modify(|_, w| unsafe { w.clk_32k_sel().bits(0) });
}
RtcCalSel::RtcCal32kXtal => {
PCR::regs()
.ctrl_32k_conf()
.modify(|_, w| unsafe { w.clk_32k_sel().bits(1) });
}
RtcCalSel::RtcCal32kOscSlow => {
PCR::regs()
.ctrl_32k_conf()
.modify(|_, w| unsafe { w.clk_32k_sel().bits(2) });
}
}
}
// Enable requested clock (150k is always on)
// Some delay is required before the time is stable
// Only enable if originaly was disabled
// If clock is already on, do nothing
let dig_32k_xtal_enabled = LP_CLKRST::regs()
.clk_to_hp()
.read()
.icg_hp_xtal32k()
.bit_is_set();
if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_xtal32k().set_bit());
}
// TODO: very hacky - icg_hp_xtal32k is already set in the above condition?
// in ESP-IDF these are not called in this function but the fields are set
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_xtal32k().set_bit());
PMU::regs().hp_sleep_lp_ck_power().modify(|_, w| {
w.hp_sleep_xpd_xtal32k().set_bit();
w.hp_sleep_xpd_rc32k().set_bit()
});
let rc_fast_enabled = PMU::regs()
.hp_sleep_lp_ck_power()
.read()
.hp_sleep_xpd_fosc_clk()
.bit_is_set();
let dig_rc_fast_enabled = LP_CLKRST::regs()
.clk_to_hp()
.read()
.icg_hp_fosc()
.bit_is_set();
if cal_clk == RtcCalSel::RtcCalRcFast {
if !rc_fast_enabled {
PMU::regs()
.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
crate::rom::ets_delay_us(50);
}
if !dig_rc_fast_enabled {
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_fosc().set_bit());
crate::rom::ets_delay_us(5);
}
}
let rc32k_enabled = PMU::regs()
.hp_sleep_lp_ck_power()
.read()
.hp_sleep_xpd_rc32k()
.bit_is_set();
let dig_rc32k_enabled = LP_CLKRST::regs()
.clk_to_hp()
.read()
.icg_hp_osc32k()
.bit_is_set();
if cal_clk == RtcCalSel::RtcCal32kRc {
if !rc32k_enabled {
PMU::regs()
.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
crate::rom::ets_delay_us(300);
}
if !dig_rc32k_enabled {
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_osc32k().set_bit());
}
}
// Check if there is already running calibration process
// TODO: &mut TIMG0 for calibration
let timg0 = TIMG0::regs();
if timg0
.rtccalicfg()
.read()
.rtc_cali_start_cycling()
.bit_is_set()
{
timg0
.rtccalicfg2()
.modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(1) });
// Set small timeout threshold to accelerate the generation of timeot
// Internal circuit will be reset when timeout occurs and will not affect the
// next calibration
while !timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_set()
&& !timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_set()
{}
}
// Prepare calibration
timg0
.rtccalicfg()
.modify(|_, w| unsafe { w.rtc_cali_clk_sel().bits(cali_clk_sel as u8) });
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start_cycling().clear_bit());
timg0
.rtccalicfg()
.modify(|_, w| unsafe { w.rtc_cali_max().bits(slowclk_cycles as u16) });
let expected_frequency = match cali_clk_sel {
RtcCaliClkSel::CaliClk32k => {
timg0.rtccalicfg2().modify(|_, w| unsafe {
w.rtc_cali_timeout_thres().bits(slowclk_cycles << 12)
});
RtcSlowClock::RtcSlowClock32kXtal.frequency()
}
RtcCaliClkSel::CaliClkRcFast => {
timg0
.rtccalicfg2()
.modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(0x01FFFFFF) });
RtcFastClock::RtcFastClockRcFast.frequency()
}
RtcCaliClkSel::CaliClkRcSlow => {
timg0.rtccalicfg2().modify(|_, w| unsafe {
w.rtc_cali_timeout_thres().bits(slowclk_cycles << 10)
});
RtcSlowClock::RtcSlowClockRcSlow.frequency()
}
};
let us_time_estimate = Rate::from_mhz(slowclk_cycles) / expected_frequency;
// Start calibration
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start().clear_bit());
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start().set_bit());
// Wait for calibration to finish up to another us_time_estimate
crate::rom::ets_delay_us(us_time_estimate);
let cal_val = loop {
if timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_set() {
// The Fosc CLK of calibration circuit is divided by 32 for ECO1.
// So we need to multiply the frequency of the Fosc for ECO1 and above chips by
// 32 times. And ensure that this modification will not affect
// ECO0.
// https://github.com/espressif/esp-idf/commit/e3148369f32fdc6de62c35a67f7adb6f4faef4e3
#[cfg(esp32c6)]
if Efuse::chip_revision() > 0 && cal_clk == RtcCalSel::RtcCalRcFast {
break timg0.rtccalicfg1().read().rtc_cali_value().bits() >> 5;
}
break timg0.rtccalicfg1().read().rtc_cali_value().bits();
}
if timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_set() {
// Timed out waiting for calibration
break 0;
}
};
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start().clear_bit());
if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_xtal32k().clear_bit());
}
if cal_clk == RtcCalSel::RtcCalRcFast {
if rc_fast_enabled {
PMU::regs()
.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
crate::rom::ets_delay_us(50);
}
if dig_rc_fast_enabled {
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_fosc().set_bit());
crate::rom::ets_delay_us(5);
}
}
if cal_clk == RtcCalSel::RtcCal32kRc {
if rc32k_enabled {
PMU::regs()
.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
crate::rom::ets_delay_us(300);
}
if dig_rc32k_enabled {
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_osc32k().set_bit());
}
}
cal_val
}
/// Measure RTC slow clock's period, based on main XTAL frequency
///
/// This function will time out and return 0 if the time for the given
@ -808,7 +1181,7 @@ impl RtcClock {
};
} else {
let calibration_clock = match RtcClock::slow_freq() {
RtcSlowClock::RtcSlowClockRtc => RtcCalSel::RtcCalRtcMux,
RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRtcMux,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock8mD256 => RtcCalSel::RtcCal8mD256,
};
@ -829,13 +1202,7 @@ impl RtcClock {
// TODO: this could reuse Self::calibrate_internal
const SLOW_CLOCK_CYCLES: u32 = 100;
cfg_if::cfg_if! {
if #[cfg(any(esp32h2, esp32c6))] {
let calibration_clock = rtc::RtcSlowClock::RtcSlowClockRcSlow;
} else {
let calibration_clock = RtcSlowClock::RtcSlowClockRtc;
}
}
let calibration_clock = RtcSlowClock::RtcSlowClockRcSlow;
// Make sure the process doesn't time out due to some spooky configuration.
#[cfg(not(esp32))]

View File

@ -8,10 +8,10 @@ use crate::{
pub(crate) fn init() {}
pub(crate) fn configure_clock() {
RtcClock::set_fast_freq(RtcFastClock::RtcFastClock8m);
RtcClock::set_fast_freq(RtcFastClock::RtcFastClockRcFast);
let cal_val = loop {
RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRtc);
RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRcSlow);
let res = RtcClock::calibrate(RtcCalSel::RtcCalRtcMux, 1024);
if res != 0 {

View File

@ -47,10 +47,10 @@ pub(crate) fn configure_clock() {
// esp_rom_delay_us(SOC_DELAY_RC_FAST_ENABLE);
crate::rom::ets_delay_us(50);
}
RtcClock::set_fast_freq(RtcFastClock::RtcFastClock8m);
RtcClock::set_fast_freq(RtcFastClock::RtcFastClockRcFast);
let cal_val = loop {
RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRtc);
RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRcSlow);
let res = RtcClock::calibrate(RtcCalSel::RtcCalRtcMux, 1024);
if res != 0 {

View File

@ -65,10 +65,10 @@ pub(crate) fn configure_clock() {
// esp_rom_delay_us(SOC_DELAY_RC_FAST_ENABLE);
crate::rom::ets_delay_us(50);
}
RtcClock::set_fast_freq(RtcFastClock::RtcFastClock8m);
RtcClock::set_fast_freq(RtcFastClock::RtcFastClockRcFast);
let cal_val = loop {
RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRtc);
RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRcSlow);
let res = RtcClock::calibrate(RtcCalSel::RtcCalRtcMux, 1024);
if res != 0 {

View File

@ -17,11 +17,9 @@ use crate::{
esp32c6_rtc_update_to_xtal_raw,
},
},
efuse::Efuse,
peripherals::{LP_AON, LP_CLKRST, MODEM_LPCON, MODEM_SYSCON, PCR, PMU, TIMG0},
rtc_cntl::RtcClock,
peripherals::{LP_AON, LP_CLKRST, MODEM_LPCON, MODEM_SYSCON, PCR, PMU},
rtc_cntl::{RtcCalSel, RtcClock, RtcFastClock, RtcSlowClock},
soc::regi2c,
time::Rate,
};
fn pmu_power_domain_force_default() {
@ -1186,398 +1184,6 @@ pub enum SocResetReason {
Cpu0JtagCpu = 0x18,
}
#[allow(unused)]
#[derive(Debug, Clone, Copy)]
/// RTC SLOW_CLK frequency values
pub(crate) enum RtcFastClock {
/// Select RC_FAST_CLK as RTC_FAST_CLK source
RtcFastClockRcFast = 0,
/// Select XTAL_D2_CLK as RTC_FAST_CLK source
RtcFastClockXtalD2 = 1,
}
impl Clock for RtcFastClock {
fn frequency(&self) -> Rate {
match self {
RtcFastClock::RtcFastClockXtalD2 => {
// TODO: Is the value correct?
Rate::from_hz(40_000_000 / 2)
}
RtcFastClock::RtcFastClockRcFast => Rate::from_hz(property!("soc.rc_fast_clk_default")),
}
}
}
#[allow(clippy::enum_variant_names)]
#[derive(Debug, Clone, Copy, PartialEq)]
/// RTC SLOW_CLK frequency values
pub enum RtcSlowClock {
/// Select RC_SLOW_CLK as RTC_SLOW_CLK source
RtcSlowClockRcSlow = 0,
/// Select XTAL32K_CLK as RTC_SLOW_CLK source
RtcSlowClock32kXtal = 1,
/// Select RC32K_CLK as RTC_SLOW_CLK source
RtcSlowClock32kRc = 2,
/// Select OSC_SLOW_CLK (external slow clock) as RTC_SLOW_CLK source
RtcSlowOscSlow = 3,
}
impl Clock for RtcSlowClock {
fn frequency(&self) -> Rate {
match self {
RtcSlowClock::RtcSlowClockRcSlow => Rate::from_hz(136_000),
RtcSlowClock::RtcSlowClock32kXtal => Rate::from_hz(32_768),
RtcSlowClock::RtcSlowClock32kRc => Rate::from_hz(32_768),
RtcSlowClock::RtcSlowOscSlow => Rate::from_hz(32_768),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
/// Clock source to be calibrated using rtc_clk_cal function
pub(crate) enum RtcCalSel {
/// Currently selected RTC SLOW_CLK
RtcCalRtcMux = -1,
/// Internal 150kHz RC oscillator
RtcCalRcSlow = 0,
/// External 32kHz XTAL, as one type of 32k clock
RtcCal32kXtal = 1,
/// Internal 32kHz RC oscillator, as one type of 32k clock
RtcCal32kRc = 2,
/// External slow clock signal input by lp_pad_gpio0, as one type of 32k
/// clock
RtcCal32kOscSlow = 3,
/// Internal 20MHz RC oscillator
RtcCalRcFast,
}
#[derive(Clone)]
pub(crate) enum RtcCaliClkSel {
CaliClkRcSlow = 0,
CaliClkRcFast = 1,
CaliClk32k = 2,
}
/// RTC Watchdog Timer driver
impl RtcClock {
/// Get the RTC_SLOW_CLK source
pub fn slow_freq() -> RtcSlowClock {
match LP_CLKRST::regs().lp_clk_conf().read().slow_clk_sel().bits() {
0 => RtcSlowClock::RtcSlowClockRcSlow,
1 => RtcSlowClock::RtcSlowClock32kXtal,
2 => RtcSlowClock::RtcSlowClock32kRc,
3 => RtcSlowClock::RtcSlowOscSlow,
_ => unreachable!(),
}
}
fn set_slow_freq(slow_freq: RtcSlowClock) {
unsafe {
LP_CLKRST::regs()
.lp_clk_conf()
.modify(|_, w| w.slow_clk_sel().bits(slow_freq as u8));
}
LP_CLKRST::regs().clk_to_hp().modify(|_, w| {
w.icg_hp_xtal32k()
.bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kXtal));
w.icg_hp_osc32k()
.bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kRc))
});
}
// TODO: IDF-5781 Some of esp32c6 SOC_RTC_FAST_CLK_SRC_XTAL_D2 rtc_fast clock
// has timing issue Force to use SOC_RTC_FAST_CLK_SRC_RC_FAST since 2nd
// stage bootloader https://github.com/espressif/esp-idf/blob/master/components/bootloader_support/src/bootloader_clock_init.c#L65-L67
fn set_fast_freq(fast_freq: RtcFastClock) {
LP_CLKRST::regs().lp_clk_conf().modify(|_, w| {
w.fast_clk_sel().bit(match fast_freq {
RtcFastClock::RtcFastClockRcFast => false,
RtcFastClock::RtcFastClockXtalD2 => true,
})
});
crate::rom::ets_delay_us(3);
}
/// Calibration of RTC_SLOW_CLK is performed using a special feature of
/// TIMG0. This feature counts the number of XTAL clock cycles within a
/// given number of RTC_SLOW_CLK cycles.
pub(crate) fn calibrate_internal(mut cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
const SOC_CLK_RC_FAST_FREQ_APPROX: u32 = 17_500_000;
const SOC_CLK_RC_SLOW_FREQ_APPROX: u32 = 136_000;
const SOC_CLK_XTAL32K_FREQ_APPROX: u32 = 32768;
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match cal_clk {
RtcCalSel::RtcCalRtcMux => match RtcClock::slow_freq() {
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
_ => cal_clk,
},
RtcCalSel::RtcCal32kOscSlow => RtcCalSel::RtcCalRtcMux,
_ => cal_clk,
};
}
let clk_src = RtcClock::slow_freq();
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match clk_src {
RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCal32kOscSlow,
};
}
let cali_clk_sel;
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match clk_src {
RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCalRcSlow,
}
}
if cal_clk == RtcCalSel::RtcCalRcFast {
cali_clk_sel = RtcCaliClkSel::CaliClkRcFast;
} else if cal_clk == RtcCalSel::RtcCalRcSlow {
cali_clk_sel = RtcCaliClkSel::CaliClkRcSlow;
} else {
cali_clk_sel = RtcCaliClkSel::CaliClk32k;
match cal_clk {
RtcCalSel::RtcCalRtcMux | RtcCalSel::RtcCalRcSlow | RtcCalSel::RtcCalRcFast => {}
RtcCalSel::RtcCal32kRc => {
PCR::regs()
.ctrl_32k_conf()
.modify(|_, w| unsafe { w.clk_32k_sel().bits(0) });
}
RtcCalSel::RtcCal32kXtal => {
PCR::regs()
.ctrl_32k_conf()
.modify(|_, w| unsafe { w.clk_32k_sel().bits(1) });
}
RtcCalSel::RtcCal32kOscSlow => {
PCR::regs()
.ctrl_32k_conf()
.modify(|_, w| unsafe { w.clk_32k_sel().bits(2) });
}
}
}
// Enable requested clock (150k is always on)
// Some delay is required before the time is stable
// Only enable if originaly was disabled
// If clock is already on, do nothing
let dig_32k_xtal_enabled = LP_CLKRST::regs()
.clk_to_hp()
.read()
.icg_hp_xtal32k()
.bit_is_set();
if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_xtal32k().set_bit());
}
// TODO: very hacky - icg_hp_xtal32k is already set in the above condition?
// in ESP-IDF these are not called in this function but the fields are set
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_xtal32k().set_bit());
PMU::regs().hp_sleep_lp_ck_power().modify(|_, w| {
w.hp_sleep_xpd_xtal32k().set_bit();
w.hp_sleep_xpd_rc32k().set_bit()
});
let rc_fast_enabled = PMU::regs()
.hp_sleep_lp_ck_power()
.read()
.hp_sleep_xpd_fosc_clk()
.bit_is_set();
let dig_rc_fast_enabled = LP_CLKRST::regs()
.clk_to_hp()
.read()
.icg_hp_fosc()
.bit_is_set();
if cal_clk == RtcCalSel::RtcCalRcFast {
if !rc_fast_enabled {
PMU::regs()
.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
crate::rom::ets_delay_us(50);
}
if !dig_rc_fast_enabled {
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_fosc().set_bit());
crate::rom::ets_delay_us(5);
}
}
let rc32k_enabled = PMU::regs()
.hp_sleep_lp_ck_power()
.read()
.hp_sleep_xpd_rc32k()
.bit_is_set();
let dig_rc32k_enabled = LP_CLKRST::regs()
.clk_to_hp()
.read()
.icg_hp_osc32k()
.bit_is_set();
if cal_clk == RtcCalSel::RtcCal32kRc {
if !rc32k_enabled {
PMU::regs()
.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
crate::rom::ets_delay_us(300);
}
if !dig_rc32k_enabled {
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_osc32k().set_bit());
}
}
// Check if there is already running calibration process
// TODO: &mut TIMG0 for calibration
let timg0 = TIMG0::regs();
if timg0
.rtccalicfg()
.read()
.rtc_cali_start_cycling()
.bit_is_set()
{
timg0
.rtccalicfg2()
.modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(1) });
// Set small timeout threshold to accelerate the generation of timeot
// Internal circuit will be reset when timeout occurs and will not affect the
// next calibration
while !timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_set()
&& !timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_set()
{}
}
// Prepare calibration
timg0
.rtccalicfg()
.modify(|_, w| unsafe { w.rtc_cali_clk_sel().bits(cali_clk_sel.clone() as u8) });
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start_cycling().clear_bit());
timg0
.rtccalicfg()
.modify(|_, w| unsafe { w.rtc_cali_max().bits(slowclk_cycles as u16) });
let expected_freq = match cali_clk_sel {
RtcCaliClkSel::CaliClk32k => {
timg0.rtccalicfg2().modify(|_, w| unsafe {
w.rtc_cali_timeout_thres().bits(slowclk_cycles << 12)
});
SOC_CLK_XTAL32K_FREQ_APPROX
}
RtcCaliClkSel::CaliClkRcFast => {
timg0
.rtccalicfg2()
.modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(0x01FFFFFF) });
SOC_CLK_RC_FAST_FREQ_APPROX
}
_ => {
timg0.rtccalicfg2().modify(|_, w| unsafe {
w.rtc_cali_timeout_thres().bits(slowclk_cycles << 10)
});
SOC_CLK_RC_SLOW_FREQ_APPROX
}
};
let us_time_estimate = (Rate::from_mhz(slowclk_cycles) / expected_freq).as_hz();
// Start calibration
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start().clear_bit());
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start().set_bit());
// Wait for calibration to finish up to another us_time_estimate
crate::rom::ets_delay_us(us_time_estimate);
let cal_val = loop {
if timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_set() {
// The Fosc CLK of calibration circuit is divided by 32 for ECO1.
// So we need to multiply the frequency of the Fosc for ECO1 and above chips by
// 32 times. And ensure that this modification will not affect
// ECO0.
// https://github.com/espressif/esp-idf/commit/e3148369f32fdc6de62c35a67f7adb6f4faef4e3
if Efuse::chip_revision() > 0 && cal_clk == RtcCalSel::RtcCalRcFast {
break timg0.rtccalicfg1().read().rtc_cali_value().bits() >> 5;
}
break timg0.rtccalicfg1().read().rtc_cali_value().bits();
}
if timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_set() {
// Timed out waiting for calibration
break 0;
}
};
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start().clear_bit());
if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_xtal32k().clear_bit());
}
if cal_clk == RtcCalSel::RtcCalRcFast {
if rc_fast_enabled {
PMU::regs()
.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
crate::rom::ets_delay_us(50);
}
if dig_rc_fast_enabled {
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_fosc().set_bit());
crate::rom::ets_delay_us(5);
}
}
if cal_clk == RtcCalSel::RtcCal32kRc {
if rc32k_enabled {
PMU::regs()
.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
crate::rom::ets_delay_us(300);
}
if dig_rc32k_enabled {
LP_CLKRST::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_osc32k().set_bit());
}
}
cal_val
}
}
pub(crate) fn rtc_clk_cpu_freq_set_xtal() {
// rtc_clk_cpu_set_to_default_config
let freq = RtcClock::xtal_freq().mhz();

View File

@ -1,10 +1,9 @@
use strum::FromRepr;
use crate::{
clock::{Clock, clocks_ll::regi2c_write_mask},
peripherals::{LP_AON, LPWR, PCR, PMU, TIMG0},
rtc_cntl::RtcClock,
time::Rate,
clock::clocks_ll::regi2c_write_mask,
peripherals::{LP_AON, PMU},
rtc_cntl::{RtcCalSel, RtcClock, RtcFastClock, RtcSlowClock},
};
const I2C_PMU: u8 = 0x6d;
@ -188,372 +187,3 @@ pub enum SocResetReason {
/// Glitch on power resets the digital core
CorePwrGlitch = 0x17,
}
/// RTC SLOW_CLK frequency values
#[derive(Debug, Clone, Copy)]
pub(crate) enum RtcFastClock {
/// Select RC_FAST_CLK as RTC_FAST_CLK source
RtcFastClockRcFast = 0,
#[allow(dead_code)]
/// Select XTAL_D2_CLK as RTC_FAST_CLK source
RtcFastClockXtalD2 = 1,
}
impl Clock for RtcFastClock {
fn frequency(&self) -> Rate {
match self {
RtcFastClock::RtcFastClockXtalD2 => Rate::from_hz(16_000_000),
RtcFastClock::RtcFastClockRcFast => Rate::from_hz(property!("soc.rc_fast_clk_default")),
}
}
}
/// RTC SLOW_CLK frequency values
#[allow(clippy::enum_variant_names)]
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub enum RtcSlowClock {
/// Select RC_SLOW_CLK as RTC_SLOW_CLK source
RtcSlowClockRcSlow = 0,
/// Select XTAL32K_CLK as RTC_SLOW_CLK source
RtcSlowClock32kXtal = 1,
/// Select RC32K_CLK as RTC_SLOW_CLK source
RtcSlowClock32kRc = 2,
/// Select OSC_SLOW_CLK (external slow clock) as RTC_SLOW_CLK source
RtcSlowOscSlow = 3,
}
impl Clock for RtcSlowClock {
fn frequency(&self) -> Rate {
match self {
RtcSlowClock::RtcSlowClockRcSlow => Rate::from_hz(150_000),
RtcSlowClock::RtcSlowClock32kXtal => Rate::from_hz(32_768),
RtcSlowClock::RtcSlowClock32kRc => Rate::from_hz(32_768),
RtcSlowClock::RtcSlowOscSlow => Rate::from_hz(32_768),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
/// Clock source to be calibrated using rtc_clk_cal function
pub(crate) enum RtcCalSel {
/// Currently selected RTC SLOW_CLK
RtcCalRtcMux = -1,
/// Internal 150kHz RC oscillator
RtcCalRcSlow = 0,
/// External 32kHz XTAL, as one type of 32k clock
RtcCal32kXtal = 1,
/// Internal 32kHz RC oscillator, as one type of 32k clock
RtcCal32kRc = 2,
/// External slow clock signal input by lp_pad_gpio0, as one type of 32k
/// clock
RtcCal32kOscSlow = 3,
/// Internal 20MHz RC oscillator
RtcCalRcFast,
}
#[derive(Clone)]
pub(crate) enum RtcCaliClkSel {
CaliClkRcSlow = 0,
CaliClkRcFast = 1,
CaliClk32k = 2,
}
/// RTC Watchdog Timer driver
impl RtcClock {
fn set_fast_freq(fast_freq: RtcFastClock) {
// components/hal/esp32s2/include/hal/clk_tree_ll.h
LPWR::regs().lp_clk_conf().modify(|_, w| unsafe {
w.fast_clk_sel().bits(match fast_freq {
RtcFastClock::RtcFastClockRcFast => 0b00,
RtcFastClock::RtcFastClockXtalD2 => 0b01,
})
});
crate::rom::ets_delay_us(3);
}
fn set_slow_freq(slow_freq: RtcSlowClock) {
LPWR::regs()
.lp_clk_conf()
.modify(|_, w| unsafe { w.slow_clk_sel().bits(slow_freq as u8) });
LPWR::regs().clk_to_hp().modify(|_, w| {
w.icg_hp_xtal32k()
.bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kXtal));
w.icg_hp_osc32k()
.bit(matches!(slow_freq, RtcSlowClock::RtcSlowClock32kRc))
});
}
/// Get the RTC_SLOW_CLK source
pub fn slow_freq() -> RtcSlowClock {
match LPWR::regs().lp_clk_conf().read().slow_clk_sel().bits() {
0 => RtcSlowClock::RtcSlowClockRcSlow,
1 => RtcSlowClock::RtcSlowClock32kXtal,
2 => RtcSlowClock::RtcSlowClock32kRc,
3 => RtcSlowClock::RtcSlowOscSlow,
_ => unreachable!(),
}
}
/// Calibration of RTC_SLOW_CLK is performed using a special feature of
/// TIMG0. This feature counts the number of XTAL clock cycles within a
/// given number of RTC_SLOW_CLK cycles.
pub(crate) fn calibrate_internal(mut cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 {
const SOC_CLK_RC_FAST_FREQ_APPROX: u32 = 17_500_000;
const SOC_CLK_RC_SLOW_FREQ_APPROX: u32 = 136_000;
const SOC_CLK_XTAL32K_FREQ_APPROX: u32 = 32768;
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match cal_clk {
RtcCalSel::RtcCalRtcMux => match RtcClock::slow_freq() {
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
_ => cal_clk,
},
RtcCalSel::RtcCal32kOscSlow => RtcCalSel::RtcCalRtcMux,
_ => cal_clk,
};
}
let clk_src = RtcClock::slow_freq();
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match clk_src {
RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCal32kOscSlow,
};
}
let cali_clk_sel;
if cal_clk == RtcCalSel::RtcCalRtcMux {
cal_clk = match clk_src {
RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRcSlow,
RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal,
RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc,
RtcSlowClock::RtcSlowOscSlow => RtcCalSel::RtcCalRcSlow,
}
}
if cal_clk == RtcCalSel::RtcCalRcFast {
cali_clk_sel = RtcCaliClkSel::CaliClkRcFast;
} else if cal_clk == RtcCalSel::RtcCalRcSlow {
cali_clk_sel = RtcCaliClkSel::CaliClkRcSlow;
} else {
cali_clk_sel = RtcCaliClkSel::CaliClk32k;
match cal_clk {
RtcCalSel::RtcCalRtcMux | RtcCalSel::RtcCalRcSlow | RtcCalSel::RtcCalRcFast => {}
RtcCalSel::RtcCal32kRc => {
PCR::regs()
.ctrl_32k_conf()
.modify(|_, w| unsafe { w.clk_32k_sel().bits(0) });
}
RtcCalSel::RtcCal32kXtal => {
PCR::regs()
.ctrl_32k_conf()
.modify(|_, w| unsafe { w.clk_32k_sel().bits(1) });
}
RtcCalSel::RtcCal32kOscSlow => {
PCR::regs()
.ctrl_32k_conf()
.modify(|_, w| unsafe { w.clk_32k_sel().bits(2) });
}
}
}
// Enable requested clock (150k is always on)
// Some delay is required before the time is stable
// Only enable if originaly was disabled
// If clock is already on, do nothing
let dig_32k_xtal_enabled = LPWR::regs()
.clk_to_hp()
.read()
.icg_hp_xtal32k()
.bit_is_set();
if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
LPWR::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_xtal32k().set_bit());
}
// TODO: very hacky - icg_hp_xtal32k is already set in the above condition?
// in ESP-IDF these are not called in this function but the fields are set
LPWR::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_xtal32k().set_bit());
PMU::regs().hp_sleep_lp_ck_power().modify(|_, w| {
w.hp_sleep_xpd_xtal32k().set_bit();
w.hp_sleep_xpd_rc32k().set_bit()
});
let rc_fast_enabled = PMU::regs()
.hp_sleep_lp_ck_power()
.read()
.hp_sleep_xpd_fosc_clk()
.bit_is_set();
let dig_rc_fast_enabled = LPWR::regs().clk_to_hp().read().icg_hp_fosc().bit_is_set();
if cal_clk == RtcCalSel::RtcCalRcFast {
if !rc_fast_enabled {
PMU::regs()
.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
crate::rom::ets_delay_us(50);
}
if !dig_rc_fast_enabled {
LPWR::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_fosc().set_bit());
crate::rom::ets_delay_us(5);
}
}
let rc32k_enabled = PMU::regs()
.hp_sleep_lp_ck_power()
.read()
.hp_sleep_xpd_rc32k()
.bit_is_set();
let dig_rc32k_enabled = LPWR::regs().clk_to_hp().read().icg_hp_osc32k().bit_is_set();
if cal_clk == RtcCalSel::RtcCal32kRc {
if !rc32k_enabled {
PMU::regs()
.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
crate::rom::ets_delay_us(300);
}
if !dig_rc32k_enabled {
LPWR::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_osc32k().set_bit());
}
}
// Check if there is already running calibration process
// TODO: &mut TIMG0 for calibration
let timg0 = TIMG0::regs();
if timg0
.rtccalicfg()
.read()
.rtc_cali_start_cycling()
.bit_is_set()
{
timg0
.rtccalicfg2()
.modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(1) });
// Set small timeout threshold to accelerate the generation of timeot
// Internal circuit will be reset when timeout occurs and will not affect the
// next calibration
while !timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_set()
&& !timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_set()
{}
}
// Prepare calibration
timg0
.rtccalicfg()
.modify(|_, w| unsafe { w.rtc_cali_clk_sel().bits(cali_clk_sel.clone() as u8) });
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start_cycling().clear_bit());
timg0
.rtccalicfg()
.modify(|_, w| unsafe { w.rtc_cali_max().bits(slowclk_cycles as u16) });
let expected_freq = match cali_clk_sel {
RtcCaliClkSel::CaliClk32k => {
timg0.rtccalicfg2().modify(|_, w| unsafe {
w.rtc_cali_timeout_thres().bits(slowclk_cycles << 12)
});
SOC_CLK_XTAL32K_FREQ_APPROX
}
RtcCaliClkSel::CaliClkRcFast => {
timg0
.rtccalicfg2()
.modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(0x01FFFFFF) });
SOC_CLK_RC_FAST_FREQ_APPROX
}
_ => {
timg0.rtccalicfg2().modify(|_, w| unsafe {
w.rtc_cali_timeout_thres().bits(slowclk_cycles << 10)
});
SOC_CLK_RC_SLOW_FREQ_APPROX
}
};
let us_time_estimate = (Rate::from_mhz(slowclk_cycles) / expected_freq).as_hz();
// Start calibration
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start().clear_bit());
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start().set_bit());
// Wait for calibration to finish up to another us_time_estimate
crate::rom::ets_delay_us(us_time_estimate);
let cal_val = loop {
if timg0.rtccalicfg().read().rtc_cali_rdy().bit_is_set() {
break timg0.rtccalicfg1().read().rtc_cali_value().bits();
}
if timg0.rtccalicfg2().read().rtc_cali_timeout().bit_is_set() {
// Timed out waiting for calibration
break 0;
}
};
timg0
.rtccalicfg()
.modify(|_, w| w.rtc_cali_start().clear_bit());
if cal_clk == RtcCalSel::RtcCal32kXtal && !dig_32k_xtal_enabled {
LPWR::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_xtal32k().clear_bit());
}
if cal_clk == RtcCalSel::RtcCalRcFast {
if rc_fast_enabled {
PMU::regs()
.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_fosc_clk().set_bit());
crate::rom::ets_delay_us(50);
}
if dig_rc_fast_enabled {
LPWR::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_fosc().set_bit());
crate::rom::ets_delay_us(5);
}
}
if cal_clk == RtcCalSel::RtcCal32kRc {
if rc32k_enabled {
PMU::regs()
.hp_sleep_lp_ck_power()
.modify(|_, w| w.hp_sleep_xpd_rc32k().set_bit());
crate::rom::ets_delay_us(300);
}
if dig_rc32k_enabled {
LPWR::regs()
.clk_to_hp()
.modify(|_, w| w.icg_hp_osc32k().set_bit());
}
}
cal_val
}
}

View File

@ -8,10 +8,10 @@ use crate::{
pub(crate) fn init() {}
pub(crate) fn configure_clock() {
RtcClock::set_fast_freq(RtcFastClock::RtcFastClock8m);
RtcClock::set_fast_freq(RtcFastClock::RtcFastClockRcFast);
let cal_val = loop {
RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRtc);
RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRcSlow);
let res = RtcClock::calibrate(RtcCalSel::RtcCalRtcMux, 1024);
if res != 0 {

View File

@ -8,10 +8,10 @@ use crate::{
pub(crate) fn init() {}
pub(crate) fn configure_clock() {
RtcClock::set_fast_freq(RtcFastClock::RtcFastClock8m);
RtcClock::set_fast_freq(RtcFastClock::RtcFastClockRcFast);
let cal_val = loop {
RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRtc);
RtcClock::set_slow_freq(RtcSlowClock::RtcSlowClockRcSlow);
let res = RtcClock::calibrate(RtcCalSel::RtcCalRtcMux, 1024);
if res != 0 {

View File

@ -6,6 +6,7 @@ use crate::{
gpio::RtcFunction,
rtc_cntl::{
Rtc,
RtcCalSel,
RtcClock,
rtc::{
HpAnalog,
@ -13,7 +14,6 @@ use crate::{
HpSysPower,
LpAnalog,
LpSysPower,
RtcCalSel,
SavedClockConfig,
rtc_clk_cpu_freq_set_xtal,
},

View File

@ -265,8 +265,10 @@ impl Chip {
"uart_uart2",
"soc_ref_tick_hz=\"1000000\"",
"soc_ref_tick_hz_is_set",
"soc_rc_fast_clk_default=\"8000000\"",
"soc_rc_fast_clk_default=\"8500000\"",
"soc_rc_fast_clk_default_is_set",
"soc_rc_slow_clock=\"150000\"",
"soc_rc_slow_clock_is_set",
"soc_has_multiple_xtal_options",
"aes_endianness_configurable",
"gpio_has_bank_1",
@ -419,8 +421,10 @@ impl Chip {
"cargo:rustc-cfg=uart_uart2",
"cargo:rustc-cfg=soc_ref_tick_hz=\"1000000\"",
"cargo:rustc-cfg=soc_ref_tick_hz_is_set",
"cargo:rustc-cfg=soc_rc_fast_clk_default=\"8000000\"",
"cargo:rustc-cfg=soc_rc_fast_clk_default=\"8500000\"",
"cargo:rustc-cfg=soc_rc_fast_clk_default_is_set",
"cargo:rustc-cfg=soc_rc_slow_clock=\"150000\"",
"cargo:rustc-cfg=soc_rc_slow_clock_is_set",
"cargo:rustc-cfg=soc_has_multiple_xtal_options",
"cargo:rustc-cfg=aes_endianness_configurable",
"cargo:rustc-cfg=gpio_has_bank_1",
@ -537,6 +541,8 @@ impl Chip {
"soc_cpu_has_csr_pc",
"soc_rc_fast_clk_default=\"17500000\"",
"soc_rc_fast_clk_default_is_set",
"soc_rc_slow_clock=\"136000\"",
"soc_rc_slow_clock_is_set",
"soc_has_multiple_xtal_options",
"assist_debug_has_sp_monitor",
"gpio_gpio_function=\"1\"",
@ -652,6 +658,8 @@ impl Chip {
"cargo:rustc-cfg=soc_cpu_has_csr_pc",
"cargo:rustc-cfg=soc_rc_fast_clk_default=\"17500000\"",
"cargo:rustc-cfg=soc_rc_fast_clk_default_is_set",
"cargo:rustc-cfg=soc_rc_slow_clock=\"136000\"",
"cargo:rustc-cfg=soc_rc_slow_clock_is_set",
"cargo:rustc-cfg=soc_has_multiple_xtal_options",
"cargo:rustc-cfg=assist_debug_has_sp_monitor",
"cargo:rustc-cfg=gpio_gpio_function=\"1\"",
@ -788,6 +796,8 @@ impl Chip {
"soc_cpu_has_csr_pc",
"soc_rc_fast_clk_default=\"17500000\"",
"soc_rc_fast_clk_default_is_set",
"soc_rc_slow_clock=\"136000\"",
"soc_rc_slow_clock_is_set",
"soc_xtal_frequency=\"40\"",
"aes_dma",
"aes_dma_mode_ecb",
@ -933,6 +943,8 @@ impl Chip {
"cargo:rustc-cfg=soc_cpu_has_csr_pc",
"cargo:rustc-cfg=soc_rc_fast_clk_default=\"17500000\"",
"cargo:rustc-cfg=soc_rc_fast_clk_default_is_set",
"cargo:rustc-cfg=soc_rc_slow_clock=\"136000\"",
"cargo:rustc-cfg=soc_rc_slow_clock_is_set",
"cargo:rustc-cfg=soc_xtal_frequency=\"40\"",
"cargo:rustc-cfg=aes_dma",
"cargo:rustc-cfg=aes_dma_mode_ecb",
@ -1133,6 +1145,8 @@ impl Chip {
"soc_cpu_has_prv_mode",
"soc_rc_fast_clk_default=\"17500000\"",
"soc_rc_fast_clk_default_is_set",
"soc_rc_slow_clock=\"136000\"",
"soc_rc_slow_clock_is_set",
"soc_xtal_frequency=\"40\"",
"aes_dma",
"aes_dma_mode_ecb",
@ -1333,6 +1347,8 @@ impl Chip {
"cargo:rustc-cfg=soc_cpu_has_prv_mode",
"cargo:rustc-cfg=soc_rc_fast_clk_default=\"17500000\"",
"cargo:rustc-cfg=soc_rc_fast_clk_default_is_set",
"cargo:rustc-cfg=soc_rc_slow_clock=\"136000\"",
"cargo:rustc-cfg=soc_rc_slow_clock_is_set",
"cargo:rustc-cfg=soc_xtal_frequency=\"40\"",
"cargo:rustc-cfg=aes_dma",
"cargo:rustc-cfg=aes_dma_mode_ecb",
@ -1512,8 +1528,10 @@ impl Chip {
"uart_uart1",
"soc_cpu_has_csr_pc",
"soc_cpu_has_prv_mode",
"soc_rc_fast_clk_default=\"8000000\"",
"soc_rc_fast_clk_default=\"8500000\"",
"soc_rc_fast_clk_default_is_set",
"soc_rc_slow_clock=\"136000\"",
"soc_rc_slow_clock_is_set",
"soc_xtal_frequency=\"32\"",
"aes_dma",
"aes_dma_mode_ecb",
@ -1687,8 +1705,10 @@ impl Chip {
"cargo:rustc-cfg=uart_uart1",
"cargo:rustc-cfg=soc_cpu_has_csr_pc",
"cargo:rustc-cfg=soc_cpu_has_prv_mode",
"cargo:rustc-cfg=soc_rc_fast_clk_default=\"8000000\"",
"cargo:rustc-cfg=soc_rc_fast_clk_default=\"8500000\"",
"cargo:rustc-cfg=soc_rc_fast_clk_default_is_set",
"cargo:rustc-cfg=soc_rc_slow_clock=\"136000\"",
"cargo:rustc-cfg=soc_rc_slow_clock_is_set",
"cargo:rustc-cfg=soc_xtal_frequency=\"32\"",
"cargo:rustc-cfg=aes_dma",
"cargo:rustc-cfg=aes_dma_mode_ecb",
@ -1861,8 +1881,10 @@ impl Chip {
"uart_uart1",
"soc_ref_tick_hz=\"1000000\"",
"soc_ref_tick_hz_is_set",
"soc_rc_fast_clk_default=\"8000000\"",
"soc_rc_fast_clk_default=\"8500000\"",
"soc_rc_fast_clk_default_is_set",
"soc_rc_slow_clock=\"90000\"",
"soc_rc_slow_clock_is_set",
"soc_xtal_frequency=\"40\"",
"aes_dma",
"aes_dma_mode_ecb",
@ -2027,8 +2049,10 @@ impl Chip {
"cargo:rustc-cfg=uart_uart1",
"cargo:rustc-cfg=soc_ref_tick_hz=\"1000000\"",
"cargo:rustc-cfg=soc_ref_tick_hz_is_set",
"cargo:rustc-cfg=soc_rc_fast_clk_default=\"8000000\"",
"cargo:rustc-cfg=soc_rc_fast_clk_default=\"8500000\"",
"cargo:rustc-cfg=soc_rc_fast_clk_default_is_set",
"cargo:rustc-cfg=soc_rc_slow_clock=\"90000\"",
"cargo:rustc-cfg=soc_rc_slow_clock_is_set",
"cargo:rustc-cfg=soc_xtal_frequency=\"40\"",
"cargo:rustc-cfg=aes_dma",
"cargo:rustc-cfg=aes_dma_mode_ecb",
@ -2213,6 +2237,8 @@ impl Chip {
"uart_uart2",
"soc_rc_fast_clk_default=\"17500000\"",
"soc_rc_fast_clk_default_is_set",
"soc_rc_slow_clock=\"136000\"",
"soc_rc_slow_clock_is_set",
"soc_xtal_frequency=\"40\"",
"aes_dma",
"aes_dma_mode_ecb",
@ -2395,6 +2421,8 @@ impl Chip {
"cargo:rustc-cfg=uart_uart2",
"cargo:rustc-cfg=soc_rc_fast_clk_default=\"17500000\"",
"cargo:rustc-cfg=soc_rc_fast_clk_default_is_set",
"cargo:rustc-cfg=soc_rc_slow_clock=\"136000\"",
"cargo:rustc-cfg=soc_rc_slow_clock_is_set",
"cargo:rustc-cfg=soc_xtal_frequency=\"40\"",
"cargo:rustc-cfg=aes_dma",
"cargo:rustc-cfg=aes_dma_mode_ecb",
@ -2574,6 +2602,7 @@ impl Config {
println!("cargo:rustc-check-cfg=cfg(uart_uart2)");
println!("cargo:rustc-check-cfg=cfg(soc_ref_tick_hz_is_set)");
println!("cargo:rustc-check-cfg=cfg(soc_rc_fast_clk_default_is_set)");
println!("cargo:rustc-check-cfg=cfg(soc_rc_slow_clock_is_set)");
println!("cargo:rustc-check-cfg=cfg(soc_has_multiple_xtal_options)");
println!("cargo:rustc-check-cfg=cfg(aes_endianness_configurable)");
println!("cargo:rustc-check-cfg=cfg(gpio_has_bank_1)");
@ -2729,7 +2758,10 @@ impl Config {
println!("cargo:rustc-check-cfg=cfg(camera)");
println!("cargo:rustc-check-cfg=cfg(soc_ref_tick_hz, values(\"1000000\"))");
println!(
"cargo:rustc-check-cfg=cfg(soc_rc_fast_clk_default, values(\"8000000\",\"17500000\"))"
"cargo:rustc-check-cfg=cfg(soc_rc_fast_clk_default, values(\"8500000\",\"17500000\"))"
);
println!(
"cargo:rustc-check-cfg=cfg(soc_rc_slow_clock, values(\"150000\",\"136000\",\"90000\"))"
);
println!("cargo:rustc-check-cfg=cfg(gpio_gpio_function, values(\"2\",\"1\"))");
println!("cargo:rustc-check-cfg=cfg(gpio_constant_0_input, values(\"48\",\"31\",\"60\"))");

View File

@ -49,10 +49,16 @@ macro_rules! property {
stringify!(1000000)
};
("soc.rc_fast_clk_default") => {
8000000
8500000
};
("soc.rc_fast_clk_default", str) => {
stringify!(8000000)
stringify!(8500000)
};
("soc.rc_slow_clock") => {
150000
};
("soc.rc_slow_clock", str) => {
stringify!(150000)
};
("soc.has_multiple_xtal_options") => {
true

View File

@ -48,6 +48,12 @@ macro_rules! property {
("soc.rc_fast_clk_default", str) => {
stringify!(17500000)
};
("soc.rc_slow_clock") => {
136000
};
("soc.rc_slow_clock", str) => {
stringify!(136000)
};
("soc.has_multiple_xtal_options") => {
true
};

View File

@ -48,6 +48,12 @@ macro_rules! property {
("soc.rc_fast_clk_default", str) => {
stringify!(17500000)
};
("soc.rc_slow_clock") => {
136000
};
("soc.rc_slow_clock", str) => {
stringify!(136000)
};
("soc.xtal_frequency") => {
40
};

View File

@ -48,6 +48,12 @@ macro_rules! property {
("soc.rc_fast_clk_default", str) => {
stringify!(17500000)
};
("soc.rc_slow_clock") => {
136000
};
("soc.rc_slow_clock", str) => {
stringify!(136000)
};
("soc.xtal_frequency") => {
40
};

View File

@ -43,10 +43,16 @@ macro_rules! property {
true
};
("soc.rc_fast_clk_default") => {
8000000
8500000
};
("soc.rc_fast_clk_default", str) => {
stringify!(8000000)
stringify!(8500000)
};
("soc.rc_slow_clock") => {
136000
};
("soc.rc_slow_clock", str) => {
stringify!(136000)
};
("soc.xtal_frequency") => {
32

View File

@ -49,10 +49,16 @@ macro_rules! property {
stringify!(1000000)
};
("soc.rc_fast_clk_default") => {
8000000
8500000
};
("soc.rc_fast_clk_default", str) => {
stringify!(8000000)
stringify!(8500000)
};
("soc.rc_slow_clock") => {
90000
};
("soc.rc_slow_clock", str) => {
stringify!(90000)
};
("soc.xtal_frequency") => {
40

View File

@ -48,6 +48,12 @@ macro_rules! property {
("soc.rc_fast_clk_default", str) => {
stringify!(17500000)
};
("soc.rc_slow_clock") => {
136000
};
("soc.rc_slow_clock", str) => {
stringify!(136000)
};
("soc.xtal_frequency") => {
40
};

View File

@ -104,7 +104,8 @@ memory = [{ name = "dram", start = 0x3FFA_E000, end = 0x4000_0000 }]
[device.soc]
ref_tick_hz = 1_000_000
rc_fast_clk_default = 8_000_000
rc_fast_clk_default = 8_500_000
rc_slow_clock = 150_000
xtal_options = [26, 40]
[device.adc]

View File

@ -83,6 +83,7 @@ memory = [{ name = "dram", start = 0x3FCA_0000, end = 0x3FCE_0000 }]
[device.soc]
cpu_has_csr_pc = true
rc_fast_clk_default = 17_500_000
rc_slow_clock = 136_000
xtal_options = [26, 40]
[device.adc]

View File

@ -92,6 +92,7 @@ memory = [{ name = "dram", start = 0x3FC8_0000, end = 0x3FCE_0000 }]
[device.soc]
cpu_has_csr_pc = true
rc_fast_clk_default = 17_500_000
rc_slow_clock = 136_000
xtal_options = [40]
[device.adc]

View File

@ -134,6 +134,7 @@ memory = [{ name = "dram", start = 0x4080_0000, end = 0x4088_0000 }]
cpu_has_csr_pc = true
cpu_has_prv_mode = true
rc_fast_clk_default = 17_500_000
rc_slow_clock = 136_000
xtal_options = [40]
[device.adc]

View File

@ -112,7 +112,8 @@ memory = [{ name = "dram", start = 0x4080_0000, end = 0x4085_0000 }]
[device.soc]
cpu_has_csr_pc = true
cpu_has_prv_mode = true
rc_fast_clk_default = 8_000_000
rc_fast_clk_default = 8_500_000
rc_slow_clock = 136_000
xtal_options = [32]
[device.adc]

View File

@ -103,7 +103,8 @@ memory = [{ name = "dram", start = 0x3FFB_0000, end = 0x4000_0000 }]
[device.soc]
ref_tick_hz = 1_000_000
rc_fast_clk_default = 8_000_000
rc_fast_clk_default = 8_500_000
rc_slow_clock = 90_000
xtal_options = [40]
[device.adc]

View File

@ -116,6 +116,7 @@ memory = [{ name = "dram", start = 0x3FC8_8000, end = 0x3FD0_0000 }]
[device.soc]
rc_fast_clk_default = 17_500_000
rc_slow_clock = 136_000
xtal_options = [40]
[device.adc]

View File

@ -285,6 +285,8 @@ driver_configs![
ref_tick_hz: Option<u32>,
#[serde(default)]
rc_fast_clk_default: Option<u32>,
#[serde(default)]
rc_slow_clock: Option<u32>,
xtal_options: Vec<u32>,
}
},