mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'bugfix/select_rtc_slow_clk' into 'master'
esp32/clk: Fix starting rtc oscillator if it bad See merge request idf/esp-idf!2215
This commit is contained in:
commit
662fe55996
@ -685,7 +685,8 @@ endchoice
|
||||
|
||||
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
|
||||
@ -698,18 +699,27 @@ config ESP32_RTC_CLK_CAL_CYCLES
|
||||
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)"
|
||||
|
@ -36,7 +36,6 @@
|
||||
* 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)
|
||||
@ -128,6 +127,9 @@ void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us)
|
||||
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
|
||||
@ -137,24 +139,23 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk)
|
||||
* 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.
|
||||
@ -165,6 +166,9 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk)
|
||||
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);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "../esp_clk_internal.h"
|
||||
#include "esp_clk.h"
|
||||
|
||||
|
||||
|
||||
@ -134,7 +135,7 @@ TEST_CASE("Test fast switching between PLL and XTAL", "[rtc_clk]")
|
||||
}
|
||||
|
||||
#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;
|
||||
@ -151,6 +152,68 @@ void stop_rtc_external_quartz(){
|
||||
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.
|
||||
@ -159,16 +222,29 @@ TEST_CASE("Test starting external RTC quartz", "[rtc_clk]")
|
||||
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;
|
||||
@ -178,11 +254,30 @@ TEST_CASE("Test starting external RTC quartz", "[rtc_clk]")
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user