config ESP32_RTC_CLK_CAL_CYCLES
int "Number of cycles for RTC_SLOW_CLK calibration"
- default 1024
+ default 3000 if ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
+ default 1024 if ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC
range 0 125000
help
When the startup code initializes RTC_SLOW_CLK, it can perform
When this option is set to 0, clock calibration will not be performed at
startup, and approximate clock frequencies will be assumed:
- - 150000 Hz if internal RC oscillator is used as clock source
- - 32768 Hz if the 32k crystal oscillator is used
+ - 150000 Hz if internal RC oscillator is used as clock source. For this use value 1024.
+ - 32768 Hz if the 32k crystal oscillator is used. For this use value 3000 or more.
+ In case more value will help improve the definition of the launch of the crystal.
+ If the crystal could not start, it will be switched to internal RC.
config ESP32_RTC_XTAL_BOOTSTRAP_CYCLES
int "Bootstrap cycles for external 32kHz crystal"
- default 100
+ depends on ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
+ default 5
range 0 32768
help
To reduce the startup time of an external RTC crystal,
we bootstrap it with a 32kHz square wave for a fixed number of cycles.
Setting 0 will disable bootstrapping (if disabled, the crystal may take
longer to start up or fail to oscillate under some conditions).
+
+ If this value is too high, a faulty crystal may initially start and then fail.
+ If this value is too low, an otherwise good crystal may not start.
+
+ To accurately determine if the crystal has started,
+ set a larger "Number of cycles for RTC_SLOW_CLK calibration" (about 3000).
config ESP32_DEEP_SLEEP_WAKEUP_DELAY
int "Extra delay in deep sleep wake stub (in us)"
* Larger values increase startup delay. Smaller values may cause false positive
* detection (i.e. oscillator runs for a few cycles and then stops).
*/
-#define XTAL_32K_DETECT_CYCLES 32
#define SLOW_CLK_CAL_CYCLES CONFIG_ESP32_RTC_CLK_CAL_CYCLES
#define MHZ (1000000)
static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk)
{
uint32_t cal_val = 0;
+ uint32_t wait = 0;
+ const uint32_t warning_timeout = 3 /* sec */ * 32768 /* Hz */ / (2 * SLOW_CLK_CAL_CYCLES);
+ bool changing_clock_to_150k = false;
do {
if (slow_clk == RTC_SLOW_FREQ_32K_XTAL) {
/* 32k XTAL oscillator needs to be enabled and running before it can
* oscillator cycles. If the 32k XTAL has not started up, calibration
* will time out, returning 0.
*/
- uint32_t wait = 0;
- // increment of 'wait' counter equivalent to 3 seconds
- const uint32_t warning_timeout = 3 /* sec */ * 32768 /* Hz */ / (2 * XTAL_32K_DETECT_CYCLES);
ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up");
- do {
- ++wait;
- rtc_clk_32k_enable(true);
- cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, XTAL_32K_DETECT_CYCLES);
- if (wait % warning_timeout == 0) {
- ESP_EARLY_LOGW(TAG, "still waiting for 32k oscillator to start up");
- }
- if(cal_val == 0){
- rtc_clk_32k_enable(false);
- rtc_clk_32k_bootstrap(CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES);
- }
- } while (cal_val == 0);
+ rtc_clk_32k_enable(true);
+ cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES);
+ if(cal_val == 0 || cal_val < 15000000L){
+ ESP_EARLY_LOGE(TAG, "RTC: Not found External 32 kHz XTAL. Switching to Internal 150 kHz RC chain");
+ slow_clk = RTC_SLOW_FREQ_RTC;
+ changing_clock_to_150k = true;
+ }
}
rtc_clk_slow_freq_set(slow_clk);
+ if (changing_clock_to_150k == true && wait > 1){
+ // This helps when there are errors when switching the clock from External 32 kHz XTAL to Internal 150 kHz RC chain.
+ rtc_clk_32k_enable(false);
+ uint32_t min_bootstrap = 5; // Min bootstrapping for continue switching the clock.
+ rtc_clk_32k_bootstrap(min_bootstrap);
+ rtc_clk_32k_enable(true);
+ }
if (SLOW_CLK_CAL_CYCLES > 0) {
/* TODO: 32k XTAL oscillator has some frequency drift at startup.
const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL;
cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz());
}
+ if (++wait % warning_timeout == 0) {
+ ESP_EARLY_LOGW(TAG, "still waiting for source selection RTC");
+ }
} while (cal_val == 0);
ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val);
esp_clk_slowclk_cal_set(cal_val);
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "../esp_clk_internal.h"
+#include "esp_clk.h"
}
#define COUNT_TEST 10
-#define TIMEOUT_TEST_MS 50
+#define TIMEOUT_TEST_MS (5 + CONFIG_ESP32_RTC_CLK_CAL_CYCLES / 16)
void stop_rtc_external_quartz(){
const uint8_t pin_32 = 32;
gpio_output_set_high(0, 0, 0, mask_32 | mask_33); // disable pins
}
+static void start_freq(rtc_slow_freq_t required_src_freq, uint32_t start_delay_ms)
+{
+ int i = 0, fail = 0;
+ uint32_t start_time;
+ uint32_t end_time;
+ rtc_slow_freq_t selected_src_freq;
+ stop_rtc_external_quartz();
+#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
+ uint32_t bootstrap_cycles = CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES;
+ printf("Test is started. Kconfig settings:\n External 32K crystal is selected,\n Oscillation cycles = %d,\n Calibration cycles = %d.\n",
+ bootstrap_cycles,
+ CONFIG_ESP32_RTC_CLK_CAL_CYCLES);
+#else
+ uint32_t bootstrap_cycles = 5;
+ printf("Test is started. Kconfig settings:\n Internal RC is selected,\n Oscillation cycles = %d,\n Calibration cycles = %d.\n",
+ bootstrap_cycles,
+ CONFIG_ESP32_RTC_CLK_CAL_CYCLES);
+#endif
+ if (start_delay_ms == 0 && CONFIG_ESP32_RTC_CLK_CAL_CYCLES < 1500){
+ start_delay_ms = 50;
+ printf("Recommended increase Number of cycles for RTC_SLOW_CLK calibration to 3000!\n");
+ }
+ while(i < COUNT_TEST){
+ start_time = xTaskGetTickCount() * (1000 / configTICK_RATE_HZ);
+ i++;
+ printf("attempt #%d/%d...", i, COUNT_TEST);
+ rtc_clk_32k_bootstrap(bootstrap_cycles);
+ ets_delay_us(start_delay_ms * 1000);
+ rtc_clk_select_rtc_slow_clk();
+ selected_src_freq = rtc_clk_slow_freq_get();
+ end_time = xTaskGetTickCount() * (1000 / configTICK_RATE_HZ);
+ printf(" [time=%d] ", (end_time - start_time) - start_delay_ms);
+ if(selected_src_freq != required_src_freq){
+ printf("FAIL. Time measurement...");
+ fail = 1;
+ } else {
+ printf("PASS. Time measurement...");
+ }
+ uint64_t clk_rtc_time;
+ uint32_t fail_measure = 0;
+ for (int j = 0; j < 3; ++j) {
+ clk_rtc_time = esp_clk_rtc_time();
+ ets_delay_us(1000000);
+ uint64_t delta = esp_clk_rtc_time() - clk_rtc_time;
+ if (delta < 900000LL || delta > 1100000){
+ printf("FAIL");
+ fail = 1;
+ fail_measure = 1;
+ break;
+ }
+ }
+ if(fail_measure == 0) {
+ printf("PASS");
+ }
+ printf(" [calibration val = %d] \n", esp_clk_slowclk_cal_get());
+ stop_rtc_external_quartz();
+ ets_delay_us(500000);
+ }
+ TEST_ASSERT_MESSAGE(fail == 0, "Test failed");
+ printf("Test passed successfully\n");
+}
+
#ifdef CONFIG_SPIRAM_SUPPORT
// PSRAM tests run on ESP-WROVER-KIT boards, which have the 32k XTAL installed.
// Other tests may run on DevKitC boards, which don't have a 32k XTAL.
int i = 0, fail = 0;
uint32_t start_time;
uint32_t end_time;
-
stop_rtc_external_quartz();
- printf("Start test. Number of oscillation cycles = %d\n", CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES);
+#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
+ uint32_t bootstrap_cycles = CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES;
+ printf("Test is started. Kconfig settings:\n External 32K crystal is selected,\n Oscillation cycles = %d,\n Calibration cycles = %d.\n",
+ bootstrap_cycles,
+ CONFIG_ESP32_RTC_CLK_CAL_CYCLES);
+#else
+ uint32_t bootstrap_cycles = 5;
+ printf("Test is started. Kconfig settings:\n Internal RC is selected,\n Oscillation cycles = %d,\n Calibration cycles = %d.\n",
+ bootstrap_cycles,
+ CONFIG_ESP32_RTC_CLK_CAL_CYCLES);
+#endif
+ if (CONFIG_ESP32_RTC_CLK_CAL_CYCLES < 1500){
+ printf("Recommended increase Number of cycles for RTC_SLOW_CLK calibration to 3000!\n");
+ }
while(i < COUNT_TEST){
start_time = xTaskGetTickCount() * (1000 / configTICK_RATE_HZ);
i++;
printf("attempt #%d/%d...", i, COUNT_TEST);
- rtc_clk_32k_bootstrap(CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES);
+ rtc_clk_32k_bootstrap(bootstrap_cycles);
rtc_clk_select_rtc_slow_clk();
end_time = xTaskGetTickCount() * (1000 / configTICK_RATE_HZ);
+ printf(" [time=%d] ", end_time - start_time);
if((end_time - start_time) > TIMEOUT_TEST_MS){
printf("FAIL\n");
fail = 1;
stop_rtc_external_quartz();
ets_delay_us(100000);
}
- if (fail == 1){
- printf("Test failed\n");
- TEST_ASSERT(false);
- } else {
- printf("Test passed successfully\n");
- }
+ TEST_ASSERT_MESSAGE(fail == 0, "Test failed");
+ printf("Test passed successfully\n");
}
+
+TEST_CASE("Test starting 'External 32kHz XTAL' on the board with it.", "[rtc_clk]")
+{
+ start_freq(RTC_SLOW_FREQ_32K_XTAL, 200);
+ start_freq(RTC_SLOW_FREQ_32K_XTAL, 0);
+}
+
+#else
+
+TEST_CASE("Test starting 'External 32kHz XTAL' on the board without it.", "[rtc_clk]")
+{
+ printf("Tries to start the 'External 32kHz XTAL' on the board without it. "
+ "Clock switching to 'Internal 150 kHz RC oscillator'.\n");
+
+ printf("This test will be successful for boards without an external crystal or non-working crystal. "
+ "First, there will be an attempt to start from the external crystal after a failure "
+ "will switch to the internal RC circuit. If the switch to the internal RC circuit "
+ "was successful then the test succeeded.\n");
+
+ start_freq(RTC_SLOW_FREQ_RTC, 200);
+ start_freq(RTC_SLOW_FREQ_RTC, 0);
+}
+
#endif // CONFIG_SPIRAM_SUPPORT