mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-09 20:41:14 +00:00
esp32s2: fix enabling 32k XTAL clock
On the ESP32S2, rtc_clk_cal(RTC_CAL_RTC_MUX) measures the frequency of the 90kHz RTC clock regardless of the selected slow clock frequency. Keep track which clock is selected and pass the argument to rtc_clk_cal accordingly. fix clock choices update rtc 32k xtal code for s2 missed api in rtc.h bootloader_clock: update for S2
This commit is contained in:
@@ -54,9 +54,8 @@ void bootloader_clock_configure(void)
|
|||||||
rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
|
rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
|
clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
|
||||||
clk_cfg.xtal_freq = RTC_XTAL_FREQ_40M;
|
|
||||||
#endif
|
#endif
|
||||||
|
/* ESP32-S2 doesn't have XTAL_FREQ choice, always 40MHz */
|
||||||
clk_cfg.cpu_freq_mhz = cpu_freq_mhz;
|
clk_cfg.cpu_freq_mhz = cpu_freq_mhz;
|
||||||
clk_cfg.slow_freq = rtc_clk_slow_freq_get();
|
clk_cfg.slow_freq = rtc_clk_slow_freq_get();
|
||||||
clk_cfg.fast_freq = rtc_clk_fast_freq_get();
|
clk_cfg.fast_freq = rtc_clk_fast_freq_get();
|
||||||
@@ -66,11 +65,20 @@ void bootloader_clock_configure(void)
|
|||||||
* part of the start up time by enabling 32k XTAL early.
|
* part of the start up time by enabling 32k XTAL early.
|
||||||
* App startup code will wait until the oscillator has started up.
|
* App startup code will wait until the oscillator has started up.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS
|
|
||||||
|
/* TODO: move the clock option into esp_system, so that this doesn't have
|
||||||
|
* to continue:
|
||||||
|
*/
|
||||||
|
#if CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS
|
||||||
if (!rtc_clk_32k_enabled()) {
|
if (!rtc_clk_32k_enabled()) {
|
||||||
rtc_clk_32k_bootstrap(CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES);
|
rtc_clk_32k_bootstrap(CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS
|
||||||
|
if (!rtc_clk_32k_enabled()) {
|
||||||
|
rtc_clk_32k_bootstrap(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BOOTLOADER_BUILD
|
#ifdef BOOTLOADER_BUILD
|
||||||
|
@@ -431,10 +431,31 @@ menu "ESP32S2-specific"
|
|||||||
help
|
help
|
||||||
Choose which clock is used as RTC clock source.
|
Choose which clock is used as RTC clock source.
|
||||||
|
|
||||||
|
- "Internal 90kHz oscillator" option provides lowest deep sleep current
|
||||||
|
consumption, and does not require extra external components. However
|
||||||
|
frequency stability with respect to temperature is poor, so time may
|
||||||
|
drift in deep/light sleep modes.
|
||||||
|
- "External 32kHz crystal" provides better frequency stability, at the
|
||||||
|
expense of slightly higher (1uA) deep sleep current consumption.
|
||||||
|
- "External 32kHz oscillator" allows using 32kHz clock generated by an
|
||||||
|
external circuit. In this case, external clock signal must be connected
|
||||||
|
to 32K_XP pin. Amplitude should be <1.2V in case of sine wave signal,
|
||||||
|
and <1V in case of square wave signal. Common mode voltage should be
|
||||||
|
0.1 < Vcm < 0.5Vamp, where Vamp is the signal amplitude.
|
||||||
|
Additionally, 1nF capacitor must be connected between 32K_XN pin and
|
||||||
|
ground. 32K_XN pin can not be used as a GPIO in this case.
|
||||||
|
- "Internal 8MHz oscillator divided by 256" option results in higher
|
||||||
|
deep sleep current (by 5uA) but has better frequency stability than
|
||||||
|
the internal 90kHz oscillator. It does not require external components.
|
||||||
|
|
||||||
config ESP32S2_RTC_CLK_SRC_INT_RC
|
config ESP32S2_RTC_CLK_SRC_INT_RC
|
||||||
bool "Internal 150kHz RC oscillator"
|
bool "Internal 90kHz RC oscillator"
|
||||||
config ESP32S2_RTC_CLK_SRC_EXT_CRYS
|
config ESP32S2_RTC_CLK_SRC_EXT_CRYS
|
||||||
bool "External 32kHz crystal"
|
bool "External 32kHz crystal"
|
||||||
|
config ESP32S2_RTC_CLK_SRC_EXT_OSC
|
||||||
|
bool "External 32kHz oscillator at 32K_XP pin"
|
||||||
|
config ESP32S2_RTC_CLK_SRC_INT_8MD256
|
||||||
|
bool "Internal 8MHz oscillator, divided by 256 (~32kHz)"
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
config ESP32S2_RTC_CLK_CAL_CYCLES
|
config ESP32S2_RTC_CLK_CAL_CYCLES
|
||||||
|
@@ -44,10 +44,29 @@
|
|||||||
|
|
||||||
#define MHZ (1000000)
|
#define MHZ (1000000)
|
||||||
|
|
||||||
static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk);
|
/* 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.
|
||||||
|
*/
|
||||||
|
#define EXT_OSC_FLAG BIT(3)
|
||||||
|
|
||||||
|
/* This is almost the same as rtc_slow_freq_t, except that we define
|
||||||
|
* an extra enum member for the external 32k oscillator.
|
||||||
|
* For convenience, lower 2 bits should correspond to rtc_slow_freq_t values.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
SLOW_CLK_RTC = RTC_SLOW_FREQ_RTC, //!< Internal 90 kHz RC oscillator
|
||||||
|
SLOW_CLK_32K_XTAL = RTC_SLOW_FREQ_32K_XTAL, //!< External 32 kHz XTAL
|
||||||
|
SLOW_CLK_8MD256 = RTC_SLOW_FREQ_8MD256, //!< Internal 8 MHz RC oscillator, divided by 256
|
||||||
|
SLOW_CLK_32K_EXT_OSC = RTC_SLOW_FREQ_32K_XTAL | EXT_OSC_FLAG //!< External 32k oscillator connected to 32K_XP pin
|
||||||
|
} slow_clk_sel_t;
|
||||||
|
|
||||||
|
static void select_rtc_slow_clk(slow_clk_sel_t slow_clk);
|
||||||
|
|
||||||
// g_ticks_us defined in ROMs for PRO CPU
|
|
||||||
extern uint32_t g_ticks_per_us_pro;
|
|
||||||
static const char *TAG = "clk";
|
static const char *TAG = "clk";
|
||||||
|
|
||||||
|
|
||||||
@@ -72,8 +91,12 @@ void esp_clk_init(void)
|
|||||||
rtc_wdt_protect_on();
|
rtc_wdt_protect_on();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS
|
#if defined(CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS)
|
||||||
select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL);
|
select_rtc_slow_clk(SLOW_CLK_32K_XTAL);
|
||||||
|
#elif defined(CONFIG_ESP32S2_RTC_CLK_SRC_EXT_OSC)
|
||||||
|
select_rtc_slow_clk(SLOW_CLK_32K_EXT_OSC);
|
||||||
|
#elif defined(CONFIG_ESP32S2_RTC_CLK_SRC_INT_8MD256)
|
||||||
|
select_rtc_slow_clk(SLOW_CLK_8MD256);
|
||||||
#else
|
#else
|
||||||
select_rtc_slow_clk(RTC_SLOW_FREQ_RTC);
|
select_rtc_slow_clk(RTC_SLOW_FREQ_RTC);
|
||||||
#endif
|
#endif
|
||||||
@@ -106,28 +129,29 @@ void esp_clk_init(void)
|
|||||||
|
|
||||||
int IRAM_ATTR esp_clk_cpu_freq(void)
|
int IRAM_ATTR esp_clk_cpu_freq(void)
|
||||||
{
|
{
|
||||||
return g_ticks_per_us_pro * 1000000;
|
return ets_get_cpu_frequency() * 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
int IRAM_ATTR esp_clk_apb_freq(void)
|
int IRAM_ATTR esp_clk_apb_freq(void)
|
||||||
{
|
{
|
||||||
return MIN(g_ticks_per_us_pro, 80) * 1000000;
|
return MIN(ets_get_cpu_frequency(), 80) * 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us)
|
static void select_rtc_slow_clk(slow_clk_sel_t slow_clk)
|
||||||
{
|
|
||||||
/* Update scale factors used by ets_delay_us */
|
|
||||||
g_ticks_per_us_pro = ticks_per_us;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk)
|
|
||||||
{
|
{
|
||||||
|
rtc_slow_freq_t rtc_slow_freq = slow_clk & RTC_CNTL_ANA_CLK_RTC_SEL_V;
|
||||||
uint32_t cal_val = 0;
|
uint32_t cal_val = 0;
|
||||||
uint32_t wait = 0;
|
/* number of times to repeat 32k XTAL calibration
|
||||||
const uint32_t warning_timeout = 3 /* sec */ * 32768 /* Hz */ / (2 * SLOW_CLK_CAL_CYCLES);
|
* before giving up and switching to the internal RC
|
||||||
bool changing_clock_to_150k = false;
|
*/
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
|
int retry_32k_xtal = 1; /* don't change the behavior for the ESP32 */
|
||||||
|
#else
|
||||||
|
int retry_32k_xtal = 3;
|
||||||
|
#endif
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (slow_clk == RTC_SLOW_FREQ_32K_XTAL) {
|
if (rtc_slow_freq == 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
|
||||||
* be used. Hardware doesn't have a direct way of checking if the
|
* be used. Hardware doesn't have a direct way of checking if the
|
||||||
* oscillator is running. Here we use rtc_clk_cal function to count
|
* oscillator is running. Here we use rtc_clk_cal function to count
|
||||||
@@ -136,22 +160,26 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk)
|
|||||||
* will time out, returning 0.
|
* will time out, returning 0.
|
||||||
*/
|
*/
|
||||||
ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up");
|
ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up");
|
||||||
|
if (slow_clk == SLOW_CLK_32K_XTAL) {
|
||||||
rtc_clk_32k_enable(true);
|
rtc_clk_32k_enable(true);
|
||||||
|
} else if (slow_clk == SLOW_CLK_32K_EXT_OSC) {
|
||||||
|
rtc_clk_32k_enable_external();
|
||||||
|
}
|
||||||
|
// 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);
|
cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES);
|
||||||
if (cal_val == 0 || cal_val < 15000000L) {
|
if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) {
|
||||||
ESP_EARLY_LOGE(TAG, "RTC: Not found External 32 kHz XTAL. Switching to Internal 150 kHz RC chain");
|
if (retry_32k_xtal-- > 0) {
|
||||||
slow_clk = RTC_SLOW_FREQ_RTC;
|
continue;
|
||||||
changing_clock_to_150k = true;
|
}
|
||||||
|
ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 90 kHz oscillator");
|
||||||
|
rtc_slow_freq = RTC_SLOW_FREQ_RTC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rtc_clk_slow_freq_set(slow_clk);
|
} else if (rtc_slow_freq == RTC_SLOW_FREQ_8MD256) {
|
||||||
if (changing_clock_to_150k == true && wait > 1) {
|
rtc_clk_8m_enable(true, true);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
rtc_clk_slow_freq_set(rtc_slow_freq);
|
||||||
|
|
||||||
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.
|
||||||
@@ -162,9 +190,6 @@ 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);
|
||||||
|
@@ -325,6 +325,11 @@ void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq);
|
|||||||
*/
|
*/
|
||||||
void rtc_clk_32k_enable(bool en);
|
void rtc_clk_32k_enable(bool en);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure 32 kHz XTAL oscillator to accept external clock signal
|
||||||
|
*/
|
||||||
|
void rtc_clk_32k_enable_external(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the state of 32k XTAL oscillator
|
* @brief Get the state of 32k XTAL oscillator
|
||||||
* @return true if 32k XTAL oscillator has been enabled
|
* @return true if 32k XTAL oscillator has been enabled
|
||||||
|
@@ -57,6 +57,8 @@ void rtc_clk_32k_enable_internal(x32k_config_t cfg)
|
|||||||
void rtc_clk_32k_enable(bool enable)
|
void rtc_clk_32k_enable(bool enable)
|
||||||
{
|
{
|
||||||
if (enable) {
|
if (enable) {
|
||||||
|
SET_PERI_REG_MASK(RTC_IO_XTAL_32P_PAD_REG, RTC_IO_X32P_MUX_SEL);
|
||||||
|
SET_PERI_REG_MASK(RTC_IO_XTAL_32N_PAD_REG, RTC_IO_X32N_MUX_SEL);
|
||||||
x32k_config_t cfg = X32K_CONFIG_DEFAULT();
|
x32k_config_t cfg = X32K_CONFIG_DEFAULT();
|
||||||
rtc_clk_32k_enable_internal(cfg);
|
rtc_clk_32k_enable_internal(cfg);
|
||||||
} else {
|
} else {
|
||||||
@@ -65,8 +67,22 @@ void rtc_clk_32k_enable(bool enable)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rtc_clk_32k_enable_external(void)
|
||||||
|
{
|
||||||
|
SET_PERI_REG_MASK(RTC_IO_XTAL_32P_PAD_REG, RTC_IO_X32P_MUX_SEL);
|
||||||
|
SET_PERI_REG_MASK(RTC_IO_XTAL_32N_PAD_REG, RTC_IO_X32N_MUX_SEL);
|
||||||
|
/* TODO: external 32k source may need different settings */
|
||||||
|
x32k_config_t cfg = X32K_CONFIG_DEFAULT();
|
||||||
|
rtc_clk_32k_enable_internal(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
void rtc_clk_32k_bootstrap(uint32_t cycle)
|
void rtc_clk_32k_bootstrap(uint32_t cycle)
|
||||||
{
|
{
|
||||||
|
/* No special bootstrapping needed for ESP32-S2, 'cycle' argument is to keep the signature
|
||||||
|
* same as for the ESP32. Just enable the XTAL here.
|
||||||
|
*/
|
||||||
|
(void) cycle;
|
||||||
|
rtc_clk_32k_enable(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rtc_clk_32k_enabled(void)
|
bool rtc_clk_32k_enabled(void)
|
||||||
@@ -76,11 +92,8 @@ bool rtc_clk_32k_enabled(void)
|
|||||||
bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S;
|
bool xtal_xpd_sw = (xtal_conf & RTC_CNTL_XTAL32K_XPD_FORCE) >> RTC_CNTL_XTAL32K_XPD_FORCE_S;
|
||||||
/* If xtal xpd software control is on */
|
/* If xtal xpd software control is on */
|
||||||
bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S;
|
bool xtal_xpd_st = (xtal_conf & RTC_CNTL_XPD_XTAL_32K) >> RTC_CNTL_XPD_XTAL_32K_S;
|
||||||
if (xtal_xpd_sw & !xtal_xpd_st) {
|
bool disabled = xtal_xpd_sw && !xtal_xpd_st;
|
||||||
return false;
|
return !disabled;
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
|
void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
|
||||||
|
Reference in New Issue
Block a user