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
|
config ESP32_RTC_CLK_CAL_CYCLES
|
||||||
int "Number of cycles for RTC_SLOW_CLK calibration"
|
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
|
range 0 125000
|
||||||
help
|
help
|
||||||
When the startup code initializes RTC_SLOW_CLK, it can perform
|
When the startup code initializes RTC_SLOW_CLK, it can perform
|
||||||
@ -698,12 +699,15 @@ config ESP32_RTC_CLK_CAL_CYCLES
|
|||||||
When this option is set to 0, clock calibration will not be performed at
|
When this option is set to 0, clock calibration will not be performed at
|
||||||
startup, and approximate clock frequencies will be assumed:
|
startup, and approximate clock frequencies will be assumed:
|
||||||
|
|
||||||
- 150000 Hz if internal RC oscillator is used as clock source
|
- 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
|
- 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
|
config ESP32_RTC_XTAL_BOOTSTRAP_CYCLES
|
||||||
int "Bootstrap cycles for external 32kHz crystal"
|
int "Bootstrap cycles for external 32kHz crystal"
|
||||||
default 100
|
depends on ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
|
||||||
|
default 5
|
||||||
range 0 32768
|
range 0 32768
|
||||||
help
|
help
|
||||||
To reduce the startup time of an external RTC crystal,
|
To reduce the startup time of an external RTC crystal,
|
||||||
@ -711,6 +715,12 @@ config ESP32_RTC_XTAL_BOOTSTRAP_CYCLES
|
|||||||
Setting 0 will disable bootstrapping (if disabled, the crystal may take
|
Setting 0 will disable bootstrapping (if disabled, the crystal may take
|
||||||
longer to start up or fail to oscillate under some conditions).
|
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
|
config ESP32_DEEP_SLEEP_WAKEUP_DELAY
|
||||||
int "Extra delay in deep sleep wake stub (in us)"
|
int "Extra delay in deep sleep wake stub (in us)"
|
||||||
default 2000
|
default 2000
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
* Larger values increase startup delay. Smaller values may cause false positive
|
* Larger values increase startup delay. Smaller values may cause false positive
|
||||||
* detection (i.e. oscillator runs for a few cycles and then stops).
|
* 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 SLOW_CLK_CAL_CYCLES CONFIG_ESP32_RTC_CLK_CAL_CYCLES
|
||||||
|
|
||||||
#define MHZ (1000000)
|
#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)
|
static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk)
|
||||||
{
|
{
|
||||||
uint32_t cal_val = 0;
|
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 {
|
do {
|
||||||
if (slow_clk == RTC_SLOW_FREQ_32K_XTAL) {
|
if (slow_clk == RTC_SLOW_FREQ_32K_XTAL) {
|
||||||
/* 32k XTAL oscillator needs to be enabled and running before it can
|
/* 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
|
* oscillator cycles. If the 32k XTAL has not started up, calibration
|
||||||
* will time out, returning 0.
|
* 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");
|
ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up");
|
||||||
do {
|
|
||||||
++wait;
|
|
||||||
rtc_clk_32k_enable(true);
|
rtc_clk_32k_enable(true);
|
||||||
cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, XTAL_32K_DETECT_CYCLES);
|
cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES);
|
||||||
if (wait % warning_timeout == 0) {
|
if(cal_val == 0 || cal_val < 15000000L){
|
||||||
ESP_EARLY_LOGW(TAG, "still waiting for 32k oscillator to start up");
|
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;
|
||||||
}
|
}
|
||||||
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_slow_freq_set(slow_clk);
|
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) {
|
if (SLOW_CLK_CAL_CYCLES > 0) {
|
||||||
/* TODO: 32k XTAL oscillator has some frequency drift at startup.
|
/* 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;
|
const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL;
|
||||||
cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz());
|
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);
|
} while (cal_val == 0);
|
||||||
ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val);
|
ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val);
|
||||||
esp_clk_slowclk_cal_set(cal_val);
|
esp_clk_slowclk_cal_set(cal_val);
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
#include "../esp_clk_internal.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 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(){
|
void stop_rtc_external_quartz(){
|
||||||
const uint8_t pin_32 = 32;
|
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
|
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
|
#ifdef CONFIG_SPIRAM_SUPPORT
|
||||||
// PSRAM tests run on ESP-WROVER-KIT boards, which have the 32k XTAL installed.
|
// 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.
|
// 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;
|
int i = 0, fail = 0;
|
||||||
uint32_t start_time;
|
uint32_t start_time;
|
||||||
uint32_t end_time;
|
uint32_t end_time;
|
||||||
|
|
||||||
stop_rtc_external_quartz();
|
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){
|
while(i < COUNT_TEST){
|
||||||
start_time = xTaskGetTickCount() * (1000 / configTICK_RATE_HZ);
|
start_time = xTaskGetTickCount() * (1000 / configTICK_RATE_HZ);
|
||||||
i++;
|
i++;
|
||||||
printf("attempt #%d/%d...", i, COUNT_TEST);
|
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();
|
rtc_clk_select_rtc_slow_clk();
|
||||||
end_time = xTaskGetTickCount() * (1000 / configTICK_RATE_HZ);
|
end_time = xTaskGetTickCount() * (1000 / configTICK_RATE_HZ);
|
||||||
|
printf(" [time=%d] ", end_time - start_time);
|
||||||
if((end_time - start_time) > TIMEOUT_TEST_MS){
|
if((end_time - start_time) > TIMEOUT_TEST_MS){
|
||||||
printf("FAIL\n");
|
printf("FAIL\n");
|
||||||
fail = 1;
|
fail = 1;
|
||||||
@ -178,11 +254,30 @@ TEST_CASE("Test starting external RTC quartz", "[rtc_clk]")
|
|||||||
stop_rtc_external_quartz();
|
stop_rtc_external_quartz();
|
||||||
ets_delay_us(100000);
|
ets_delay_us(100000);
|
||||||
}
|
}
|
||||||
if (fail == 1){
|
TEST_ASSERT_MESSAGE(fail == 0, "Test failed");
|
||||||
printf("Test failed\n");
|
|
||||||
TEST_ASSERT(false);
|
|
||||||
} else {
|
|
||||||
printf("Test passed successfully\n");
|
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
|
#endif // CONFIG_SPIRAM_SUPPORT
|
||||||
|
Loading…
x
Reference in New Issue
Block a user