From 13984c0a79f326b3ee326560ff677a2f89e552b2 Mon Sep 17 00:00:00 2001 From: jingli Date: Thu, 11 Aug 2022 11:48:50 +0800 Subject: [PATCH 1/2] esp_hw_support/clk_cali: fix xtal32k error detect --- components/esp_hw_support/port/esp32/rtc_time.c | 12 ++++++++++++ components/esp_hw_support/port/esp32c3/rtc_time.c | 12 ++++++++++++ components/esp_hw_support/port/esp32h2/rtc_time.c | 12 ++++++++++++ components/esp_hw_support/port/esp32s2/rtc_time.c | 15 +++++++++++++-- components/esp_hw_support/port/esp32s3/rtc_time.c | 12 ++++++++++++ components/soc/esp32/include/soc/rtc.h | 5 +++++ components/soc/esp32c3/include/soc/rtc.h | 5 +++++ components/soc/esp32h2/include/soc/rtc.h | 5 +++++ components/soc/esp32s2/include/soc/rtc.h | 5 +++++ components/soc/esp32s3/include/soc/rtc.h | 5 +++++ 10 files changed, 86 insertions(+), 2 deletions(-) diff --git a/components/esp_hw_support/port/esp32/rtc_time.c b/components/esp_hw_support/port/esp32/rtc_time.c index 8345c55d4a..846c0c36dc 100644 --- a/components/esp_hw_support/port/esp32/rtc_time.c +++ b/components/esp_hw_support/port/esp32/rtc_time.c @@ -109,10 +109,22 @@ uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles) return ratio; } +static inline bool rtc_clk_cal_32k_valid(rtc_xtal_freq_t xtal_freq, uint32_t slowclk_cycles, uint64_t actual_xtal_cycles) +{ + uint64_t expected_xtal_cycles = (xtal_freq * 1000000ULL * slowclk_cycles) >> 15; // xtal_freq(hz) * slowclk_cycles / 32768 + uint64_t delta = expected_xtal_cycles / 2000; // 5/10000 + 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) { rtc_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(xtal_freq, slowclk_cycles, xtal_cycles)) { + return 0; + } + uint64_t divider = ((uint64_t)xtal_freq) * slowclk_cycles; uint64_t period_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT) + divider / 2 - 1) / divider; uint32_t period = (uint32_t)(period_64 & UINT32_MAX); diff --git a/components/esp_hw_support/port/esp32c3/rtc_time.c b/components/esp_hw_support/port/esp32c3/rtc_time.c index 55d1048c66..ecf840e3e5 100644 --- a/components/esp_hw_support/port/esp32c3/rtc_time.c +++ b/components/esp_hw_support/port/esp32c3/rtc_time.c @@ -125,10 +125,22 @@ uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles) return ratio; } +static bool rtc_clk_cal_32k_valid(rtc_xtal_freq_t xtal_freq, uint32_t slowclk_cycles, uint64_t actual_xtal_cycles) +{ + uint64_t expected_xtal_cycles = (xtal_freq * 1000000ULL * slowclk_cycles) >> 15; // xtal_freq(hz) * slowclk_cycles / 32768 + uint64_t delta = expected_xtal_cycles / 2000; // 5/10000 + 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) { rtc_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(xtal_freq, slowclk_cycles, xtal_cycles)) { + return 0; + } + uint64_t divider = ((uint64_t)xtal_freq) * slowclk_cycles; uint64_t period_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT) + divider / 2 - 1) / divider; uint32_t period = (uint32_t)(period_64 & UINT32_MAX); diff --git a/components/esp_hw_support/port/esp32h2/rtc_time.c b/components/esp_hw_support/port/esp32h2/rtc_time.c index 44f47aff53..a328664a49 100644 --- a/components/esp_hw_support/port/esp32h2/rtc_time.c +++ b/components/esp_hw_support/port/esp32h2/rtc_time.c @@ -118,10 +118,22 @@ uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles) return ratio; } +static inline bool rtc_clk_cal_32k_valid(rtc_xtal_freq_t xtal_freq, uint32_t slowclk_cycles, uint64_t actual_xtal_cycles) +{ + uint64_t expected_xtal_cycles = (xtal_freq * 1000000ULL * slowclk_cycles) >> 15; // xtal_freq(hz) * slowclk_cycles / 32768 + uint64_t delta = expected_xtal_cycles / 2000; // 5/10000 + 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) { rtc_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(xtal_freq, slowclk_cycles, xtal_cycles)) { + return 0; + } + uint64_t divider = ((uint64_t)xtal_freq) * slowclk_cycles; uint64_t period_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT) + divider / 2 - 1) / divider; uint32_t period = (uint32_t)(period_64 & UINT32_MAX); diff --git a/components/esp_hw_support/port/esp32s2/rtc_time.c b/components/esp_hw_support/port/esp32s2/rtc_time.c index 4dca202b23..8139dce83a 100644 --- a/components/esp_hw_support/port/esp32s2/rtc_time.c +++ b/components/esp_hw_support/port/esp32s2/rtc_time.c @@ -186,11 +186,22 @@ uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles) return ratio; } +static inline bool rtc_clk_cal_32k_valid(rtc_xtal_freq_t xtal_freq, uint32_t slowclk_cycles, uint64_t actual_xtal_cycles) +{ + uint64_t expected_xtal_cycles = (xtal_freq * 1000000ULL * slowclk_cycles) >> 15; // xtal_freq(hz) * slowclk_cycles / 32768 + uint64_t delta = expected_xtal_cycles / 2000; // 5/10000 + 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) { uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles, RTC_TIME_CAL_ONEOFF_MODE); - uint32_t period = rtc_clk_xtal_to_slowclk(xtal_cycles, slowclk_cycles); - return period; + + if ((cal_clk == RTC_CAL_32K_XTAL) && !rtc_clk_cal_32k_valid(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) diff --git a/components/esp_hw_support/port/esp32s3/rtc_time.c b/components/esp_hw_support/port/esp32s3/rtc_time.c index ed7eaabda2..5e8c982cb3 100644 --- a/components/esp_hw_support/port/esp32s3/rtc_time.c +++ b/components/esp_hw_support/port/esp32s3/rtc_time.c @@ -123,10 +123,22 @@ uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles) return ratio; } +static inline bool rtc_clk_cal_32k_valid(rtc_xtal_freq_t xtal_freq, uint32_t slowclk_cycles, uint64_t actual_xtal_cycles) +{ + uint64_t expected_xtal_cycles = (xtal_freq * 1000000ULL * slowclk_cycles) >> 15; // xtal_freq(hz) * slowclk_cycles / 32768 + uint64_t delta = expected_xtal_cycles / 2000; // 5/10000 + 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) { rtc_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(xtal_freq, slowclk_cycles, xtal_cycles)) { + return 0; + } + uint64_t divider = ((uint64_t)xtal_freq) * slowclk_cycles; uint64_t period_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT) + divider / 2 - 1) / divider; uint32_t period = (uint32_t)(period_64 & UINT32_MAX); diff --git a/components/soc/esp32/include/soc/rtc.h b/components/soc/esp32/include/soc/rtc.h index b336cb2a7d..033a877a07 100644 --- a/components/soc/esp32/include/soc/rtc.h +++ b/components/soc/esp32/include/soc/rtc.h @@ -403,6 +403,11 @@ 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). * + * @note When 32k CLK is being calibrated, this function will check the accuracy + * of the clock. Since the xtal 32k or ext osc 32k is generally very stable, if + * 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 slow_clk_cycles number of slow clock cycles to average * @return average slow clock period in microseconds, Q13.19 fixed point format, diff --git a/components/soc/esp32c3/include/soc/rtc.h b/components/soc/esp32c3/include/soc/rtc.h index 56e089cb77..75a19cc094 100644 --- a/components/soc/esp32c3/include/soc/rtc.h +++ b/components/soc/esp32c3/include/soc/rtc.h @@ -510,6 +510,11 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles); * 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). * + * @note When 32k CLK is being calibrated, this function will check the accuracy + * of the clock. Since the xtal 32k or ext osc 32k is generally very stable, if + * 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 slow_clk_cycles number of slow clock cycles to average * @return average slow clock period in microseconds, Q13.19 fixed point format, diff --git a/components/soc/esp32h2/include/soc/rtc.h b/components/soc/esp32h2/include/soc/rtc.h index 596e130588..f93e6fafdd 100644 --- a/components/soc/esp32h2/include/soc/rtc.h +++ b/components/soc/esp32h2/include/soc/rtc.h @@ -526,6 +526,11 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles); * 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). * + * @note When 32k CLK is being calibrated, this function will check the accuracy + * of the clock. Since the xtal 32k or ext osc 32k is generally very stable, if + * 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 slow_clk_cycles number of slow clock cycles to average * @return average slow clock period in microseconds, Q13.19 fixed point format, diff --git a/components/soc/esp32s2/include/soc/rtc.h b/components/soc/esp32s2/include/soc/rtc.h index 12cb8ba1e8..c23f73d514 100644 --- a/components/soc/esp32s2/include/soc/rtc.h +++ b/components/soc/esp32s2/include/soc/rtc.h @@ -540,6 +540,11 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles, ui * 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). * + * @note When 32k CLK is being calibrated, this function will check the accuracy + * of the clock. Since the xtal 32k or ext osc 32k is generally very stable, if + * 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 slow_clk_cycles number of slow clock cycles to average * @return average slow clock period in microseconds, Q13.19 fixed point format, diff --git a/components/soc/esp32s3/include/soc/rtc.h b/components/soc/esp32s3/include/soc/rtc.h index 2f5e867d01..9dd3aad316 100644 --- a/components/soc/esp32s3/include/soc/rtc.h +++ b/components/soc/esp32s3/include/soc/rtc.h @@ -522,6 +522,11 @@ uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles); * 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). * + * @note When 32k CLK is being calibrated, this function will check the accuracy + * of the clock. Since the xtal 32k or ext osc 32k is generally very stable, if + * 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 slow_clk_cycles number of slow clock cycles to average * @return average slow clock period in microseconds, Q13.19 fixed point format, From 9a61a07fd86f0868898f7b4dee48cba17b5f3701 Mon Sep 17 00:00:00 2001 From: jingli Date: Tue, 20 Sep 2022 20:01:17 +0800 Subject: [PATCH 2/2] esp_hw_support/clk_cali: remove redundant check for cali value --- components/esp_system/port/soc/esp32/clk.c | 7 +------ components/esp_system/port/soc/esp32c3/clk.c | 7 +------ components/esp_system/port/soc/esp32h2/clk.c | 7 +------ components/esp_system/port/soc/esp32s2/clk.c | 7 +------ components/esp_system/port/soc/esp32s3/clk.c | 7 +------ 5 files changed, 5 insertions(+), 30 deletions(-) diff --git a/components/esp_system/port/soc/esp32/clk.c b/components/esp_system/port/soc/esp32/clk.c index 3b3f2b7329..15cdc83e06 100644 --- a/components/esp_system/port/soc/esp32/clk.c +++ b/components/esp_system/port/soc/esp32/clk.c @@ -37,11 +37,6 @@ static const char* TAG = "clk"; #define RTC_XTAL_CAL_RETRY 1 #endif -/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. - * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. - */ -#define MIN_32K_XTAL_CAL_VAL 15000000L - /* Indicates that this 32k oscillator gets input from external oscillator, rather * than a crystal. */ @@ -85,7 +80,7 @@ static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. if (SLOW_CLK_CAL_CYCLES > 0) { cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); - if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { + if (cal_val == 0) { if (retry_32k_xtal-- > 0) { continue; } diff --git a/components/esp_system/port/soc/esp32c3/clk.c b/components/esp_system/port/soc/esp32c3/clk.c index 5f86775173..e7f8a9dfdc 100644 --- a/components/esp_system/port/soc/esp32c3/clk.c +++ b/components/esp_system/port/soc/esp32c3/clk.c @@ -37,11 +37,6 @@ #define MHZ (1000000) -/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. - * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. - */ -#define MIN_32K_XTAL_CAL_VAL 15000000L - /* Indicates that this 32k oscillator gets input from external oscillator, rather * than a crystal. */ @@ -164,7 +159,7 @@ static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. if (SLOW_CLK_CAL_CYCLES > 0) { cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); - if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { + if (cal_val == 0) { if (retry_32k_xtal-- > 0) { continue; } diff --git a/components/esp_system/port/soc/esp32h2/clk.c b/components/esp_system/port/soc/esp32h2/clk.c index 7ea2dde1ae..d946f142dd 100644 --- a/components/esp_system/port/soc/esp32h2/clk.c +++ b/components/esp_system/port/soc/esp32h2/clk.c @@ -37,11 +37,6 @@ #define MHZ (1000000) -/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. - * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. - */ -#define MIN_32K_XTAL_CAL_VAL 15000000L - /* Indicates that this 32k oscillator gets input from external oscillator, rather * than a crystal. */ @@ -158,7 +153,7 @@ static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. if (SLOW_CLK_CAL_CYCLES > 0) { cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); - if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { + if (cal_val == 0) { if (retry_32k_xtal-- > 0) { continue; } diff --git a/components/esp_system/port/soc/esp32s2/clk.c b/components/esp_system/port/soc/esp32s2/clk.c index f1eb0bee55..76012792d6 100644 --- a/components/esp_system/port/soc/esp32s2/clk.c +++ b/components/esp_system/port/soc/esp32s2/clk.c @@ -42,11 +42,6 @@ static const char *TAG = "clk"; #define RTC_XTAL_CAL_RETRY 1 #endif -/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. - * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. - */ -#define MIN_32K_XTAL_CAL_VAL 15000000L - /* Indicates that this 32k oscillator gets input from external oscillator, rather * than a crystal. */ @@ -168,7 +163,7 @@ static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. if (SLOW_CLK_CAL_CYCLES > 0) { cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); - if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { + if (cal_val == 0) { if (retry_32k_xtal-- > 0) { continue; } diff --git a/components/esp_system/port/soc/esp32s3/clk.c b/components/esp_system/port/soc/esp32s3/clk.c index ca2f282820..122e41d40f 100644 --- a/components/esp_system/port/soc/esp32s3/clk.c +++ b/components/esp_system/port/soc/esp32s3/clk.c @@ -41,11 +41,6 @@ static const char *TAG = "clk"; #define RTC_XTAL_CAL_RETRY 1 #endif -/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. - * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. - */ -#define MIN_32K_XTAL_CAL_VAL 15000000L - /* Indicates that this 32k oscillator gets input from external oscillator, rather * than a crystal. */ @@ -162,7 +157,7 @@ static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. if (SLOW_CLK_CAL_CYCLES > 0) { cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); - if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { + if (cal_val == 0) { if (retry_32k_xtal-- > 0) { continue; }