]> granicus.if.org Git - esp-idf/commitdiff
rtc_clk_init: handle case when XTAL frequency has already been set
authorIvan Grokhotkov <ivan@espressif.com>
Fri, 21 Apr 2017 02:33:58 +0000 (10:33 +0800)
committerIvan Grokhotkov <ivan@espressif.com>
Fri, 21 Apr 2017 02:33:58 +0000 (10:33 +0800)
On first reset, ROM code writes the estimated XTAL frequency into
RTC_APB_FREQ_REG (aka STORE5). If the application doesn’t specify exact
XTAL frequency (which is always the case for now), rtc_clk_init will
guess what kind of XTAL is used (26M or 40M), based on the estimated
frequency. Later, detected frequency is written into RTC_XTAL_FREQ_REG
(aka STORE4).

When the application switches clock source to PLL, APB frequency changes
and RTC_APB_FREQ_REG is updated. If the application encounters an RTC
WDT reset, RTC_APB_FREQ_REG will not be updated prior to reset. Once the
application starts up again, it will attempt to auto-detect XTAL
frequency based on RTC_APB_FREQ_REG, which now has value of 80000000.
This will fail, and rtc_clk_xtal_freq_estimate will fall back to the
default value of 26 MHz. Due to an incorrect XTAL frequency, PLL
initialization will also take incorrect path, and PLL will run at a
different frequency. Depending on the application this may cause just
garbage output on UART or a crash (if WiFi is used).

components/soc/esp32/rtc_clk.c

index 79b56f993651b4a773d212df2a5131f665bf6ab4..bc7eacc9d45906aafb87347d4bb8523513e0835e 100644 (file)
@@ -488,10 +488,16 @@ void rtc_clk_init(rtc_clk_config_t cfg)
     /* Estimate XTAL frequency if requested */
     rtc_xtal_freq_t xtal_freq = cfg.xtal_freq;
     if (xtal_freq == RTC_XTAL_FREQ_AUTO) {
-        xtal_freq = rtc_clk_xtal_freq_estimate();
-        if (xtal_freq == RTC_XTAL_FREQ_AUTO) {
-            SOC_LOGW(TAG, "Can't estimate XTAL frequency, assuming 26MHz");
-            xtal_freq = RTC_XTAL_FREQ_26M;
+        if (clk_val_is_valid(READ_PERI_REG(RTC_XTAL_FREQ_REG))) {
+            /* XTAL frequency has already been set, use existing value */
+            xtal_freq = rtc_clk_xtal_freq_get();
+        } else {
+            /* Not set yet, estimate XTAL frequency based on RTC_FAST_CLK */
+            xtal_freq = rtc_clk_xtal_freq_estimate();
+            if (xtal_freq == RTC_XTAL_FREQ_AUTO) {
+                SOC_LOGW(TAG, "Can't estimate XTAL frequency, assuming 26MHz");
+                xtal_freq = RTC_XTAL_FREQ_26M;
+            }
         }
     }
     rtc_clk_xtal_freq_update(xtal_freq);