Merge branch 'refactor/rtc_cal_clk' into 'master'

refactor(clk): add soc_clk_calibration_clk_src_t for all targets

Closes IDF-11790

See merge request espressif/esp-idf!40737
This commit is contained in:
Song Ruo Jing
2025-07-31 19:49:17 +08:00
89 changed files with 1078 additions and 953 deletions
@@ -89,14 +89,9 @@ typedef struct rtc_cpu_freq_config_s {
uint32_t freq_mhz; //!< CPU clock frequency
} rtc_cpu_freq_config_t;
/**
* @brief Clock source to be calibrated using rtc_clk_cal function
*/
typedef enum {
RTC_CAL_RTC_MUX = 0, //!< Currently selected RTC SLOW_CLK
RTC_CAL_8MD256 = 1, //!< Internal 8 MHz RC oscillator, divided by 256
RTC_CAL_32K_XTAL = 2 //!< External 32 kHz XTAL
} rtc_cal_sel_t;
#define RTC_CAL_RTC_MUX _Pragma ("GCC warning \"'RTC_CAL_RTC_MUX' macro is deprecated\"") CLK_CAL_RTC_SLOW
#define RTC_CAL_8MD256 _Pragma ("GCC warning \"'RTC_CAL_8MD256' macro is deprecated\"") CLK_CAL_RC_FAST_D256
#define RTC_CAL_32K_XTAL _Pragma ("GCC warning \"'RTC_CAL_32K_XTAL' macro is deprecated\"") CLK_CAL_32K_XTAL
/**
* Initialization parameters for rtc_clk_init
@@ -397,21 +392,21 @@ uint32_t rtc_clk_apb_freq_get(void);
* the check fails, then consider this an invalid 32k clock and return 0. This
* check can filter some jamming signal.
*
* @param cal_clk clock to be measured
* @param cal_clk_sel clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average slow clock period in microseconds, Q13.19 fixed point format,
* or 0 if calibration has timed out
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Measure ratio between XTAL frequency and RTC slow clock frequency
* @param cal_clk slow clock to be measured
* @param cal_clk_sel slow clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average ratio between XTAL frequency and slow clock frequency,
* Q13.19 fixed point format, or 0 if calibration has timed out.
*/
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal_ratio(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Convert time interval from microseconds to RTC_SLOW_CLK cycles
@@ -150,7 +150,7 @@ static soc_xtal_freq_t rtc_clk_xtal_freq_estimate(void)
rtc_clk_8m_enable(true, true);
}
uint64_t cal_val = rtc_clk_cal_ratio(RTC_CAL_8MD256, XTAL_FREQ_EST_CYCLES);
uint64_t cal_val = rtc_clk_cal_ratio(CLK_CAL_RC_FAST_D256, XTAL_FREQ_EST_CYCLES);
/* cal_val contains period of 8M/256 clock in XTAL clock cycles
* (shifted by RTC_CLK_CAL_FRACT bits).
* Xtal frequency will be (cal_val * 8M / 256) / 2^19
+19 -18
View File
@@ -30,37 +30,38 @@ static const char *TAG = "rtc_time";
/**
* @brief Clock calibration function used by rtc_clk_cal and rtc_clk_cal_ratio
* @param cal_clk which clock to calibrate
* @param cal_clk_sel which clock to calculate frequency
* @param slowclk_cycles number of slow clock cycles to count. Max value is 32766.
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
static uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles < 32767);
/* Enable requested clock (150k clock is always on) */
/* Enable requested clock (rtc slow clock is always on) */
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
bool rc_fast_d256_enabled = clk_ll_rc_fast_d256_is_enabled();
if (cal_clk == RTC_CAL_8MD256) {
if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
rtc_clk_8m_enable(true, true);
clk_ll_rc_fast_d256_digi_enable();
}
/* Prepare calibration */
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cal_clk);
clk_ll_freq_calulation_set_target(cal_clk_sel);
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
/* Figure out how long to wait for calibration to finish */
uint32_t expected_freq;
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
if (cal_clk == RTC_CAL_32K_XTAL ||
(cal_clk == RTC_CAL_RTC_MUX && slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K)) {
if (cal_clk_sel == CLK_CAL_32K_XTAL ||
(cal_clk_sel == CLK_CAL_RTC_SLOW && slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K)) {
expected_freq = SOC_CLK_XTAL32K_FREQ_APPROX; /* standard 32k XTAL */
} else if (cal_clk == RTC_CAL_8MD256 ||
(cal_clk == RTC_CAL_RTC_MUX && slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256)) {
} else if (cal_clk_sel == CLK_CAL_RC_FAST_D256 ||
(cal_clk_sel == CLK_CAL_RTC_SLOW && slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256)) {
expected_freq = SOC_CLK_RC_FAST_D256_FREQ_APPROX;
} else {
expected_freq = SOC_CLK_RC_SLOW_FREQ_APPROX; /* 150k internal oscillator */
@@ -94,11 +95,11 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_8MD256) {
if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
clk_ll_rc_fast_d256_digi_disable();
rtc_clk_8m_enable(rc_fast_enabled, rc_fast_d256_enabled);
}
@@ -110,10 +111,10 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
return REG_GET_FIELD(TIMG_RTCCALICFG1_REG(0), TIMG_RTC_CALI_VALUE);
}
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal_ratio(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
uint64_t ratio_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT)) / slowclk_cycles;
uint32_t ratio = (uint32_t)(ratio_64 & UINT32_MAX);
return ratio;
@@ -126,13 +127,13 @@ static inline bool rtc_clk_cal_32k_valid(uint32_t xtal_freq, uint32_t slowclk_cy
return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles);
soc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
if ((cal_clk == RTC_CAL_32K_XTAL) && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
if ((cal_clk_sel == CLK_CAL_32K_XTAL) && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
return 0;
}
@@ -165,7 +166,7 @@ void rtc_clk_wait_for_slow_cycle(void)
{
REG_CLR_BIT(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING | TIMG_RTC_CALI_START);
REG_CLR_BIT(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY);
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, RTC_CAL_RTC_MUX);
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, CLK_CAL_RTC_SLOW);
/* Request to run calibration for 0 slow clock cycles.
* RDY bit will be set on the nearest slow clock cycle.
*/
@@ -155,17 +155,10 @@ typedef struct rtc_cpu_freq_config_s {
#define RTC_VDDSDIO_TIEH_1_8V 0 //!< TIEH field value for 1.8V VDDSDIO
#define RTC_VDDSDIO_TIEH_3_3V 1 //!< TIEH field value for 3.3V VDDSDIO
/**
* @brief Clock source to be calibrated using rtc_clk_cal function
*/
typedef enum {
RTC_CAL_RTC_MUX = 0, //!< Currently selected RTC SLOW_CLK
RTC_CAL_8MD256 = 1, //!< Internal 8 MHz RC oscillator, divided by 256
RTC_CAL_32K_OSC_SLOW = 2, //!< External 32.768 KHz CLK
// deprecated name
RTC_CAL_EXT_32K __attribute__((deprecated)) = RTC_CAL_32K_OSC_SLOW,
} rtc_cal_sel_t;
#define RTC_CAL_RTC_MUX _Pragma ("GCC warning \"'RTC_CAL_RTC_MUX' macro is deprecated\"") CLK_CAL_RTC_SLOW
#define RTC_CAL_8MD256 _Pragma ("GCC warning \"'RTC_CAL_8MD256' macro is deprecated\"") CLK_CAL_RC_FAST_D256
#define RTC_CAL_32K_OSC_SLOW _Pragma ("GCC warning \"'RTC_CAL_32K_OSC_SLOW' macro is deprecated\"") CLK_CAL_32K_OSC_SLOW
#define RTC_CAL_INTERNAL_OSC _Pragma ("GCC warning \"'RTC_CAL_INTERNAL_OSC' macro is deprecated\"") CLK_CAL_RC_SLOW
/**
* Initialization parameters for rtc_clk_init
@@ -409,8 +402,6 @@ void rtc_clk_apb_freq_update(uint32_t apb_freq);
*/
uint32_t rtc_clk_apb_freq_get(void);
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles);
/**
* @brief Measure RTC slow clock's period, based on main XTAL frequency
*
@@ -424,21 +415,21 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles);
* the check fails, then consider this an invalid 32k clock and return 0. This
* check can filter some jamming signal.
*
* @param cal_clk clock to be measured
* @param cal_clk_sel clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average slow clock period in microseconds, Q13.19 fixed point format,
* or 0 if calibration has timed out
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Measure ratio between XTAL frequency and RTC slow clock frequency
* @param cal_clk slow clock to be measured
* @param cal_clk_sel slow clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average ratio between XTAL frequency and slow clock frequency,
* Q13.19 fixed point format, or 0 if calibration has timed out.
*/
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal_ratio(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Convert time interval from microseconds to RTC_SLOW_CLK cycles
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -154,16 +154,9 @@ static void calibrate_ocode(void)
4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout;
5. set cpu to old-config.
*/
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX;
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) {
cal_clk = RTC_CAL_32K_OSC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256) {
cal_clk = RTC_CAL_8MD256;
}
uint64_t max_delay_time_us = 10000;
uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100);
uint32_t slow_clk_period = rtc_clk_cal(CLK_CAL_RTC_SLOW, 100);
uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period);
uint64_t cycle0 = rtc_time_get();
uint64_t timeout_cycle = cycle0 + max_delay_cycle;
@@ -259,7 +252,7 @@ uint32_t get_rtc_dbias_by_efuse(uint8_t dbias_scheme_ver, uint32_t dig_dbias)
static void set_rtc_dig_dbias()
{
/*
1. a reasonable dig_dbias which by scaning pvt to make 120 CPU run successful stored in efuse;
1. a reasonable dig_dbias which by scanning pvt to make 120 CPU run successful stored in efuse;
2. a reasonable rtc_dbias can be calculated by a certion formula.
*/
uint32_t rtc_dbias = 31, dig_dbias = 26;
@@ -29,34 +29,32 @@
/**
* @brief Clock calibration function used by rtc_clk_cal and rtc_clk_cal_ratio
* @param cal_clk which clock to calibrate
* @param cal_clk_sel which clock to calculate frequency
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
static uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
/* On ESP32-C2, choosing RTC_CAL_RTC_MUX results in calibration of
* the 150k RTC clock regardless of the currently selected SLOW_CLK.
* On the ESP32, it used the currently selected SLOW_CLK.
* The following code emulates ESP32 behavior:
*/
if (cal_clk == RTC_CAL_RTC_MUX) {
if (cal_clk_sel == CLK_CAL_RTC_SLOW) {
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) {
cal_clk = RTC_CAL_32K_OSC_SLOW;
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) {
cal_clk_sel = CLK_CAL_RC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) {
cal_clk_sel = CLK_CAL_32K_OSC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256) {
cal_clk = RTC_CAL_8MD256;
cal_clk_sel = CLK_CAL_RC_FAST_D256;
}
}
/* Enable requested clock (150k clock is always on) */
bool dig_ext_clk_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_OSC_SLOW && !dig_ext_clk_enabled) {
if (cal_clk_sel == CLK_CAL_32K_OSC_SLOW && !dig_ext_clk_enabled) {
clk_ll_xtal32k_digi_enable();
}
bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
bool rc_fast_d256_enabled = clk_ll_rc_fast_d256_is_enabled();
if (cal_clk == RTC_CAL_8MD256) {
if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
rtc_clk_8m_enable(true, true);
clk_ll_rc_fast_d256_digi_enable();
}
@@ -74,17 +72,17 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
}
/* Prepare calibration */
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cal_clk);
clk_ll_freq_calulation_set_target(cal_clk_sel);
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
/* Figure out how long to wait for calibration to finish */
/* Set timeout reg and expect time delay*/
uint32_t expected_freq;
if (cal_clk == RTC_CAL_32K_OSC_SLOW) {
if (cal_clk_sel == CLK_CAL_32K_OSC_SLOW) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_X32K_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_OSC_SLOW_FREQ_APPROX;
} else if (cal_clk == RTC_CAL_8MD256) {
} else if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_8MD256_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_RC_FAST_D256_FREQ_APPROX;
} else {
@@ -112,11 +110,11 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
/* if dig_ext_clk was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_OSC_SLOW && !dig_ext_clk_enabled) {
if (cal_clk_sel == CLK_CAL_32K_OSC_SLOW && !dig_ext_clk_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_8MD256) {
if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
clk_ll_rc_fast_d256_digi_disable();
rtc_clk_8m_enable(rc_fast_enabled, rc_fast_d256_enabled);
}
@@ -124,10 +122,10 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
return cal_val;
}
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal_ratio(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
uint64_t ratio_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT)) / slowclk_cycles;
uint32_t ratio = (uint32_t)(ratio_64 & UINT32_MAX);
return ratio;
@@ -140,13 +138,13 @@ static inline bool rtc_clk_cal_32k_valid(uint32_t xtal_freq, uint32_t slowclk_cy
return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles);
soc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
if ((cal_clk == RTC_CAL_32K_OSC_SLOW) && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
if ((cal_clk_sel == CLK_CAL_32K_OSC_SLOW) && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
return 0;
}
@@ -157,15 +157,10 @@ typedef struct rtc_cpu_freq_config_s {
#define RTC_VDDSDIO_TIEH_1_8V 0 //!< TIEH field value for 1.8V VDDSDIO
#define RTC_VDDSDIO_TIEH_3_3V 1 //!< TIEH field value for 3.3V VDDSDIO
/**
* @brief Clock source to be calibrated using rtc_clk_cal function
*/
typedef enum {
RTC_CAL_RTC_MUX = 0, //!< Currently selected RTC SLOW_CLK
RTC_CAL_8MD256 = 1, //!< Internal 8 MHz RC oscillator, divided by 256
RTC_CAL_32K_XTAL = 2, //!< External 32 kHz XTAL
RTC_CAL_INTERNAL_OSC = 3 //!< Internal 150 kHz oscillator
} rtc_cal_sel_t;
#define RTC_CAL_RTC_MUX _Pragma ("GCC warning \"'RTC_CAL_RTC_MUX' macro is deprecated\"") CLK_CAL_RTC_SLOW
#define RTC_CAL_8MD256 _Pragma ("GCC warning \"'RTC_CAL_8MD256' macro is deprecated\"") CLK_CAL_RC_FAST_D256
#define RTC_CAL_32K_XTAL _Pragma ("GCC warning \"'RTC_CAL_32K_XTAL' macro is deprecated\"") CLK_CAL_32K_XTAL
#define RTC_CAL_INTERNAL_OSC _Pragma ("GCC warning \"'RTC_CAL_INTERNAL_OSC' macro is deprecated\"") CLK_CAL_RC_SLOW
/**
* Initialization parameters for rtc_clk_init
@@ -437,8 +432,6 @@ void rtc_clk_apb_freq_update(uint32_t apb_freq);
*/
uint32_t rtc_clk_apb_freq_get(void);
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles);
/**
* @brief Measure RTC slow clock's period, based on main XTAL frequency
*
@@ -452,21 +445,21 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles);
* the check fails, then consider this an invalid 32k clock and return 0. This
* check can filter some jamming signal.
*
* @param cal_clk clock to be measured
* @param cal_clk_sel clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average slow clock period in microseconds, Q13.19 fixed point format,
* or 0 if calibration has timed out
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Measure ratio between XTAL frequency and RTC slow clock frequency
* @param cal_clk slow clock to be measured
* @param cal_clk_sel slow clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average ratio between XTAL frequency and slow clock frequency,
* Q13.19 fixed point format, or 0 if calibration has timed out.
*/
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal_ratio(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Convert time interval from microseconds to RTC_SLOW_CLK cycles
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -190,16 +190,9 @@ static void calibrate_ocode(void)
4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout;
5. set cpu to old-config.
*/
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX;
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk = RTC_CAL_32K_XTAL;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256) {
cal_clk = RTC_CAL_8MD256;
}
uint64_t max_delay_time_us = 10000;
uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100);
uint32_t slow_clk_period = rtc_clk_cal(CLK_CAL_RTC_SLOW, 100);
uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period);
uint64_t cycle0 = rtc_time_get();
uint64_t timeout_cycle = cycle0 + max_delay_cycle;
@@ -29,37 +29,32 @@
/**
* @brief Clock calibration function used by rtc_clk_cal and rtc_clk_cal_ratio
* @param cal_clk which clock to calibrate
* @param cal_clk_sel which clock to calibrate
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
static uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
/* On ESP32C3, choosing RTC_CAL_RTC_MUX results in calibration of
* the 150k RTC clock regardless of the currently selected SLOW_CLK.
* On the ESP32, it used the currently selected SLOW_CLK.
* The following code emulates ESP32 behavior:
*/
if (cal_clk == RTC_CAL_RTC_MUX) {
if (cal_clk_sel == CLK_CAL_RTC_SLOW) {
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk = RTC_CAL_32K_XTAL;
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) {
cal_clk_sel = CLK_CAL_RC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk_sel = CLK_CAL_32K_XTAL;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256) {
cal_clk = RTC_CAL_8MD256;
cal_clk_sel = CLK_CAL_RC_FAST_D256;
}
} else if (cal_clk == RTC_CAL_INTERNAL_OSC) {
cal_clk = RTC_CAL_RTC_MUX;
}
/* Enable requested clock (150k clock is always on) */
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
bool rc_fast_d256_enabled = clk_ll_rc_fast_d256_is_enabled();
if (cal_clk == RTC_CAL_8MD256) {
if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
rtc_clk_8m_enable(true, true);
clk_ll_rc_fast_d256_digi_enable();
}
@@ -77,17 +72,17 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
}
/* Prepare calibration */
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cal_clk);
clk_ll_freq_calulation_set_target(cal_clk_sel);
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
/* Figure out how long to wait for calibration to finish */
/* Set timeout reg and expect time delay*/
uint32_t expected_freq;
if (cal_clk == RTC_CAL_32K_XTAL) {
if (cal_clk_sel == CLK_CAL_32K_XTAL) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_X32K_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_XTAL32K_FREQ_APPROX;
} else if (cal_clk == RTC_CAL_8MD256) {
} else if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_8MD256_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_RC_FAST_D256_FREQ_APPROX;
} else {
@@ -115,11 +110,11 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_8MD256) {
if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
clk_ll_rc_fast_d256_digi_disable();
rtc_clk_8m_enable(rc_fast_enabled, rc_fast_d256_enabled);
}
@@ -127,10 +122,10 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
return cal_val;
}
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal_ratio(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
uint64_t ratio_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT)) / slowclk_cycles;
uint32_t ratio = (uint32_t)(ratio_64 & UINT32_MAX);
return ratio;
@@ -143,13 +138,13 @@ static bool rtc_clk_cal_32k_valid(uint32_t xtal_freq, uint32_t slowclk_cycles, u
return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles);
soc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
if ((cal_clk == RTC_CAL_32K_XTAL) && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
if ((cal_clk_sel == CLK_CAL_32K_XTAL) && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
return 0;
}
@@ -114,19 +114,11 @@ typedef struct rtc_cpu_freq_config_s {
#define RTC_VDDSDIO_TIEH_1_8V 0 //!< TIEH field value for 1.8V VDDSDIO
#define RTC_VDDSDIO_TIEH_3_3V 1 //!< TIEH field value for 3.3V VDDSDIO
/**
* @brief Clock source to be calibrated using rtc_clk_cal function
*
* @note On ESP32C5, the enum values somehow reflects the register field values of PCR_32K_SEL.
*/
typedef enum {
RTC_CAL_RTC_MUX = -1, //!< Currently selected RTC_SLOW_CLK
RTC_CAL_32K_XTAL = 1, //!< External 32kHz XTAL, as one type of 32k clock
RTC_CAL_32K_OSC_SLOW = 2, //!< External slow clock signal input by lp_pad_gpio0, as one type of 32k clock
RTC_CAL_RC_SLOW = 3, //!< Internal 150kHz RC oscillator
RTC_CAL_RC_FAST = 4, //!< Internal 20MHz RC oscillator
RTC_CAL_INVALID_CLK, //!< Clock not available to calibrate
} rtc_cal_sel_t;
#define RTC_CAL_RTC_MUX _Pragma ("GCC warning \"'RTC_CAL_RTC_MUX' macro is deprecated\"") CLK_CAL_RTC_SLOW
#define RTC_CAL_32K_XTAL _Pragma ("GCC warning \"'RTC_CAL_32K_XTAL' macro is deprecated\"") CLK_CAL_32K_XTAL
#define RTC_CAL_32K_OSC_SLOW _Pragma ("GCC warning \"'RTC_CAL_32K_OSC_SLOW' macro is deprecated\"") CLK_CAL_32K_OSC_SLOW
#define RTC_CAL_RC_SLOW _Pragma ("GCC warning \"'RTC_CAL_RC_SLOW' macro is deprecated\"") CLK_CAL_RC_SLOW
#define RTC_CAL_RC_FAST _Pragma ("GCC warning \"'RTC_CAL_RC_FAST' macro is deprecated\"") CLK_CAL_RC_FAST
/**
* Initialization parameters for rtc_clk_init
@@ -352,12 +344,12 @@ uint32_t rtc_clk_apb_freq_get(void);
* the check fails, then consider this an invalid 32k clock and return 0. This
* check can filter some jamming signal.
*
* @param cal_clk clock to be measured
* @param cal_clk_sel clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average slow clock period in microseconds, Q13.19 fixed point format,
* or 0 if calibration has timed out
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Convert time interval from microseconds to RTC_SLOW_CLK cycles
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -38,16 +38,9 @@ static void IRAM_ATTR NOINLINE_ATTR calibrate_ocode(void)
4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout;
5. set cpu to old-config.
*/
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX;
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) {
cal_clk = RTC_CAL_32K_OSC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk = RTC_CAL_32K_XTAL;
}
uint64_t max_delay_time_us = 10000;
uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100);
uint32_t slow_clk_period = rtc_clk_cal(CLK_CAL_RTC_SLOW, 100);
uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period);
uint64_t cycle0 = rtc_time_get();
uint64_t timeout_cycle = cycle0 + max_delay_cycle;
@@ -19,44 +19,46 @@
__attribute__((unused)) static const char *TAG = "rtc_time";
/* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0.
#define CLK_CAL_TIMEOUT_THRES(cal_clk_sel, cycles) ((cal_clk_sel == CLK_CAL_32K_XTAL || cal_clk_sel == CLK_CAL_32K_OSC_SLOW) ? (cycles << 12) : (cycles << 10))
/**
* @brief Clock frequency calculation function used by rtc_clk_cal
*
* Calculation of clock frequency 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.
* clock cycles.
*
* @param cal_clk_sel which clock to calculate frequency
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
#define CLK_CAL_TIMEOUT_THRES(cal_clk, cycles) ((cal_clk == RTC_CAL_32K_XTAL || cal_clk == RTC_CAL_32K_OSC_SLOW) ? (cycles << 12) : (cycles << 10))
static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
static uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles < TIMG_RTC_CALI_MAX_V);
if (cal_clk == RTC_CAL_RTC_MUX) {
if (cal_clk_sel == CLK_CAL_RTC_SLOW) {
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) {
cal_clk = RTC_CAL_RC_SLOW;
cal_clk_sel = CLK_CAL_RC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk = RTC_CAL_32K_XTAL;
cal_clk_sel = CLK_CAL_32K_XTAL;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) {
cal_clk = RTC_CAL_32K_OSC_SLOW;
cal_clk_sel = CLK_CAL_32K_OSC_SLOW;
}
}
if (cal_clk < 0 || cal_clk >= RTC_CAL_INVALID_CLK) {
ESP_EARLY_LOGE(TAG, "clock not supported to be calibrated");
return 0;
}
/* Enable requested clock (150k clock is always on) */
// All clocks on/off takes time to be stable, so we shouldn't frequently enable/disable the clock
// Only enable if originally was disabled, and set back to the disable state after calibration is done
// If the clock is already on, then do nothing
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
bool dig_rc_fast_enabled = clk_ll_rc_fast_digi_is_enabled();
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!rc_fast_enabled) {
rtc_clk_8m_enable(true);
}
@@ -79,8 +81,8 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
/* Prepare calibration */
REG_SET_FIELD(PCR_CTRL_32K_CONF_REG, PCR_32K_SEL, cal_clk);
if (cal_clk == RTC_CAL_RC_FAST) {
clk_ll_freq_calulation_set_target(cal_clk_sel);
if (cal_clk_sel == CLK_CAL_RC_FAST) {
clk_ll_rc_fast_tick_conf();
}
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
@@ -88,11 +90,11 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
/* Figure out how long to wait for calibration to finish */
/* Set timeout reg and expect time delay*/
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, CLK_CAL_TIMEOUT_THRES(cal_clk, slowclk_cycles));
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, CLK_CAL_TIMEOUT_THRES(cal_clk_sel, slowclk_cycles));
uint32_t expected_freq;
if (cal_clk == RTC_CAL_32K_XTAL || cal_clk == RTC_CAL_32K_OSC_SLOW) {
if (cal_clk_sel == CLK_CAL_32K_XTAL || cal_clk_sel == CLK_CAL_32K_OSC_SLOW) {
expected_freq = SOC_CLK_XTAL32K_FREQ_APPROX;
} else if (cal_clk == RTC_CAL_RC_FAST) {
} else if (cal_clk_sel == CLK_CAL_RC_FAST) {
expected_freq = SOC_CLK_RC_FAST_FREQ_APPROX >> CLK_LL_RC_FAST_CALIB_TICK_DIV_BITS;
} else {
expected_freq = SOC_CLK_RC_SLOW_FREQ_APPROX;
@@ -111,7 +113,7 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
/*The Fosc CLK of calibration circuit is divided by a factor, k.
So we need to multiply the frequency of the FOSC by k times.*/
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
cal_val = cal_val >> CLK_LL_RC_FAST_CALIB_TICK_DIV_BITS;
}
break;
@@ -125,11 +127,11 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
clk_ll_enable_timergroup_rtc_calibration_clock(false);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!dig_rc_fast_enabled) {
rtc_dig_clk8m_disable();
}
@@ -148,19 +150,19 @@ static bool rtc_clk_cal_32k_valid(uint32_t xtal_freq, uint32_t slowclk_cycles, u
return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
/*The Fosc CLK of calibration circuit is divided by a factor, k.
So we need to divide the calibrate cycles of the FOSC by k to
avoid excessive calibration time.*/
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
slowclk_cycles = slowclk_cycles >> CLK_LL_RC_FAST_CALIB_TICK_DIV_BITS;
}
assert(slowclk_cycles);
soc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
if (cal_clk == RTC_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
if (cal_clk_sel == CLK_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
return 0;
}
@@ -12,24 +12,13 @@ choice RTC_CLK_SRC
config RTC_CLK_SRC_EXT_OSC
bool "External 32 kHz oscillator at 32K_XP pin"
select ESP_SYSTEM_RTC_EXT_OSC
config RTC_CLK_SRC_INT_RC32K
bool "Internal 32 kHz RC oscillator (NOT RECOMMENDED TO USE, READ DOCS FIRST)"
depends on RTC_CLK_SRC_USE_DANGEROUS_RC32K_ALLOWED
help
To be able to select this option, please select `RTC_CLK_SRC_USE_DANGEROUS_RC32K_ALLOWED` first.
This option will be removed in IDF v6.0.
endchoice
config RTC_CLK_SRC_USE_DANGEROUS_RC32K_ALLOWED
bool "Confirm to use the unrecommended 32 kHz RC oscillator (READ DOCS FIRST)"
help
Internal RC32K clock is unstable at extreme temperatures and is not recommended for use.
config RTC_CLK_CAL_CYCLES
int "Number of cycles for RTC_SLOW_CLK calibration"
default 3000 if RTC_CLK_SRC_EXT_CRYS || RTC_CLK_SRC_EXT_OSC || RTC_CLK_SRC_INT_RC32K
default 3000 if RTC_CLK_SRC_EXT_CRYS || RTC_CLK_SRC_EXT_OSC
default 1024 if RTC_CLK_SRC_INT_RC
range 0 8190 if RTC_CLK_SRC_EXT_CRYS || RTC_CLK_SRC_EXT_OSC || RTC_CLK_SRC_INT_RC32K
range 0 8190 if RTC_CLK_SRC_EXT_CRYS || RTC_CLK_SRC_EXT_OSC
range 0 32766 if RTC_CLK_SRC_INT_RC
help
When the startup code initializes RTC_SLOW_CLK, it can perform
@@ -120,22 +120,12 @@ typedef struct rtc_cpu_freq_config_s {
#define RTC_VDDSDIO_TIEH_1_8V 0 //!< TIEH field value for 1.8V VDDSDIO
#define RTC_VDDSDIO_TIEH_3_3V 1 //!< TIEH field value for 3.3V VDDSDIO
/**
* @brief Clock source to be calibrated using rtc_clk_cal function
*
* @note On previous targets, the enum values somehow reflects the register field values of TIMG_RTC_CALI_CLK_SEL
* However, this is not true on ESP32C6. The conversion to register field values is explicitly done in
* rtc_clk_cal_internal
*/
typedef enum {
RTC_CAL_RTC_MUX = -1, //!< Currently selected RTC_SLOW_CLK
RTC_CAL_RC_SLOW = SOC_RTC_SLOW_CLK_SRC_RC_SLOW, //!< Internal 150kHz RC oscillator
RTC_CAL_RC32K = SOC_RTC_SLOW_CLK_SRC_RC32K, //!< Internal 32kHz RC oscillator, as one type of 32k clock
RTC_CAL_32K_XTAL = SOC_RTC_SLOW_CLK_SRC_XTAL32K, //!< External 32kHz XTAL, as one type of 32k clock
RTC_CAL_32K_OSC_SLOW = SOC_RTC_SLOW_CLK_SRC_OSC_SLOW, //!< External slow clock signal input by lp_pad_gpio0, as one type of 32k clock
RTC_CAL_RC_FAST //!< Internal 20MHz RC oscillator
} rtc_cal_sel_t;
#define RTC_CAL_RTC_MUX _Pragma ("GCC warning \"'RTC_CAL_RTC_MUX' macro is deprecated\"") CLK_CAL_RTC_SLOW
#define RTC_CAL_RC_SLOW _Pragma ("GCC warning \"'RTC_CAL_RC_SLOW' macro is deprecated\"") CLK_CAL_RC_SLOW
#define RTC_CAL_RC32K _Pragma ("GCC warning \"'RTC_CAL_RC32K' macro is deprecated\"") CLK_CAL_RC32K
#define RTC_CAL_32K_XTAL _Pragma ("GCC warning \"'RTC_CAL_32K_XTAL' macro is deprecated\"") CLK_CAL_32K_XTAL
#define RTC_CAL_32K_OSC_SLOW _Pragma ("GCC warning \"'RTC_CAL_32K_OSC_SLOW' macro is deprecated\"") CLK_CAL_32K_OSC_SLOW
#define RTC_CAL_RC_FAST _Pragma ("GCC warning \"'RTC_CAL_RC_FAST' macro is deprecated\"") CLK_CAL_RC_FAST
/**
* Initialization parameters for rtc_clk_init
@@ -381,12 +371,12 @@ uint32_t rtc_clk_apb_freq_get(void);
* the check fails, then consider this an invalid 32k clock and return 0. This
* check can filter some jamming signal.
*
* @param cal_clk clock to be measured
* @param cal_clk_sel clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average slow clock period in microseconds, Q13.19 fixed point format,
* or 0 if calibration has timed out
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Convert time interval from microseconds to RTC_SLOW_CLK cycles
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -37,16 +37,9 @@ static void calibrate_ocode(void)
4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout;
5. set cpu to old-config.
*/
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX;
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) {
cal_clk = RTC_CAL_32K_OSC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk = RTC_CAL_32K_XTAL;
}
uint64_t max_delay_time_us = 10000;
uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100);
uint32_t slow_clk_period = rtc_clk_cal(CLK_CAL_RTC_SLOW, 100);
uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period);
uint64_t cycle0 = rtc_time_get();
uint64_t timeout_cycle = cycle0 + max_delay_cycle;
@@ -20,31 +20,10 @@
__attribute__((unused)) static const char *TAG = "rtc_time";
/* 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.
*
* Slow clock calibration feature has two modes of operation: one-off and cycling.
* In cycling mode (which is enabled by default on SoC reset), counting of XTAL
* cycles within RTC_SLOW_CLK cycle is done continuously. Cycling mode is enabled
* using TIMG_RTC_CALI_START_CYCLING bit. In one-off mode counting is performed
* once, and TIMG_RTC_CALI_RDY bit is set when counting is done. One-off mode is
* enabled using TIMG_RTC_CALI_START bit.
*/
/* On ESP32C6, TIMG_RTC_CALI_CLK_SEL can config to 0, 1, 2, 3
* 0 or 3: calibrate RC_SLOW clock
* 1: calibrate RC_FAST clock
* 2: calibrate 32K clock, which 32k depends on reg_32k_sel: 0: Internal 32 kHz RC oscillator, 1: External 32 kHz XTAL, 2: External 32kHz clock input by lp_pad_gpio0
*/
#define TIMG_RTC_CALI_CLK_SEL_RC_SLOW 0
#define TIMG_RTC_CALI_CLK_SEL_RC_FAST 1
#define TIMG_RTC_CALI_CLK_SEL_32K 2
/**
* @brief Clock calibration function used by rtc_clk_cal
* @brief Clock frequency calculation function used by rtc_clk_cal
*
* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0.
* Calculation 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.
*
@@ -55,42 +34,39 @@ __attribute__((unused)) static const char *TAG = "rtc_time";
* once, and TIMG_RTC_CALI_RDY bit is set when counting is done. One-off mode is
* enabled using TIMG_RTC_CALI_START bit.
*
* @param cal_clk which clock to calibrate
* @param cal_clk_sel which clock to calculate frequency
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
static uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles < TIMG_RTC_CALI_MAX_V);
uint32_t cali_clk_sel = 0;
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
soc_rtc_slow_clk_src_t old_32k_cal_clk_sel = clk_ll_32k_calibration_get_target();
if (cal_clk == RTC_CAL_RTC_MUX) {
cal_clk = (rtc_cal_sel_t)slow_clk_src;
if (cal_clk_sel == CLK_CAL_RTC_SLOW) {
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) {
cal_clk_sel = CLK_CAL_RC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) {
cal_clk_sel = CLK_CAL_32K_OSC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk_sel = CLK_CAL_32K_XTAL;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC32K) {
cal_clk_sel = CLK_CAL_RC32K;
}
}
if (cal_clk == RTC_CAL_RC_FAST) {
cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_FAST;
} else if (cal_clk == RTC_CAL_RC_SLOW) {
cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_SLOW;
} else {
cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_32K;
clk_ll_32k_calibration_set_target((soc_rtc_slow_clk_src_t)cal_clk);
}
/* Enable requested clock (150k clock is always on) */
// All clocks on/off takes time to be stable, so we shouldn't frequently enable/disable the clock
// Only enable if originally was disabled, and set back to the disable state after calibration is done
// If the clock is already on, then do nothing
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
bool dig_rc_fast_enabled = clk_ll_rc_fast_digi_is_enabled();
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!rc_fast_enabled) {
rtc_clk_8m_enable(true);
}
@@ -101,7 +77,7 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
bool rc32k_enabled = clk_ll_rc32k_is_enabled();
bool dig_rc32k_enabled = clk_ll_rc32k_digi_is_enabled();
if (cal_clk == RTC_CAL_RC32K) {
if (cal_clk_sel == CLK_CAL_RC32K) {
if (!rc32k_enabled) {
rtc_clk_rc32k_enable(true);
}
@@ -124,8 +100,8 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
/* Prepare calibration */
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cali_clk_sel);
if (cali_clk_sel == TIMG_RTC_CALI_CLK_SEL_RC_FAST) {
clk_ll_freq_calulation_set_target(cal_clk_sel);
if (cal_clk_sel == CLK_CAL_RC_FAST) {
clk_ll_rc_fast_tick_conf();
}
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
@@ -134,10 +110,10 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
/* Set timeout reg and expect time delay*/
uint32_t expected_freq;
if (cali_clk_sel == TIMG_RTC_CALI_CLK_SEL_32K) {
if (cal_clk_sel == CLK_CAL_32K_XTAL || cal_clk_sel == CLK_CAL_32K_OSC_SLOW || cal_clk_sel == CLK_CAL_RC32K) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_32K_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_XTAL32K_FREQ_APPROX;
} else if (cali_clk_sel == TIMG_RTC_CALI_CLK_SEL_RC_FAST) {
} else if (cal_clk_sel == CLK_CAL_RC_FAST) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_FAST_CLK_20M_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_RC_FAST_FREQ_APPROX;
if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 1)) {
@@ -165,7 +141,7 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
And the 32-divider belongs to REF_TICK module, so we need to enable its clock during
calibration. */
if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 1)) {
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
cal_val = cal_val >> CLK_LL_RC_FAST_CALIB_TICK_DIV_BITS;
CLEAR_PERI_REG_MASK(PCR_CTRL_TICK_CONF_REG, PCR_TICK_ENABLE);
}
@@ -180,11 +156,11 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!dig_rc_fast_enabled) {
rtc_dig_clk8m_disable();
}
@@ -193,7 +169,7 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
}
if (cal_clk == RTC_CAL_RC32K) {
if (cal_clk_sel == CLK_CAL_RC32K) {
if (!dig_rc32k_enabled) {
clk_ll_rc32k_digi_disable();
}
@@ -202,11 +178,6 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
}
// Always set back the calibration 32kHz clock selection
if (old_32k_cal_clk_sel != SOC_RTC_SLOW_CLK_SRC_INVALID) {
clk_ll_32k_calibration_set_target(old_32k_cal_clk_sel);
}
return cal_val;
}
@@ -217,7 +188,7 @@ static bool rtc_clk_cal_32k_valid(uint32_t xtal_freq, uint32_t slowclk_cycles, u
return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles);
soc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
@@ -226,15 +197,15 @@ uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
So we need to divide the calibrate cycles of the FOSC for ECO1 and above chips by 32 to
avoid excessive calibration time.*/
if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 1)) {
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
slowclk_cycles = slowclk_cycles >> CLK_LL_RC_FAST_CALIB_TICK_DIV_BITS;
SET_PERI_REG_MASK(PCR_CTRL_TICK_CONF_REG, PCR_TICK_ENABLE);
}
}
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
if (cal_clk == RTC_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
return 0;
}
@@ -114,19 +114,11 @@ typedef struct rtc_cpu_freq_config_s {
#define RTC_VDDSDIO_TIEH_1_8V 0 //!< TIEH field value for 1.8V VDDSDIO
#define RTC_VDDSDIO_TIEH_3_3V 1 //!< TIEH field value for 3.3V VDDSDIO
/**
* @brief Clock source to be calibrated using rtc_clk_cal function
*
* @note On ESP32C61, the enum values somehow reflects the register field values of PCR_32K_SEL.
*/
typedef enum {
RTC_CAL_RTC_MUX = -1, //!< Currently selected RTC_SLOW_CLK
RTC_CAL_32K_XTAL = 1, //!< External 32kHz XTAL, as one type of 32k clock
RTC_CAL_32K_OSC_SLOW = 2, //!< External slow clock signal input by lp_pad_gpio0, as one type of 32k clock
RTC_CAL_RC_SLOW = 3, //!< Internal 150kHz RC oscillator
RTC_CAL_RC_FAST = 4, //!< Internal 20MHz RC oscillator
RTC_CAL_INVALID_CLK, //!< Clock not available to calibrate
} rtc_cal_sel_t;
#define RTC_CAL_RTC_MUX _Pragma ("GCC warning \"'RTC_CAL_RTC_MUX' macro is deprecated\"") CLK_CAL_RTC_SLOW
#define RTC_CAL_32K_XTAL _Pragma ("GCC warning \"'RTC_CAL_32K_XTAL' macro is deprecated\"") CLK_CAL_32K_XTAL
#define RTC_CAL_32K_OSC_SLOW _Pragma ("GCC warning \"'RTC_CAL_32K_OSC_SLOW' macro is deprecated\"") CLK_CAL_32K_OSC_SLOW
#define RTC_CAL_RC_SLOW _Pragma ("GCC warning \"'RTC_CAL_RC_SLOW' macro is deprecated\"") CLK_CAL_RC_SLOW
#define RTC_CAL_RC_FAST _Pragma ("GCC warning \"'RTC_CAL_RC_FAST' macro is deprecated\"") CLK_CAL_RC_FAST
/**
* Initialization parameters for rtc_clk_init
@@ -350,12 +342,12 @@ uint32_t rtc_clk_apb_freq_get(void);
* the check fails, then consider this an invalid 32k clock and return 0. This
* check can filter some jamming signal.
*
* @param cal_clk clock to be measured
* @param cal_clk_sel clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average slow clock period in microseconds, Q13.19 fixed point format,
* or 0 if calibration has timed out
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Convert time interval from microseconds to RTC_SLOW_CLK cycles
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -37,16 +37,9 @@ static void IRAM_ATTR NOINLINE_ATTR calibrate_ocode(void)
4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout;
5. set cpu to old-config.
*/
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX;
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) {
cal_clk = RTC_CAL_32K_OSC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk = RTC_CAL_32K_XTAL;
}
uint64_t max_delay_time_us = 10000;
uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100);
uint32_t slow_clk_period = rtc_clk_cal(CLK_CAL_RTC_SLOW, 100);
uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period);
uint64_t cycle0 = rtc_time_get();
uint64_t timeout_cycle = cycle0 + max_delay_cycle;
@@ -18,44 +18,46 @@
__attribute__((unused)) static const char *TAG = "rtc_time";
/* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0.
#define CLK_CAL_TIMEOUT_THRES(cal_clk_sel, cycles) ((cal_clk_sel == CLK_CAL_32K_XTAL || cal_clk_sel == CLK_CAL_32K_OSC_SLOW) ? (cycles << 12) : (cycles << 10))
/**
* @brief Clock frequency calculation function used by rtc_clk_cal
*
* Calculation of clock frequency 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.
* clock cycles.
*
* @param cal_clk_sel which clock to calculate frequency
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
#define CLK_CAL_TIMEOUT_THRES(cal_clk, cycles) ((cal_clk == RTC_CAL_32K_XTAL || cal_clk == RTC_CAL_32K_OSC_SLOW) ? (cycles << 12) : (cycles << 10))
static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
static uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles < TIMG_RTC_CALI_MAX_V);
if (cal_clk == RTC_CAL_RTC_MUX) {
if (cal_clk_sel == CLK_CAL_RTC_SLOW) {
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) {
cal_clk = RTC_CAL_RC_SLOW;
cal_clk_sel = CLK_CAL_RC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk = RTC_CAL_32K_XTAL;
cal_clk_sel = CLK_CAL_32K_XTAL;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) {
cal_clk = RTC_CAL_32K_OSC_SLOW;
cal_clk_sel = CLK_CAL_32K_OSC_SLOW;
}
}
if (cal_clk < 0 || cal_clk >= RTC_CAL_INVALID_CLK) {
ESP_EARLY_LOGE(TAG, "clock not supported to be calibrated");
return 0;
}
/* Enable requested clock (150k clock is always on) */
// All clocks on/off takes time to be stable, so we shouldn't frequently enable/disable the clock
// Only enable if originally was disabled, and set back to the disable state after calibration is done
// If the clock is already on, then do nothing
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
bool dig_rc_fast_enabled = clk_ll_rc_fast_digi_is_enabled();
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!rc_fast_enabled) {
rtc_clk_8m_enable(true);
}
@@ -78,8 +80,8 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
/* Prepare calibration */
REG_SET_FIELD(PCR_CTRL_32K_CONF_REG, PCR_32K_SEL, cal_clk);
if (cal_clk == RTC_CAL_RC_FAST) {
clk_ll_freq_calulation_set_target(cal_clk_sel);
if (cal_clk_sel == CLK_CAL_RC_FAST) {
clk_ll_rc_fast_tick_conf();
}
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
@@ -87,11 +89,11 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
/* Figure out how long to wait for calibration to finish */
/* Set timeout reg and expect time delay*/
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, CLK_CAL_TIMEOUT_THRES(cal_clk, slowclk_cycles));
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, CLK_CAL_TIMEOUT_THRES(cal_clk_sel, slowclk_cycles));
uint32_t expected_freq;
if (cal_clk == RTC_CAL_32K_XTAL || cal_clk == RTC_CAL_32K_OSC_SLOW) {
if (cal_clk_sel == CLK_CAL_32K_XTAL || cal_clk_sel == CLK_CAL_32K_OSC_SLOW) {
expected_freq = SOC_CLK_XTAL32K_FREQ_APPROX;
} else if (cal_clk == RTC_CAL_RC_FAST) {
} else if (cal_clk_sel == CLK_CAL_RC_FAST) {
expected_freq = SOC_CLK_RC_FAST_FREQ_APPROX >> CLK_LL_RC_FAST_CALIB_TICK_DIV_BITS;
} else {
expected_freq = SOC_CLK_RC_SLOW_FREQ_APPROX;
@@ -110,7 +112,7 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
/*The Fosc CLK of calibration circuit is divided by a factor, k.
So we need to multiply the frequency of the FOSC by k times.*/
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
cal_val = cal_val >> CLK_LL_RC_FAST_CALIB_TICK_DIV_BITS;
}
break;
@@ -123,11 +125,11 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!dig_rc_fast_enabled) {
rtc_dig_clk8m_disable();
}
@@ -146,20 +148,20 @@ static bool rtc_clk_cal_32k_valid(uint32_t xtal_freq, uint32_t slowclk_cycles, u
return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
/*The Fosc CLK of calibration circuit is divided by a factor, k.
So we need to divide the calibrate cycles of the FOSC by k to
avoid excessive calibration time.*/
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
slowclk_cycles = slowclk_cycles >> CLK_LL_RC_FAST_CALIB_TICK_DIV_BITS;
}
assert(slowclk_cycles);
soc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
if (cal_clk == RTC_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
return 0;
}
@@ -123,21 +123,12 @@ typedef struct rtc_cpu_freq_config_s {
#define RTC_VDDSDIO_TIEH_1_8V 0 //!< TIEH field value for 1.8V VDDSDIO
#define RTC_VDDSDIO_TIEH_3_3V 1 //!< TIEH field value for 3.3V VDDSDIO
/**
* @brief Clock source to be calibrated using rtc_clk_cal function
*
* @note On previous targets, the enum values somehow reflects the register field values of TIMG_RTC_CALI_CLK_SEL
* However, this is not true on ESP32H2. The conversion to register field values is explicitly done in
* rtc_clk_cal_internal
*/
typedef enum {
RTC_CAL_RTC_MUX = -1, //!< Currently selected RTC_SLOW_CLK
RTC_CAL_RC_SLOW = SOC_RTC_SLOW_CLK_SRC_RC_SLOW, //!< Internal 150kHz RC oscillator
RTC_CAL_RC32K = SOC_RTC_SLOW_CLK_SRC_RC32K, //!< Internal 32kHz RC oscillator, as one type of 32k clock
RTC_CAL_32K_XTAL = SOC_RTC_SLOW_CLK_SRC_XTAL32K, //!< External 32kHz XTAL, as one type of 32k clock
RTC_CAL_32K_OSC_SLOW = SOC_RTC_SLOW_CLK_SRC_OSC_SLOW, //!< External slow clock signal input by lp_pad_gpiox, as one type of 32k clock
RTC_CAL_RC_FAST //!< Internal 8MHz RC oscillator
} rtc_cal_sel_t;
#define RTC_CAL_RTC_MUX _Pragma ("GCC warning \"'RTC_CAL_RTC_MUX' macro is deprecated\"") CLK_CAL_RTC_SLOW
#define RTC_CAL_RC_SLOW _Pragma ("GCC warning \"'RTC_CAL_RC_SLOW' macro is deprecated\"") CLK_CAL_RC_SLOW
#define RTC_CAL_RC32K _Pragma ("GCC warning \"'RTC_CAL_RC32K' macro is deprecated\"") CLK_CAL_RC32K
#define RTC_CAL_32K_XTAL _Pragma ("GCC warning \"'RTC_CAL_32K_XTAL' macro is deprecated\"") CLK_CAL_32K_XTAL
#define RTC_CAL_32K_OSC_SLOW _Pragma ("GCC warning \"'RTC_CAL_32K_OSC_SLOW' macro is deprecated\"") CLK_CAL_32K_OSC_SLOW
#define RTC_CAL_RC_FAST _Pragma ("GCC warning \"'RTC_CAL_RC_FAST' macro is deprecated\"") CLK_CAL_RC_FAST
/**
* Initialization parameters for rtc_clk_init
@@ -379,12 +370,12 @@ uint32_t rtc_clk_apb_freq_get(void);
* 32k XTAL is being calibrated, but the oscillator has not started up (due to
* incorrect loading capacitance, board design issue, or lack of 32 XTAL on board).
*
* @param cal_clk clock to be measured
* @param cal_clk_sel clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average slow clock period in microseconds, Q13.19 fixed point format,
* or 0 if calibration has timed out
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Convert time interval from microseconds to RTC_SLOW_CLK cycles
@@ -20,31 +20,10 @@
__attribute__((unused)) static const char *TAG = "rtc_time";
/* 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.
*
* Slow clock calibration feature has two modes of operation: one-off and cycling.
* In cycling mode (which is enabled by default on SoC reset), counting of XTAL
* cycles within RTC_SLOW_CLK cycle is done continuously. Cycling mode is enabled
* using TIMG_RTC_CALI_START_CYCLING bit. In one-off mode counting is performed
* once, and TIMG_RTC_CALI_RDY bit is set when counting is done. One-off mode is
* enabled using TIMG_RTC_CALI_START bit.
*/
/* On ESP32H2, TIMG_RTC_CALI_CLK_SEL can config to 0, 1, 2, 3
* 0 or 3: calibrate RC_SLOW clock
* 1: calibrate RC_FAST clock
* 2: calibrate 32K clock, which 32k depends on reg_32k_sel: 0: Internal 32 kHz RC oscillator, 1: External 32 kHz XTAL, 2: External 32kHz clock input by gpio13
*/
#define TIMG_RTC_CALI_CLK_SEL_RC_SLOW 0
#define TIMG_RTC_CALI_CLK_SEL_RC_FAST 1
#define TIMG_RTC_CALI_CLK_SEL_32K 2
/**
* @brief Clock calibration function used by rtc_clk_cal
* @brief Clock frequency calculation function used by rtc_clk_cal
*
* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0.
* Calculation 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.
*
@@ -55,42 +34,39 @@ __attribute__((unused)) static const char *TAG = "rtc_time";
* once, and TIMG_RTC_CALI_RDY bit is set when counting is done. One-off mode is
* enabled using TIMG_RTC_CALI_START bit.
*
* @param cal_clk which clock to calibrate
* @param cal_clk_sel which clock to calculate frequency
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
static uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles < TIMG_RTC_CALI_MAX_V);
uint32_t cali_clk_sel = 0;
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
soc_rtc_slow_clk_src_t old_32k_cal_clk_sel = clk_ll_32k_calibration_get_target();
if (cal_clk == RTC_CAL_RTC_MUX) {
cal_clk = (rtc_cal_sel_t)slow_clk_src;
if (cal_clk_sel == CLK_CAL_RTC_SLOW) {
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) {
cal_clk_sel = CLK_CAL_RC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_OSC_SLOW) {
cal_clk_sel = CLK_CAL_32K_OSC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk_sel = CLK_CAL_32K_XTAL;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC32K) {
cal_clk_sel = CLK_CAL_RC32K;
}
}
if (cal_clk == RTC_CAL_RC_FAST) {
cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_FAST;
} else if (cal_clk == RTC_CAL_RC_SLOW) {
cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_RC_SLOW;
} else {
cali_clk_sel = TIMG_RTC_CALI_CLK_SEL_32K;
clk_ll_32k_calibration_set_target((soc_rtc_slow_clk_src_t)cal_clk);
}
/* Enable requested clock (150k clock is always on) */
// All clocks on/off takes time to be stable, so we shouldn't frequently enable/disable the clock
// Only enable if originally was disabled, and set back to the disable state after calibration is done
// If the clock is already on, then do nothing
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
bool dig_rc_fast_enabled = clk_ll_rc_fast_digi_is_enabled();
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!rc_fast_enabled) {
rtc_clk_8m_enable(true);
}
@@ -101,7 +77,7 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
bool rc32k_enabled = clk_ll_rc32k_is_enabled();
bool dig_rc32k_enabled = clk_ll_rc32k_digi_is_enabled();
if (cal_clk == RTC_CAL_RC32K) {
if (cal_clk_sel == CLK_CAL_RC32K) {
if (!rc32k_enabled) {
rtc_clk_rc32k_enable(true);
}
@@ -124,8 +100,8 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
/* Prepare calibration */
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cali_clk_sel);
if (cali_clk_sel == TIMG_RTC_CALI_CLK_SEL_RC_FAST) {
clk_ll_freq_calulation_set_target(cal_clk_sel);
if (cal_clk_sel == CLK_CAL_RC_FAST) {
clk_ll_rc_fast_tick_conf();
}
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
@@ -134,10 +110,10 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
/* Set timeout reg and expect time delay*/
uint32_t expected_freq;
if (cali_clk_sel == TIMG_RTC_CALI_CLK_SEL_32K) {
if (cal_clk_sel == CLK_CAL_32K_XTAL || cal_clk_sel == CLK_CAL_32K_OSC_SLOW || cal_clk_sel == CLK_CAL_RC32K) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_32K_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_XTAL32K_FREQ_APPROX;
} else if (cali_clk_sel == TIMG_RTC_CALI_CLK_SEL_RC_FAST) {
} else if (cal_clk_sel == CLK_CAL_RC_FAST) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_FAST_CLK_8M_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_RC_FAST_FREQ_APPROX;
if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 2)) {
@@ -165,7 +141,7 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
And the 32-divider belongs to REF_TICK module, so we need to enable its clock during
calibration. */
if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 2)) {
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
cal_val = cal_val >> CLK_LL_RC_FAST_CALIB_TICK_DIV_BITS;
CLEAR_PERI_REG_MASK(PCR_CTRL_TICK_CONF_REG, PCR_TICK_ENABLE);
}
@@ -180,11 +156,11 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!dig_rc_fast_enabled) {
rtc_dig_clk8m_disable();
}
@@ -193,7 +169,7 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
}
if (cal_clk == RTC_CAL_RC32K) {
if (cal_clk_sel == CLK_CAL_RC32K) {
if (!dig_rc32k_enabled) {
clk_ll_rc32k_digi_disable();
}
@@ -202,11 +178,6 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
}
// Always set back the calibration 32kHz clock selection
if (old_32k_cal_clk_sel != SOC_RTC_SLOW_CLK_SRC_INVALID) {
clk_ll_32k_calibration_set_target(old_32k_cal_clk_sel);
}
return cal_val;
}
@@ -217,7 +188,7 @@ static bool rtc_clk_cal_32k_valid(uint32_t xtal_freq, uint32_t slowclk_cycles, u
return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles);
soc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
@@ -226,15 +197,15 @@ uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
So we need to divide the calibrate cycles of the FOSC for ECO1 and above chips by 32 to
avoid excessive calibration time.*/
if (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 2)) {
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
slowclk_cycles = slowclk_cycles >> CLK_LL_RC_FAST_CALIB_TICK_DIV_BITS;
SET_PERI_REG_MASK(PCR_CTRL_TICK_CONF_REG, PCR_TICK_ENABLE);
}
}
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
if (cal_clk == RTC_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
return 0;
}
@@ -105,20 +105,6 @@ typedef struct rtc_cpu_freq_config_s {
#define RTC_CLK_CAL_FRACT 19 //!< Number of fractional bits in values returned by rtc_clk_cal
/**
* @brief Clock source to be calibrated using rtc_clk_cal function
*
* @note On previous targets, the enum values somehow reflects the register field values of TIMG_RTC_CALI_CLK_SEL
* However, this is not true on ESP32H21. The conversion to register field values is explicitly done internally
*/
typedef enum {
RTC_CAL_RTC_MUX = -1, //!< Currently selected RTC_SLOW_CLK
RTC_CAL_RC_SLOW = CLK_CAL_RC_SLOW, //!< Internal 600kHz RC oscillator
RTC_CAL_32K_XTAL = CLK_CAL_32K_XTAL, //!< External 32kHz XTAL, as one type of 32k clock
RTC_CAL_32K_OSC_SLOW = CLK_CAL_32K_OSC_SLOW, //!< External slow clock signal input by gpio11, as one type of 32k clock
RTC_CAL_RC_FAST = CLK_CAL_RC_FAST, //!< Internal 20MHz RC oscillator
} rtc_cal_sel_t;
/**
* Initialization parameters for rtc_clk_init
*/
@@ -328,12 +314,12 @@ uint32_t rtc_clk_apb_freq_get(void);
* the check fails, then consider this an invalid 32k clock and return 0. This
* check can filter some jamming signal.
*
* @param cal_clk clock to be measured
* @param cal_clk_sel clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average slow clock period in microseconds, Q13.19 fixed point format,
* or 0 if calibration has timed out
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Convert time interval from microseconds to RTC_SLOW_CLK cycles
@@ -18,31 +18,38 @@
__attribute__((unused)) static const char *TAG = "rtc_time";
/* 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.
*/
#define RTC_SLOW_CLK_600K_CAL_TIMEOUT_THRES(cycles) (cycles << 10)
#define RTC_SLOW_CLK_32K_CAL_TIMEOUT_THRES(cycles) (cycles << 12)
#define RTC_FAST_CLK_20M_CAL_TIMEOUT_THRES(cycles) (TIMG_RTC_CALI_TIMEOUT_THRES_V) // Just use the max timeout thres value
static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
/**
* @brief Clock frequency calculation function used by rtc_clk_cal
*
* Calculation of clock frequency is performed using a special feature of TIMG0.
* This feature counts the number of XTAL clock cycles within a given number of
* clock cycles.
*
* @param cal_clk_sel which clock to calculate frequency
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
static uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles < TIMG_RTC_CALI_MAX_V);
bool is_cal_clk_rtc_slow = false;
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
soc_clk_calibration_clk_src_t cali_clk_sel = (soc_clk_calibration_clk_src_t)cal_clk;
if (cal_clk == RTC_CAL_RTC_MUX) {
if (cal_clk_sel == CLK_CAL_RTC_SLOW) {
is_cal_clk_rtc_slow = true;
switch (slow_clk_src) {
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW_D4:
cali_clk_sel = CLK_CAL_RC_SLOW;
cal_clk_sel = CLK_CAL_RC_SLOW;
break;
case SOC_RTC_SLOW_CLK_SRC_XTAL32K:
cali_clk_sel = CLK_CAL_32K_XTAL;
cal_clk_sel = CLK_CAL_32K_XTAL;
break;
case SOC_RTC_SLOW_CLK_SRC_OSC_SLOW:
cali_clk_sel = CLK_CAL_32K_OSC_SLOW;
cal_clk_sel = CLK_CAL_32K_OSC_SLOW;
break;
default:
ESP_EARLY_LOGE(TAG, "clock not supported to be calibrated");
@@ -55,13 +62,13 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
// Only enable if originally was disabled, and set back to the disable state after calibration is done
// If the clock is already on, then do nothing
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
bool dig_rc_fast_enabled = clk_ll_rc_fast_digi_is_enabled();
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!rc_fast_enabled) {
rtc_clk_8m_enable(true);
}
@@ -84,8 +91,8 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
/* Prepare calibration */
clk_ll_calibration_set_target(cali_clk_sel);
if (cali_clk_sel == CLK_CAL_RC_FAST) {
clk_ll_freq_calulation_set_target(cal_clk_sel);
if (cal_clk_sel == CLK_CAL_RC_FAST) {
clk_ll_rc_fast_tick_conf();
}
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
@@ -94,10 +101,10 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
/* Set timeout reg and expect time delay*/
uint32_t expected_freq;
if (cali_clk_sel == CLK_CAL_32K_XTAL || cali_clk_sel == CLK_CAL_32K_OSC_SLOW) {
if (cal_clk_sel == CLK_CAL_32K_XTAL || cal_clk_sel == CLK_CAL_32K_OSC_SLOW) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_32K_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_XTAL32K_FREQ_APPROX;
} else if (cali_clk_sel == CLK_CAL_RC_FAST) {
} else if (cal_clk_sel == CLK_CAL_RC_FAST) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_FAST_CLK_20M_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_RC_FAST_FREQ_APPROX >> CLK_LL_RC_FAST_CALIB_TICK_DIV_BITS;
} else {
@@ -118,7 +125,7 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
/* The Fosc CLK of calibration circuit is divided by a factor, k.
So we need to multiply the frequency of the FOSC by k times. */
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
cal_val = cal_val >> CLK_LL_RC_FAST_CALIB_TICK_DIV_BITS;
}
break;
@@ -131,11 +138,11 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!dig_rc_fast_enabled) {
rtc_dig_clk8m_disable();
}
@@ -144,7 +151,7 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
}
if (cal_clk == RTC_CAL_RTC_MUX && slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW_D4) {
if (is_cal_clk_rtc_slow && slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW_D4) {
// calibration was done on RC_SLOW clock, but rtc_slow_clk src is RC_SLOW_D4, so we need to multiply the cal_val by 4
cal_val *= 4;
}
@@ -159,20 +166,20 @@ static bool rtc_clk_cal_32k_valid(uint32_t xtal_freq, uint32_t slowclk_cycles, u
return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
/* The Fosc CLK of calibration circuit is divided by a factor, k.
So we need to divide the calibrate cycles of the FOSC by k to
avoid excessive calibration time. */
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
slowclk_cycles = slowclk_cycles >> CLK_LL_RC_FAST_CALIB_TICK_DIV_BITS;
}
assert(slowclk_cycles);
soc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
if (cal_clk == RTC_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
return 0;
}
@@ -105,20 +105,6 @@ typedef struct rtc_cpu_freq_config_s {
#define RTC_CLK_CAL_FRACT 19 //!< Number of fractional bits in values returned by rtc_clk_cal
/**
* @brief Clock source to be calibrated using rtc_clk_cal function
*
* @note On previous targets, the enum values somehow reflects the register field values of TIMG_RTC_CALI_CLK_SEL
* However, this is not true on ESP32H4. The conversion to register field values is explicitly done internally
*/
typedef enum {
RTC_CAL_RTC_MUX = -1, //!< Currently selected RTC_SLOW_CLK
RTC_CAL_RC_SLOW = CLK_CAL_RC_SLOW, //!< Internal 600kHz RC oscillator
RTC_CAL_32K_XTAL = CLK_CAL_32K_XTAL, //!< External 32kHz XTAL, as one type of 32k clock
RTC_CAL_32K_OSC_SLOW = CLK_CAL_32K_OSC_SLOW, //!< External slow clock signal input by gpio5, as one type of 32k clock
RTC_CAL_RC_FAST = CLK_CAL_RC_FAST, //!< Internal 20MHz RC oscillator
} rtc_cal_sel_t;
/**
* Initialization parameters for rtc_clk_init
*/
@@ -341,12 +327,12 @@ uint32_t rtc_clk_apb_freq_get(void);
* the check fails, then consider this an invalid 32k clock and return 0. This
* check can filter some jamming signal.
*
* @param cal_clk clock to be measured
* @param cal_clk_sel clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average slow clock period in microseconds, Q13.19 fixed point format,
* or 0 if calibration has timed out
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Convert time interval from microseconds to RTC_SLOW_CLK cycles
@@ -19,29 +19,41 @@ static const char *TAG = "rtc_time";
#define RTC_SLOW_CLK_600K_CAL_TIMEOUT_THRES(cycles) (cycles << 10)
#define RTC_SLOW_CLK_32K_CAL_TIMEOUT_THRES(cycles) (cycles << 12)
#define RTC_FAST_CLK_20M_CAL_TIMEOUT_THRES(cycles) (TIMG_RTC_CALI_TIMEOUT_THRES_V) // Just use the max timeout thres value
#define RTC_FAST_CLK_20M_CAL_TIMEOUT_THRES(cycles) (TIMG_RTC_CALI_TIMEOUT_THRES_V) // Just use the max timeout thres value
// Calibration can only be performed on relatively slow speed clock signal. Therefore, for high-speed clocks,
// calibration is performed on their DIV_CLKs. The divider is configurable. We set:
#define CLK_CAL_DIV_VAL(cal_clk) \
((cal_clk == RTC_CAL_RC_FAST) ? 32 : 1)
#define CLK_CAL_DIV_VAL(cal_clk_sel) \
((cal_clk_sel == CLK_CAL_RC_FAST) ? 32 : 1)
static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
/**
* @brief Clock frequency calculation function used by rtc_clk_cal
*
* Calculation of clock frequency is performed using a special feature of TIMG0.
* This feature counts the number of XTAL clock cycles within a given number of
* clock cycles.
*
* @param cal_clk_sel which clock to calculate frequency
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
static uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles < TIMG_RTC_CALI_MAX_V);
bool is_cal_clk_rtc_slow = false;
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
soc_clk_calibration_clk_src_t cali_clk_sel = (soc_clk_calibration_clk_src_t)cal_clk;
if (cal_clk == RTC_CAL_RTC_MUX) {
if (cal_clk_sel == CLK_CAL_RTC_SLOW) {
is_cal_clk_rtc_slow = true;
switch (slow_clk_src) {
case SOC_RTC_SLOW_CLK_SRC_RC_SLOW_D4:
cali_clk_sel = CLK_CAL_RC_SLOW;
cal_clk_sel = CLK_CAL_RC_SLOW;
break;
case SOC_RTC_SLOW_CLK_SRC_XTAL32K:
cali_clk_sel = CLK_CAL_32K_XTAL;
cal_clk_sel = CLK_CAL_32K_XTAL;
break;
case SOC_RTC_SLOW_CLK_SRC_OSC_SLOW:
cali_clk_sel = CLK_CAL_32K_OSC_SLOW;
cal_clk_sel = CLK_CAL_32K_OSC_SLOW;
break;
default:
ESP_EARLY_LOGE(TAG, "clock not supported to be calibrated");
@@ -49,18 +61,23 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
}
if (cal_clk_sel != CLK_CAL_RC_SLOW && cal_clk_sel != CLK_CAL_32K_XTAL && cal_clk_sel != CLK_CAL_32K_OSC_SLOW && cal_clk_sel != CLK_CAL_RC_FAST) {
ESP_EARLY_LOGE(TAG, "calibration not yet supported for this clock");
return 0;
}
/* Enable requested clock (rc_slow clock is always on) */
// All clocks on/off takes time to be stable, so we shouldn't frequently enable/disable the clock
// Only enable if originally was disabled, and set back to the disable state after calibration is done
// If the clock is already on, then do nothing
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
bool dig_rc_fast_enabled = clk_ll_rc_fast_digi_is_enabled();
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!rc_fast_enabled) {
rtc_clk_8m_enable(true);
}
@@ -83,19 +100,19 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
/* Prepare calibration */
clk_ll_calibration_set_target(cali_clk_sel);
uint32_t clk_cal_divider = CLK_CAL_DIV_VAL(cal_clk);
clk_ll_calibration_set_divider(clk_cal_divider);
clk_ll_freq_calulation_set_target(cal_clk_sel);
uint32_t clk_cal_divider = CLK_CAL_DIV_VAL(cal_clk_sel);
clk_ll_freq_calculation_set_divider(clk_cal_divider);
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
/* Figure out how long to wait for calibration to finish */
/* Set timeout reg and expect time delay*/
uint32_t expected_freq;
if (cali_clk_sel == CLK_CAL_32K_XTAL || cali_clk_sel == CLK_CAL_32K_OSC_SLOW) {
if (cal_clk_sel == CLK_CAL_32K_XTAL || cal_clk_sel == CLK_CAL_32K_OSC_SLOW) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_32K_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_XTAL32K_FREQ_APPROX;
} else if (cali_clk_sel == CLK_CAL_RC_FAST) {
} else if (cal_clk_sel == CLK_CAL_RC_FAST) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_FAST_CLK_20M_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_RC_FAST_FREQ_APPROX;
} else {
@@ -123,14 +140,14 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
}
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
clk_ll_calibration_set_divider(1);
clk_ll_freq_calculation_set_divider(1);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!dig_rc_fast_enabled) {
rtc_dig_clk8m_disable();
}
@@ -139,7 +156,7 @@ static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cyc
}
}
if (cal_clk == RTC_CAL_RTC_MUX && slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW_D4) {
if (is_cal_clk_rtc_slow && slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW_D4) {
// calibration was done on RC_SLOW clock, but rtc_slow_clk src is RC_SLOW_D4, so we need to multiply the cal_val by 4
cal_val *= 4;
}
@@ -154,14 +171,14 @@ static bool rtc_clk_cal_32k_valid(soc_xtal_freq_t xtal_freq, uint32_t slowclk_cy
return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
slowclk_cycles /= (cal_clk == RTC_CAL_RTC_MUX) ? 1 : CLK_CAL_DIV_VAL(cal_clk);
slowclk_cycles /= (cal_clk_sel == CLK_CAL_RTC_SLOW) ? 1 : CLK_CAL_DIV_VAL(cal_clk_sel);
assert(slowclk_cycles);
soc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
if (cal_clk == RTC_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
return 0;
}
@@ -149,27 +149,19 @@ typedef struct rtc_cpu_freq_config_s {
#define RTC_VDDSDIO_TIEH_1_8V 0 //!< TIEH field value for 1.8V VDDSDIO
#define RTC_VDDSDIO_TIEH_3_3V 1 //!< TIEH field value for 3.3V VDDSDIO
/**
* @brief Clock source to be calibrated using rtc_clk_cal function
*
* @note On ESP32P4, the enum values somehow reflects the register field values of HP_SYS_CLKRST_REG_TIMERGRP0_TGRT_CLK_SRC_SEL.
*/
typedef enum {
RTC_CAL_RTC_MUX = -1, //!< Currently selected RTC_SLOW_CLK
RTC_CAL_MPLL = 0, //!< 500MHz MSPI_PLL_CLK
RTC_CAL_SPLL = 1, //!< 480MHz SYS_PLL_CLK
RTC_CAL_CPLL = 2, //!< 400MHz CPU_PLL_CLK
RTC_CAL_APLL = 3, //!< AUDIO_PLL_CLK
RTC_CAL_SDIO_PLL0 = 4, //!< SDIO_PLL0_CLK
RTC_CAL_SDIO_PLL1 = 5, //!< SDIO_PLL1_CLK
RTC_CAL_SDIO_PLL2 = 6, //!< SDIO_PLL2_CLK
RTC_CAL_RC_FAST = 7, //!< Internal 20MHz RC oscillator
RTC_CAL_RC_SLOW = 8, //!< Internal 150kHz RC oscillator
RTC_CAL_RC32K = 9, //!< Internal 32kHz RC oscillator, as one type of 32k clock
RTC_CAL_32K_XTAL = 10, //!< External 32kHz XTAL, as one type of 32k clock
RTC_CAL_LP_PLL = 11, //!< 8MHz LP_PLL_CLK
RTC_CAL_INVALID_CLK, //!< Clock not available to calibrate
} rtc_cal_sel_t;
#define RTC_CAL_RTC_MUX _Pragma ("GCC warning \"'RTC_CAL_RTC_MUX' macro is deprecated\"") CLK_CAL_RTC_SLOW
#define RTC_CAL_MPLL _Pragma ("GCC warning \"'RTC_CAL_MPLL' macro is deprecated\"") CLK_CAL_MPLL
#define RTC_CAL_SPLL _Pragma ("GCC warning \"'RTC_CAL_SPLL' macro is deprecated\"") CLK_CAL_SPLL
#define RTC_CAL_CPLL _Pragma ("GCC warning \"'RTC_CAL_CPLL' macro is deprecated\"") CLK_CAL_CPLL
#define RTC_CAL_APLL _Pragma ("GCC warning \"'RTC_CAL_APLL' macro is deprecated\"") CLK_CAL_APLL
#define RTC_CAL_SDIO_PLL0 _Pragma ("GCC warning \"'RTC_CAL_SDIO_PLL0' macro is deprecated\"") CLK_CAL_SDIO_PLL0
#define RTC_CAL_SDIO_PLL1 _Pragma ("GCC warning \"'RTC_CAL_SDIO_PLL1' macro is deprecated\"") CLK_CAL_SDIO_PLL1
#define RTC_CAL_SDIO_PLL2 _Pragma ("GCC warning \"'RTC_CAL_SDIO_PLL2' macro is deprecated\"") CLK_CAL_SDIO_PLL2
#define RTC_CAL_RC_FAST _Pragma ("GCC warning \"'RTC_CAL_RC_FAST' macro is deprecated\"") CLK_CAL_RC_FAST
#define RTC_CAL_RC_SLOW _Pragma ("GCC warning \"'RTC_CAL_RC_SLOW' macro is deprecated\"") CLK_CAL_RC_SLOW
#define RTC_CAL_RC32K _Pragma ("GCC warning \"'RTC_CAL_RC32K' macro is deprecated\"") CLK_CAL_RC32K
#define RTC_CAL_32K_XTAL _Pragma ("GCC warning \"'RTC_CAL_32K_XTAL' macro is deprecated\"") CLK_CAL_32K_XTAL
#define RTC_CAL_LP_PLL _Pragma ("GCC warning \"'RTC_CAL_LP_PLL' macro is deprecated\"") CLK_CAL_LP_PLL
/**
* Initialization parameters for rtc_clk_init
@@ -391,26 +383,6 @@ void rtc_clk_cpu_freq_set_xtal(void);
*/
uint32_t rtc_clk_apb_freq_get(void);
/**
* @brief Clock calibration function used by rtc_clk_cal
*
* 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.
*
* Slow clock calibration feature has two modes of operation: one-off and cycling.
* In cycling mode (which is enabled by default on SoC reset), counting of XTAL
* cycles within RTC_SLOW_CLK cycle is done continuously. Cycling mode is enabled
* using TIMG_RTC_CALI_START_CYCLING bit. In one-off mode counting is performed
* once, and TIMG_RTC_CALI_RDY bit is set when counting is done. One-off mode is
* enabled using TIMG_RTC_CALI_START bit.
*
* @param cal_clk which clock to calibrate
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles);
/**
* @brief Measure RTC slow clock's period, based on main XTAL frequency
*
@@ -424,12 +396,12 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles);
* the check fails, then consider this an invalid 32k clock and return 0. This
* check can filter some jamming signal.
*
* @param cal_clk clock to be measured
* @param cal_clk_sel clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average slow clock period in microseconds, Q13.19 fixed point format,
* or 0 if calibration has timed out
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Convert time interval from microseconds to RTC_SLOW_CLK cycles
@@ -18,67 +18,69 @@
__attribute__((unused)) static const char *TAG = "rtc_time";
/* Calibration of clock frequency is performed using a special feature of TIMG0.
* This feature counts the number of XTAL clock cycles within a given number of
* clock cycles.
*/
#define CLK_CAL_TIMEOUT_THRES(cal_clk_sel, cycles) ((cal_clk_sel == CLK_CAL_RC32K || cal_clk_sel == CLK_CAL_32K_XTAL) ? (cycles << 12) : (cycles << 10))
#define CLK_CAL_TIMEOUT_THRES(cal_clk, cycles) ((cal_clk == RTC_CAL_RC32K || cal_clk == RTC_CAL_32K_XTAL) ? (cycles << 12) : (cycles << 10))
// Calibration can only be performed on relatively slow speed clock signal. Therefore, for high-speed clocks,
// calibration is performed on their DIV_CLKs. The divider is configurable. We set:
#define CLK_CAL_DIV_VAL(cal_clk) \
((cal_clk == RTC_CAL_RC_SLOW || cal_clk == RTC_CAL_RC32K || cal_clk == RTC_CAL_32K_XTAL) ? 1 : \
(cal_clk == RTC_CAL_LP_PLL) ? 25 : \
(cal_clk == RTC_CAL_RC_FAST) ? 50 : \
(cal_clk == RTC_CAL_APLL) ? 200 : \
// Calculation can only be performed on relatively slow speed clock signal. Therefore, for high-speed clocks,
// calculation is performed on their DIV_CLKs. The divider is configurable. We set:
#define CLK_CAL_DIV_VAL(cal_clk_sel) \
((cal_clk_sel == CLK_CAL_RC_SLOW || cal_clk_sel == CLK_CAL_RC32K || cal_clk_sel == CLK_CAL_32K_XTAL) ? 1 : \
(cal_clk_sel == CLK_CAL_LP_PLL) ? 25 : \
(cal_clk_sel == CLK_CAL_RC_FAST) ? 50 : \
(cal_clk_sel == CLK_CAL_APLL) ? 200 : \
4000)
// CLK_CAL_FREQ_APPROX = CLK_FREQ_APPROX / CLK_CAL_DIV_VAL
#define CLK_CAL_FREQ_APPROX(cal_clk) \
((cal_clk == RTC_CAL_MPLL) ? (CLK_LL_PLL_500M_FREQ_MHZ * MHZ / 4000) : \
(cal_clk == RTC_CAL_SPLL) ? (CLK_LL_PLL_480M_FREQ_MHZ * MHZ / 4000) : \
(cal_clk == RTC_CAL_CPLL) ? (CLK_LL_PLL_400M_FREQ_MHZ * MHZ / 4000) : \
(cal_clk == RTC_CAL_APLL) ? (105 * MHZ / 200) : \
(cal_clk == RTC_CAL_SDIO_PLL0 || cal_clk == RTC_CAL_SDIO_PLL1 || cal_clk == RTC_CAL_SDIO_PLL2) ? (200 * MHZ / 4000) : \
(cal_clk == RTC_CAL_RC_FAST) ? (SOC_CLK_RC_FAST_FREQ_APPROX / 50) : \
(cal_clk == RTC_CAL_RC_SLOW) ? (SOC_CLK_RC_SLOW_FREQ_APPROX) : \
(cal_clk == RTC_CAL_RC32K) ? (SOC_CLK_RC32K_FREQ_APPROX) : \
(cal_clk == RTC_CAL_32K_XTAL) ? (SOC_CLK_XTAL32K_FREQ_APPROX) : \
(cal_clk == RTC_CAL_LP_PLL) ? (CLK_LL_PLL_8M_FREQ_MHZ * MHZ / 25) : \
#define CLK_CAL_FREQ_APPROX(cal_clk_sel) \
((cal_clk_sel == CLK_CAL_MPLL) ? (CLK_LL_PLL_500M_FREQ_MHZ * MHZ / 4000) : \
(cal_clk_sel == CLK_CAL_SPLL) ? (CLK_LL_PLL_480M_FREQ_MHZ * MHZ / 4000) : \
(cal_clk_sel == CLK_CAL_CPLL) ? (CLK_LL_PLL_400M_FREQ_MHZ * MHZ / 4000) : \
(cal_clk_sel == CLK_CAL_APLL) ? (105 * MHZ / 200) : \
(cal_clk_sel == CLK_CAL_SDIO_PLL0 || cal_clk_sel == CLK_CAL_SDIO_PLL1 || cal_clk_sel == CLK_CAL_SDIO_PLL2) ? (200 * MHZ / 4000) : \
(cal_clk_sel == CLK_CAL_RC_FAST) ? (SOC_CLK_RC_FAST_FREQ_APPROX / 50) : \
(cal_clk_sel == CLK_CAL_RC_SLOW) ? (SOC_CLK_RC_SLOW_FREQ_APPROX) : \
(cal_clk_sel == CLK_CAL_RC32K) ? (SOC_CLK_RC32K_FREQ_APPROX) : \
(cal_clk_sel == CLK_CAL_32K_XTAL) ? (SOC_CLK_XTAL32K_FREQ_APPROX) : \
(cal_clk_sel == CLK_CAL_LP_PLL) ? (CLK_LL_PLL_8M_FREQ_MHZ * MHZ / 25) : \
0)
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
/**
* @brief Clock frequency calculation function used by rtc_clk_cal
*
* Calculation of clock frequency is performed using a special feature of TIMG0.
* This feature counts the number of XTAL clock cycles within a given number of
* clock cycles.
*
* @param cal_clk_sel which clock to calculate frequency
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
static uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles < TIMG_RTC_CALI_MAX_V);
if (cal_clk == RTC_CAL_RTC_MUX) {
if (cal_clk_sel == CLK_CAL_RTC_SLOW) {
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) {
cal_clk = RTC_CAL_RC_SLOW;
cal_clk_sel = CLK_CAL_RC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk = RTC_CAL_32K_XTAL;
cal_clk_sel = CLK_CAL_32K_XTAL;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC32K) {
cal_clk = RTC_CAL_RC32K;
cal_clk_sel = CLK_CAL_RC32K;
}
}
if (cal_clk < 0 || cal_clk >= RTC_CAL_INVALID_CLK) {
ESP_EARLY_LOGE(TAG, "clock not supported to be calibrated");
return 0;
}
/* Enable requested clock (some clocks are always on) */
// All clocks on/off takes time to be stable, so we shouldn't frequently enable/disable the clock
// Only enable if originally was disabled, and set back to the disable state after calibration is done
// If the clock is already on, then do nothing
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
bool dig_rc_fast_enabled = clk_ll_rc_fast_digi_is_enabled();
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!rc_fast_enabled) {
rtc_clk_8m_enable(true);
}
@@ -89,7 +91,7 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
bool rc32k_enabled = clk_ll_rc32k_is_enabled();
bool dig_rc32k_enabled = clk_ll_rc32k_digi_is_enabled();
if (cal_clk == RTC_CAL_RC32K) {
if (cal_clk_sel == CLK_CAL_RC32K) {
if (!rc32k_enabled) {
rtc_clk_rc32k_enable(true);
}
@@ -112,16 +114,16 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
}
/* Prepare calibration */
REG_SET_FIELD(HP_SYS_CLKRST_PERI_CLK_CTRL21_REG, HP_SYS_CLKRST_REG_TIMERGRP0_TGRT_CLK_SRC_SEL, cal_clk);
uint32_t clk_cal_divider = CLK_CAL_DIV_VAL(cal_clk);
REG_SET_FIELD(HP_SYS_CLKRST_PERI_CLK_CTRL21_REG, HP_SYS_CLKRST_REG_TIMERGRP0_TGRT_CLK_DIV_NUM, clk_cal_divider - 1);
clk_ll_freq_calulation_set_target(cal_clk_sel);
uint32_t clk_cal_divider = CLK_CAL_DIV_VAL(cal_clk_sel);
clk_ll_freq_calculation_set_divider(clk_cal_divider);
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
/* Figure out how long to wait for calibration to finish */
/* Set timeout reg and expect time delay*/
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, CLK_CAL_TIMEOUT_THRES(cal_clk, slowclk_cycles));
uint32_t expected_freq = CLK_CAL_FREQ_APPROX(cal_clk);
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, CLK_CAL_TIMEOUT_THRES(cal_clk_sel, slowclk_cycles));
uint32_t expected_freq = CLK_CAL_FREQ_APPROX(cal_clk_sel);
assert(expected_freq);
uint32_t us_time_estimate = (uint32_t) (((uint64_t) slowclk_cycles) * MHZ / expected_freq);
/* Start calibration */
@@ -143,14 +145,14 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
}
}
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL21_REG, HP_SYS_CLKRST_REG_TIMERGRP0_TGRT_CLK_DIV_NUM_M);
clk_ll_freq_calculation_set_divider(1);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_RC_FAST) {
if (cal_clk_sel == CLK_CAL_RC_FAST) {
if (!dig_rc_fast_enabled) {
rtc_dig_clk8m_disable();
}
@@ -159,7 +161,7 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
}
}
if (cal_clk == RTC_CAL_RC32K) {
if (cal_clk_sel == CLK_CAL_RC32K) {
if (!dig_rc32k_enabled) {
clk_ll_rc32k_digi_disable();
}
@@ -178,14 +180,14 @@ static bool rtc_clk_cal_32k_valid(uint32_t xtal_freq, uint32_t slowclk_cycles, u
return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
slowclk_cycles /= (cal_clk == RTC_CAL_RTC_MUX) ? 1 : CLK_CAL_DIV_VAL(cal_clk);
slowclk_cycles /= (cal_clk_sel == CLK_CAL_RTC_SLOW) ? 1 : CLK_CAL_DIV_VAL(cal_clk_sel);
assert(slowclk_cycles);
soc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
if (cal_clk == RTC_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
return 0;
}
@@ -159,15 +159,10 @@ typedef struct rtc_cpu_freq_config_s {
#define RTC_VDDSDIO_TIEH_1_8V 0 //!< TIEH field value for 1.8V VDDSDIO
#define RTC_VDDSDIO_TIEH_3_3V 1 //!< TIEH field value for 3.3V VDDSDIO
/**
* @brief Clock source to be calibrated using rtc_clk_cal function
*/
typedef enum {
RTC_CAL_RTC_MUX = 0, //!< Currently selected RTC SLOW_CLK
RTC_CAL_8MD256 = 1, //!< Internal 8 MHz RC oscillator, divided by 256
RTC_CAL_32K_XTAL = 2, //!< External 32 kHz XTAL
RTC_CAL_INTERNAL_OSC = 3 //!< Internal 150 kHz oscillator
} rtc_cal_sel_t;
#define RTC_CAL_RTC_MUX _Pragma ("GCC warning \"'RTC_CAL_RTC_MUX' macro is deprecated\"") CLK_CAL_RTC_SLOW
#define RTC_CAL_8MD256 _Pragma ("GCC warning \"'RTC_CAL_8MD256' macro is deprecated\"") CLK_CAL_RC_FAST_D256
#define RTC_CAL_32K_XTAL _Pragma ("GCC warning \"'RTC_CAL_32K_XTAL' macro is deprecated\"") CLK_CAL_32K_XTAL
#define RTC_CAL_INTERNAL_OSC _Pragma ("GCC warning \"'RTC_CAL_INTERNAL_OSC' macro is deprecated\"") CLK_CAL_RC_SLOW
/**
* Initialization parameters for rtc_clk_init
@@ -470,8 +465,6 @@ void rtc_clk_apb_freq_update(uint32_t apb_freq);
*/
uint32_t rtc_clk_apb_freq_get(void);
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles, uint32_t cal_mode);
/**
* @brief Measure RTC slow clock's period, based on main XTAL frequency
*
@@ -485,21 +478,21 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles, ui
* the check fails, then consider this an invalid 32k clock and return 0. This
* check can filter some jamming signal.
*
* @param cal_clk clock to be measured
* @param cal_clk_sel clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average slow clock period in microseconds, Q13.19 fixed point format,
* or 0 if calibration has timed out
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Measure ratio between XTAL frequency and RTC slow clock frequency
* @param cal_clk slow clock to be measured
* @param cal_clk_sel slow clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average ratio between XTAL frequency and slow clock frequency,
* Q13.19 fixed point format, or 0 if calibration has timed out.
*/
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal_ratio(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Convert time interval from microseconds to RTC_SLOW_CLK cycles
@@ -848,10 +841,10 @@ void rtc_vddsdio_set_config(rtc_vddsdio_config_t config);
/**
* Using valid hardware calibration value to calibrate slowclk
* If there is no hardware calibration in process, start hardware calibration and wait for calibration finished
* @param cal_clk clock to be measured
* @param cal_clk_sel clock to be measured
* @param slowclk_cycles if no hardware calibration in process, use this amount of slow cycles to calibrate slowclk.
*/
uint32_t rtc_clk_cal_cycling(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles);
uint32_t rtc_clk_cal_cycling(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles);
// -------------------------- CLOCK TREE DEFS ALIAS ----------------------------
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -255,16 +255,9 @@ static void calibrate_ocode(void)
4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout;
5. set cpu to old-config.
*/
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX;
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk = RTC_CAL_32K_XTAL;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256) {
cal_clk = RTC_CAL_8MD256;
}
uint64_t max_delay_time_us = 10000;
uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100);
uint32_t slow_clk_period = rtc_clk_cal(CLK_CAL_RTC_SLOW, 100);
uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period);
uint64_t cycle0 = rtc_time_get();
uint64_t timeout_cycle = cycle0 + max_delay_cycle;
@@ -14,11 +14,11 @@
#include "soc/timer_group_reg.h"
#include "esp_private/periph_ctrl.h"
/* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0.
/* Calculation 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.
*
* Slow clock calibration feature has two modes of operation: one-off and cycling.
* Slow clock frequency calculation feature has two modes of operation: one-off and cycling.
* In cycling mode (which is enabled by default on SoC reset), counting of XTAL
* cycles within RTC_SLOW_CLK cycle is done continuously. Cycling mode is enabled
* using TIMG_RTC_CALI_START_CYCLING bit. In one-off mode counting is performed
@@ -28,11 +28,11 @@
/**
* @brief One-off clock calibration function used by rtc_clk_cal_internal
* @param cal_clk which clock to calibrate
* @param cal_clk_sel which clock to calculate frequency
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
static uint32_t rtc_clk_cal_internal_oneoff(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
static uint32_t rtc_clk_cal_internal_oneoff(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
/* There may be another calibration process already running during we call this function,
* so we should wait the last process is done.
@@ -48,17 +48,17 @@ static uint32_t rtc_clk_cal_internal_oneoff(rtc_cal_sel_t cal_clk, uint32_t slow
}
/* Prepare calibration */
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cal_clk);
clk_ll_freq_calulation_set_target(cal_clk_sel);
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
/* Figure out how long to wait for calibration to finish */
/* Set timeout reg and expect time delay*/
uint32_t expected_freq;
if (cal_clk == RTC_CAL_32K_XTAL) {
if (cal_clk_sel == CLK_CAL_32K_XTAL) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_X32K_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_XTAL32K_FREQ_APPROX;
} else if (cal_clk == RTC_CAL_8MD256) {
} else if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_8MD256_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_RC_FAST_D256_FREQ_APPROX;
} else {
@@ -89,20 +89,19 @@ static uint32_t rtc_clk_cal_internal_oneoff(rtc_cal_sel_t cal_clk, uint32_t slow
/**
* @brief Cycling clock calibration function used by rtc_clk_cal_internal
* @param cal_clk which clock to calibrate
* @param cal_clk_sel which clock to calculate frequency
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
static uint32_t rtc_clk_cal_internal_cycling(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
static uint32_t rtc_clk_cal_internal_cycling(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
/* Get which slowclk is in calibration and max cali cycles */
rtc_cal_sel_t in_calibration_clk;
in_calibration_clk = REG_GET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL);
soc_clk_freq_calculation_src_t in_calibration_clk = REG_GET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL);
uint32_t cali_slowclk_cycles = REG_GET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX);
/* If no calibration in process or calibration period equal to 0, use slowclk_cycles cycles to calibrate slowclk */
if (cali_slowclk_cycles == 0 || !GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING) || in_calibration_clk != cal_clk) {
if (cali_slowclk_cycles == 0 || !GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING) || in_calibration_clk != cal_clk_sel) {
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cal_clk);
clk_ll_freq_calulation_set_target(cal_clk_sel);
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
SET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
cali_slowclk_cycles = slowclk_cycles;
@@ -133,56 +132,51 @@ static uint32_t rtc_clk_xtal_to_slowclk(uint64_t xtal_cycles, uint32_t slowclk_c
/**
* @brief Clock calibration function used by rtc_clk_cal and rtc_clk_cal_ratio
* @param cal_clk which clock to calibrate
* @param cal_clk_sel which clock to calculate frequency
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles, uint32_t cal_mode)
static uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles, uint32_t cal_mode)
{
/* On ESP32S2, choosing RTC_CAL_RTC_MUX results in calibration of
* the 90k RTC clock regardless of the currently selected SLOW_CLK.
* On the ESP32, it used the currently selected SLOW_CLK.
* The following code emulates ESP32 behavior:
*/
if (cal_clk == RTC_CAL_RTC_MUX) {
if (cal_clk_sel == CLK_CAL_RTC_SLOW) {
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk = RTC_CAL_32K_XTAL;
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) {
cal_clk_sel = CLK_CAL_RC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk_sel = CLK_CAL_32K_XTAL;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256) {
cal_clk = RTC_CAL_8MD256;
cal_clk_sel = CLK_CAL_RC_FAST_D256;
}
} else if (cal_clk == RTC_CAL_INTERNAL_OSC) {
cal_clk = RTC_CAL_RTC_MUX;
}
/* Enable requested clock (90k clock is always on) */
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
bool rc_fast_d256_enabled = clk_ll_rc_fast_d256_is_enabled();
if (cal_clk == RTC_CAL_8MD256) {
if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
rtc_clk_8m_enable(true, true);
clk_ll_rc_fast_d256_digi_enable();
}
uint32_t cal_val;
if (cal_mode == RTC_TIME_CAL_ONEOFF_MODE) {
cal_val = rtc_clk_cal_internal_oneoff(cal_clk, slowclk_cycles);
cal_val = rtc_clk_cal_internal_oneoff(cal_clk_sel, slowclk_cycles);
} else {
cal_val = rtc_clk_cal_internal_cycling(cal_clk, slowclk_cycles);
cal_val = rtc_clk_cal_internal_cycling(cal_clk_sel, slowclk_cycles);
}
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_8MD256) {
if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
clk_ll_rc_fast_d256_digi_disable();
rtc_clk_8m_enable(rc_fast_enabled, rc_fast_d256_enabled);
}
@@ -190,10 +184,10 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles, ui
return cal_val;
}
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal_ratio(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles, RTC_TIME_CAL_ONEOFF_MODE);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles, RTC_TIME_CAL_ONEOFF_MODE);
uint64_t ratio_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT)) / slowclk_cycles;
uint32_t ratio = (uint32_t)(ratio_64 & UINT32_MAX);
return ratio;
@@ -206,20 +200,20 @@ static inline bool rtc_clk_cal_32k_valid(uint32_t xtal_freq, uint32_t slowclk_cy
return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles, RTC_TIME_CAL_ONEOFF_MODE);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles, RTC_TIME_CAL_ONEOFF_MODE);
if ((cal_clk == RTC_CAL_32K_XTAL) && !rtc_clk_cal_32k_valid((uint32_t)rtc_clk_xtal_freq_get(), slowclk_cycles, xtal_cycles)) {
if ((cal_clk_sel == CLK_CAL_32K_XTAL) && !rtc_clk_cal_32k_valid((uint32_t)rtc_clk_xtal_freq_get(), slowclk_cycles, xtal_cycles)) {
return 0;
}
return rtc_clk_xtal_to_slowclk(xtal_cycles, slowclk_cycles);
}
uint32_t rtc_clk_cal_cycling(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal_cycling(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles, RTC_TIME_CAL_CYCLING_MODE);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles, RTC_TIME_CAL_CYCLING_MODE);
uint32_t period = rtc_clk_xtal_to_slowclk(xtal_cycles, slowclk_cycles);
return period;
}
@@ -161,15 +161,10 @@ typedef struct rtc_cpu_freq_config_s {
#define RTC_VDDSDIO_TIEH_1_8V 0 //!< TIEH field value for 1.8V VDDSDIO
#define RTC_VDDSDIO_TIEH_3_3V 1 //!< TIEH field value for 3.3V VDDSDIO
/**
* @brief Clock source to be calibrated using rtc_clk_cal function
*/
typedef enum {
RTC_CAL_RTC_MUX = 0, //!< Currently selected RTC SLOW_CLK
RTC_CAL_8MD256 = 1, //!< Internal 8 MHz RC oscillator, divided by 256
RTC_CAL_32K_XTAL = 2, //!< External 32 kHz XTAL
RTC_CAL_INTERNAL_OSC = 3 //!< Internal 150 kHz oscillator
} rtc_cal_sel_t;
#define RTC_CAL_RTC_MUX _Pragma ("GCC warning \"'RTC_CAL_RTC_MUX' macro is deprecated\"") CLK_CAL_RTC_SLOW
#define RTC_CAL_8MD256 _Pragma ("GCC warning \"'RTC_CAL_8MD256' macro is deprecated\"") CLK_CAL_RC_FAST_D256
#define RTC_CAL_32K_XTAL _Pragma ("GCC warning \"'RTC_CAL_32K_XTAL' macro is deprecated\"") CLK_CAL_32K_XTAL
#define RTC_CAL_INTERNAL_OSC _Pragma ("GCC warning \"'RTC_CAL_INTERNAL_OSC' macro is deprecated\"") CLK_CAL_RC_SLOW
/**
* Initialization parameters for rtc_clk_init
@@ -448,8 +443,6 @@ void rtc_clk_apb_freq_update(uint32_t apb_freq);
*/
uint32_t rtc_clk_apb_freq_get(void);
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles);
/**
* @brief Measure RTC slow clock's period, based on main XTAL frequency
*
@@ -463,21 +456,21 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles);
* the check fails, then consider this an invalid 32k clock and return 0. This
* check can filter some jamming signal.
*
* @param cal_clk clock to be measured
* @param cal_clk_sel clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average slow clock period in microseconds, Q13.19 fixed point format,
* or 0 if calibration has timed out
*/
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Measure ratio between XTAL frequency and RTC slow clock frequency
* @param cal_clk slow clock to be measured
* @param cal_clk_sel slow clock to be measured
* @param slow_clk_cycles number of slow clock cycles to average
* @return average ratio between XTAL frequency and slow clock frequency,
* Q13.19 fixed point format, or 0 if calibration has timed out.
*/
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slow_clk_cycles);
uint32_t rtc_clk_cal_ratio(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slow_clk_cycles);
/**
* @brief Convert time interval from microseconds to RTC_SLOW_CLK cycles
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -283,16 +283,9 @@ static void calibrate_ocode(void)
4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout;
5. set cpu to old-config.
*/
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX;
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk = RTC_CAL_32K_XTAL;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256) {
cal_clk = RTC_CAL_8MD256;
}
uint64_t max_delay_time_us = 10000;
uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100);
uint32_t slow_clk_period = rtc_clk_cal(CLK_CAL_RTC_SLOW, 100);
uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period);
uint64_t cycle0 = rtc_time_get();
uint64_t timeout_cycle = cycle0 + max_delay_cycle;
@@ -14,11 +14,11 @@
#include "soc/timer_group_reg.h"
#include "esp_private/periph_ctrl.h"
/* Calibration of RTC_SLOW_CLK is performed using a special feature of TIMG0.
/* Calculation 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.
*
* Slow clock calibration feature has two modes of operation: one-off and cycling.
* Slow clock frequency calculation feature has two modes of operation: one-off and cycling.
* In cycling mode (which is enabled by default on SoC reset), counting of XTAL
* cycles within RTC_SLOW_CLK cycle is done continuously. Cycling mode is enabled
* using TIMG_RTC_CALI_START_CYCLING bit. In one-off mode counting is performed
@@ -27,38 +27,33 @@
*/
/**
* @brief Clock calibration function used by rtc_clk_cal and rtc_clk_cal_ratio
* @param cal_clk which clock to calibrate
* @brief Clock frequency calculation function used by rtc_clk_cal and rtc_clk_cal_ratio
* @param cal_clk_sel which clock to calculate frequency
* @param slowclk_cycles number of slow clock cycles to count
* @return number of XTAL clock cycles within the given number of slow clock cycles
*/
uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
static uint32_t rtc_clk_cal_internal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
/* On ESP32S3, choosing RTC_CAL_RTC_MUX results in calibration of
* the 150k RTC clock regardless of the currently selected SLOW_CLK.
* On the ESP32, it used the currently selected SLOW_CLK.
* The following code emulates ESP32 behavior:
*/
if (cal_clk == RTC_CAL_RTC_MUX) {
if (cal_clk_sel == CLK_CAL_RTC_SLOW) {
soc_rtc_slow_clk_src_t slow_clk_src = rtc_clk_slow_src_get();
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk = RTC_CAL_32K_XTAL;
if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) {
cal_clk_sel = CLK_CAL_RC_SLOW;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
cal_clk_sel = CLK_CAL_32K_XTAL;
} else if (slow_clk_src == SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256) {
cal_clk = RTC_CAL_8MD256;
cal_clk_sel = CLK_CAL_RC_FAST_D256;
}
} else if (cal_clk == RTC_CAL_INTERNAL_OSC) {
cal_clk = RTC_CAL_RTC_MUX;
}
/* Enable requested clock (150k clock is always on) */
bool dig_32k_xtal_enabled = clk_ll_xtal32k_digi_is_enabled();
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_enable();
}
bool rc_fast_enabled = clk_ll_rc_fast_is_enabled();
bool rc_fast_d256_enabled = clk_ll_rc_fast_d256_is_enabled();
if (cal_clk == RTC_CAL_8MD256) {
if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
rtc_clk_8m_enable(true, true);
clk_ll_rc_fast_d256_digi_enable();
}
@@ -76,17 +71,17 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
}
/* Prepare calibration */
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, cal_clk);
clk_ll_freq_calulation_set_target(cal_clk_sel);
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING);
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, slowclk_cycles);
/* Figure out how long to wait for calibration to finish */
/* Set timeout reg and expect time delay*/
uint32_t expected_freq;
if (cal_clk == RTC_CAL_32K_XTAL) {
if (cal_clk_sel == CLK_CAL_32K_XTAL) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_X32K_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_XTAL32K_FREQ_APPROX;
} else if (cal_clk == RTC_CAL_8MD256) {
} else if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
REG_SET_FIELD(TIMG_RTCCALICFG2_REG(0), TIMG_RTC_CALI_TIMEOUT_THRES, RTC_SLOW_CLK_8MD256_CAL_TIMEOUT_THRES(slowclk_cycles));
expected_freq = SOC_CLK_RC_FAST_D256_FREQ_APPROX;
} else {
@@ -114,11 +109,11 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
/* if dig_32k_xtal was originally off and enabled due to calibration, then set back to off state */
if (cal_clk == RTC_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
if (cal_clk_sel == CLK_CAL_32K_XTAL && !dig_32k_xtal_enabled) {
clk_ll_xtal32k_digi_disable();
}
if (cal_clk == RTC_CAL_8MD256) {
if (cal_clk_sel == CLK_CAL_RC_FAST_D256) {
clk_ll_rc_fast_d256_digi_disable();
rtc_clk_8m_enable(rc_fast_enabled, rc_fast_d256_enabled);
}
@@ -126,10 +121,10 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
return cal_val;
}
uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal_ratio(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
uint64_t ratio_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT)) / slowclk_cycles;
uint32_t ratio = (uint32_t)(ratio_64 & UINT32_MAX);
return ratio;
@@ -142,13 +137,13 @@ static inline bool rtc_clk_cal_32k_valid(uint32_t xtal_freq, uint32_t slowclk_cy
return (actual_xtal_cycles >= (expected_xtal_cycles - delta)) && (actual_xtal_cycles <= (expected_xtal_cycles + delta));
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
uint32_t rtc_clk_cal(soc_clk_freq_calculation_src_t cal_clk_sel, uint32_t slowclk_cycles)
{
assert(slowclk_cycles);
soc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk_sel, slowclk_cycles);
if ((cal_clk == RTC_CAL_32K_XTAL) && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
if ((cal_clk_sel == CLK_CAL_32K_XTAL) && !rtc_clk_cal_32k_valid((uint32_t)xtal_freq, slowclk_cycles, xtal_cycles)) {
return 0;
}
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -59,7 +59,7 @@ static uint32_t clk_tree_rtc_slow_calibration(uint32_t slowclk_cycles)
{
uint32_t cal_val = 0;
if (slowclk_cycles > 0) {
cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, slowclk_cycles);
cal_val = rtc_clk_cal(CLK_CAL_RTC_SLOW, slowclk_cycles);
} else {
const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL;
uint32_t source_approx_freq = clk_hal_lp_slow_get_freq_hz();
@@ -82,11 +82,11 @@ uint32_t esp_clk_tree_rc_fast_d256_get_freq_hz(esp_clk_tree_src_freq_precision_t
return SOC_CLK_RC_FAST_D256_FREQ_APPROX;
case ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED:
if (!s_calibrated_freq.rc_fast_d256) {
s_calibrated_freq.rc_fast_d256 = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_8MD256, DEFAULT_32K_CLK_CAL_CYCLES));
s_calibrated_freq.rc_fast_d256 = rtc_clk_freq_cal(rtc_clk_cal(CLK_CAL_RC_FAST_D256, DEFAULT_32K_CLK_CAL_CYCLES));
}
return s_calibrated_freq.rc_fast_d256;
case ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT:
s_calibrated_freq.rc_fast_d256 = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_8MD256, DEFAULT_32K_CLK_CAL_CYCLES));
s_calibrated_freq.rc_fast_d256 = rtc_clk_freq_cal(rtc_clk_cal(CLK_CAL_RC_FAST_D256, DEFAULT_32K_CLK_CAL_CYCLES));
return s_calibrated_freq.rc_fast_d256;
default:
return 0;
@@ -102,11 +102,11 @@ uint32_t esp_clk_tree_xtal32k_get_freq_hz(esp_clk_tree_src_freq_precision_t prec
return SOC_CLK_XTAL32K_FREQ_APPROX;
case ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED:
if (!s_calibrated_freq.xtal32k) {
s_calibrated_freq.xtal32k = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_32K_XTAL, DEFAULT_32K_CLK_CAL_CYCLES));
s_calibrated_freq.xtal32k = rtc_clk_freq_cal(rtc_clk_cal(CLK_CAL_32K_XTAL, DEFAULT_32K_CLK_CAL_CYCLES));
}
return s_calibrated_freq.xtal32k;
case ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT:
s_calibrated_freq.xtal32k = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_32K_XTAL, DEFAULT_32K_CLK_CAL_CYCLES));
s_calibrated_freq.xtal32k = rtc_clk_freq_cal(rtc_clk_cal(CLK_CAL_32K_XTAL, DEFAULT_32K_CLK_CAL_CYCLES));
return s_calibrated_freq.xtal32k;
default:
return 0;
@@ -122,11 +122,11 @@ uint32_t esp_clk_tree_osc_slow_get_freq_hz(esp_clk_tree_src_freq_precision_t pre
return SOC_CLK_OSC_SLOW_FREQ_APPROX;
case ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED:
if (!s_calibrated_freq.osc_slow) {
s_calibrated_freq.osc_slow = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_32K_OSC_SLOW, DEFAULT_32K_CLK_CAL_CYCLES));
s_calibrated_freq.osc_slow = rtc_clk_freq_cal(rtc_clk_cal(CLK_CAL_32K_OSC_SLOW, DEFAULT_32K_CLK_CAL_CYCLES));
}
return s_calibrated_freq.osc_slow;
case ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT:
s_calibrated_freq.osc_slow = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_32K_OSC_SLOW, DEFAULT_32K_CLK_CAL_CYCLES));
s_calibrated_freq.osc_slow = rtc_clk_freq_cal(rtc_clk_cal(CLK_CAL_32K_OSC_SLOW, DEFAULT_32K_CLK_CAL_CYCLES));
return s_calibrated_freq.osc_slow;
default:
return 0;
@@ -161,7 +161,7 @@ uint32_t esp_clk_tree_rc_fast_get_freq_hz(esp_clk_tree_src_freq_precision_t prec
#else
// Calibrate directly on the RC_FAST clock requires much more slow clock cycles to get an accurate freq value
if (precision != ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED || !s_calibrated_freq.rc_fast) {
s_calibrated_freq.rc_fast = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_RC_FAST, DEFAULT_RC_FAST_CAL_CYCLES));
s_calibrated_freq.rc_fast = rtc_clk_freq_cal(rtc_clk_cal(CLK_CAL_RC_FAST, DEFAULT_RC_FAST_CAL_CYCLES));
}
return s_calibrated_freq.rc_fast;
#endif //SOC_CLK_RC_FAST_D256_SUPPORTED
+4 -4
View File
@@ -828,18 +828,18 @@ static SLEEP_FN_ATTR void sleep_low_power_clock_calibration(bool is_dslp)
} else {
// If the external 32 kHz XTAL does not exist, use the internal 150 kHz RC oscillator
// as the RTC slow clock source.
s_config.rtc_clk_cal_period = rtc_clk_cal(RTC_CAL_RTC_MUX, RTC_CLK_SRC_CAL_CYCLES);
s_config.rtc_clk_cal_period = rtc_clk_cal(CLK_CAL_RTC_SLOW, RTC_CLK_SRC_CAL_CYCLES);
esp_clk_slowclk_cal_set(s_config.rtc_clk_cal_period);
}
#elif CONFIG_RTC_CLK_SRC_INT_RC && CONFIG_IDF_TARGET_ESP32S2
s_config.rtc_clk_cal_period = rtc_clk_cal_cycling(RTC_CAL_RTC_MUX, RTC_CLK_SRC_CAL_CYCLES);
s_config.rtc_clk_cal_period = rtc_clk_cal_cycling(CLK_CAL_RTC_SLOW, RTC_CLK_SRC_CAL_CYCLES);
esp_clk_slowclk_cal_set(s_config.rtc_clk_cal_period);
#else
#if CONFIG_PM_ENABLE
if ((s_lightsleep_cnt % CONFIG_PM_LIGHTSLEEP_RTC_OSC_CAL_INTERVAL == 0) || is_dslp)
#endif
{
s_config.rtc_clk_cal_period = rtc_clk_cal(RTC_CAL_RTC_MUX, RTC_CLK_SRC_CAL_CYCLES);
s_config.rtc_clk_cal_period = rtc_clk_cal(CLK_CAL_RTC_SLOW, RTC_CLK_SRC_CAL_CYCLES);
esp_clk_slowclk_cal_set(s_config.rtc_clk_cal_period);
}
#endif
@@ -850,7 +850,7 @@ static SLEEP_FN_ATTR void sleep_low_power_clock_calibration(bool is_dslp)
if ((s_lightsleep_cnt % CONFIG_PM_LIGHTSLEEP_RTC_OSC_CAL_INTERVAL == 0) || is_dslp)
#endif
{
s_config.fast_clk_cal_period = rtc_clk_cal(RTC_CAL_RC_FAST, FAST_CLK_SRC_CAL_CYCLES);
s_config.fast_clk_cal_period = rtc_clk_cal(CLK_CAL_RC_FAST, FAST_CLK_SRC_CAL_CYCLES);
}
#endif
}
@@ -31,7 +31,7 @@
#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)
static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char* name)
static uint32_t calibrate_one(soc_clk_freq_calculation_src_t cal_clk, const char* name)
{
const uint32_t cal_count = 1000;
const float factor = (1 << 19) * 1000.0f;
@@ -54,13 +54,13 @@ TEST_CASE("RTC_SLOW_CLK sources calibration", "[rtc_clk]")
// By default Kconfig, RTC_SLOW_CLK source is RC_SLOW
soc_rtc_slow_clk_src_t default_rtc_slow_clk_src = rtc_clk_slow_src_get();
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
CALIBRATE_ONE(CLK_CAL_RTC_SLOW);
#if SOC_CLK_RC_FAST_D256_SUPPORTED
CALIBRATE_ONE(RTC_CAL_8MD256);
CALIBRATE_ONE(CLK_CAL_RC_FAST_D256);
#endif
#if SOC_CLK_XTAL32K_SUPPORTED
uint32_t cal_32k = CALIBRATE_ONE(RTC_CAL_32K_XTAL);
uint32_t cal_32k = CALIBRATE_ONE(CLK_CAL_32K_XTAL);
if (cal_32k == 0) {
printf("32K XTAL OSC has not started up\n");
} else {
@@ -68,11 +68,11 @@ TEST_CASE("RTC_SLOW_CLK sources calibration", "[rtc_clk]")
rtc_clk_slow_src_set(SOC_RTC_SLOW_CLK_SRC_XTAL32K);
printf("done\n");
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
CALIBRATE_ONE(CLK_CAL_RTC_SLOW);
#if SOC_CLK_RC_FAST_D256_SUPPORTED
CALIBRATE_ONE(RTC_CAL_8MD256);
CALIBRATE_ONE(CLK_CAL_RC_FAST_D256);
#endif
CALIBRATE_ONE(RTC_CAL_32K_XTAL);
CALIBRATE_ONE(CLK_CAL_32K_XTAL);
}
#endif
@@ -81,16 +81,16 @@ TEST_CASE("RTC_SLOW_CLK sources calibration", "[rtc_clk]")
rtc_clk_slow_src_set(SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256);
printf("done\n");
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
CALIBRATE_ONE(RTC_CAL_8MD256);
CALIBRATE_ONE(CLK_CAL_RTC_SLOW);
CALIBRATE_ONE(CLK_CAL_RC_FAST_D256);
#if SOC_CLK_XTAL32K_SUPPORTED
CALIBRATE_ONE(RTC_CAL_32K_XTAL);
CALIBRATE_ONE(CLK_CAL_32K_XTAL);
#endif
#endif
#if SOC_CLK_OSC_SLOW_SUPPORTED
rtc_clk_32k_enable_external();
uint32_t cal_ext_slow_clk = CALIBRATE_ONE(RTC_CAL_32K_OSC_SLOW);
uint32_t cal_ext_slow_clk = CALIBRATE_ONE(CLK_CAL_32K_OSC_SLOW);
if (cal_ext_slow_clk == 0) {
printf("EXT CLOCK by PIN has not started up\n");
} else {
@@ -98,11 +98,11 @@ TEST_CASE("RTC_SLOW_CLK sources calibration", "[rtc_clk]")
rtc_clk_slow_src_set(SOC_RTC_SLOW_CLK_SRC_OSC_SLOW);
printf("done\n");
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
CALIBRATE_ONE(CLK_CAL_RTC_SLOW);
#if SOC_CLK_RC_FAST_D256_SUPPORTED
CALIBRATE_ONE(RTC_CAL_8MD256);
CALIBRATE_ONE(CLK_CAL_RC_FAST_D256);
#endif
CALIBRATE_ONE(RTC_CAL_32K_OSC_SLOW);
CALIBRATE_ONE(CLK_CAL_32K_OSC_SLOW);
}
#endif