From: Ivan Grokhotkov Date: Thu, 26 Oct 2017 10:46:27 +0000 (+0800) Subject: soc/rtc: wait for SLOW_CLK cycle when switching CPU clock X-Git-Tag: v3.1-dev~102^2~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6d4ed4ff6c4ca6e3b3bd4af3c7aeabe33570b540;p=esp-idf soc/rtc: wait for SLOW_CLK cycle when switching CPU clock Previous implementation waited for 20us after setting RTC_CNTL_SOC_CLK_SEL_XTL register, using ets_delay_us, assuming that the CPU was running at XTAL frequency. In reality, clock switch happened on the next RTC_SLOW_CLK cycle, and CPU could be running at the previous frequency (for example, 240 MHz) until then. ets_delay_us would wait for 20 us * 40 cycles per us = 800 CPU cycles (assuming 40 MHz XTAL; even less with a 26 MHz XTAL). But if CPU was running at 240 MHz, 800 cycles would pass in just 3.3us, while SLOW_CLK cycle could happen as much as 1/150kHz = 6.7us after RTC_CNTL_SOC_CLK_SEL_XTL was set. So the software would not actually wait long enough for the clock switch to happen, and would disable the PLL while CPU was still clocked from PLL, leading to a halt. This implementation uses rtc_clk_wait_for_slow_cycle() function to wait until the clock switch, removing the need to wait for a fixed number of CPU cycles. --- diff --git a/components/soc/esp32/rtc_clk.c b/components/soc/esp32/rtc_clk.c index 6e2b0909d0..049b47306a 100644 --- a/components/soc/esp32/rtc_clk.c +++ b/components/soc/esp32/rtc_clk.c @@ -72,9 +72,6 @@ static const char* TAG = "rtc_clk"; * All values are in microseconds. * TODO: some of these are excessive, and should be reduced. */ -#define DELAY_CPU_FREQ_SWITCH_TO_XTAL_WITH_150K 20 -#define DELAY_CPU_FREQ_SWITCH_TO_XTAL_WITH_32K 160 -#define DELAY_CPU_FREQ_SWITCH_TO_PLL 20 #define DELAY_PLL_DBIAS_RAISE 3 #define DELAY_PLL_ENABLE_WITH_150K 80 #define DELAY_PLL_ENABLE_WITH_32K 160 @@ -397,9 +394,12 @@ void rtc_clk_cpu_freq_set(rtc_cpu_freq_t cpu_freq) REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, RTC_CNTL_SOC_CLK_SEL_XTL); REG_SET_FIELD(APB_CTRL_SYSCLK_CONF_REG, APB_CTRL_PRE_DIV_CNT, 0); ets_update_cpu_frequency(xtal_freq); - uint32_t delay_xtal_switch = (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_RTC) ? - DELAY_CPU_FREQ_SWITCH_TO_XTAL_WITH_150K : DELAY_CPU_FREQ_SWITCH_TO_XTAL_WITH_32K; - ets_delay_us(delay_xtal_switch); + + /* Frequency switch is synchronized to SLOW_CLK cycle. Wait until the switch + * is complete before disabling the PLL. + */ + rtc_clk_wait_for_slow_cycle(); + DPORT_REG_SET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL, 0); SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BB_I2C_FORCE_PD | RTC_CNTL_BBPLL_FORCE_PD | @@ -443,7 +443,7 @@ void rtc_clk_cpu_freq_set(rtc_cpu_freq_t cpu_freq) s_pll_freq = 480; } REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, RTC_CNTL_SOC_CLK_SEL_PLL); - ets_delay_us(DELAY_CPU_FREQ_SWITCH_TO_PLL); + rtc_clk_wait_for_slow_cycle(); rtc_clk_apb_freq_update(80 * MHZ); } s_cur_freq = cpu_freq;