Bläddra i källkod

Merge branch 'feature/rtc_slowclk_extra_options' into 'master'

Add more RTC_SLOW_CLK options

See merge request idf/esp-idf!2984
Ivan Grokhotkov 7 år sedan
förälder
incheckning
88d40e01b4

+ 22 - 1
components/esp32/Kconfig

@@ -687,18 +687,39 @@ choice ESP32_RTC_CLOCK_SOURCE
     default ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC
     help
         Choose which clock is used as RTC clock source.
+        
+        - "Internal 150kHz 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 8.5MHz oscillator divided by 256" option results in higher
+          deep sleep current (by 5uA) but has better frequency stability than
+          the internal 150kHz oscillator. It does not require external components.  
 
 config ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC
     bool "Internal 150kHz RC oscillator"
 config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
     bool "External 32kHz crystal"
+config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC
+    bool "External 32kHz oscillator at 32K_XP pin"
+config ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256
+    bool "Internal 8.5MHz oscillator, divided by 256 (~33kHz)"
 endchoice
 
 config ESP32_RTC_CLK_CAL_CYCLES
     int "Number of cycles for RTC_SLOW_CLK calibration"
     default 3000 if ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
     default 1024 if ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC
-    range 0 27000 if ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
+    range 0 27000 if ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL || ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC || ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256
     range 0 32766 if ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC
     help
         When the startup code initializes RTC_SLOW_CLK, it can perform

+ 36 - 25
components/esp32/clk.c

@@ -40,7 +40,23 @@
 
 #define MHZ (1000000)
 
-static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk);
+/* 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_150K = RTC_SLOW_FREQ_RTC,          //!< Internal 150 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 and APP CPU
 extern uint32_t g_ticks_per_us_pro;
@@ -71,8 +87,12 @@ void esp_clk_init(void)
 
     rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M);
 
-#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
-    select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL);
+#if defined(CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL)
+    select_rtc_slow_clk(SLOW_CLK_32K_XTAL);
+#elif defined(CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC)
+    select_rtc_slow_clk(SLOW_CLK_32K_EXT_OSC);
+#elif defined(CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256)
+    select_rtc_slow_clk(SLOW_CLK_8MD256);
 #else
     select_rtc_slow_clk(RTC_SLOW_FREQ_RTC);
 #endif
@@ -117,16 +137,12 @@ void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us)
     g_ticks_per_us_app = ticks_per_us;
 }
 
-static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk)
+static void select_rtc_slow_clk(slow_clk_sel_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 wait = 0;
-    uint32_t freq_hz = ((slow_clk == RTC_SLOW_FREQ_32K_XTAL) ? 32768 : 150000);
-    uint32_t warning_timeout = 3 /* sec */ * freq_hz /* Hz */ / (SLOW_CLK_CAL_CYCLES + 1);
-    warning_timeout = ((warning_timeout == 0) ? 3 /* sec */ : warning_timeout);
-    bool changing_clock_to_150k = false;
     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
              * 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
@@ -135,25 +151,23 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk)
              * will time out, returning 0.
              */
             ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up");
-            rtc_clk_32k_enable(true);
+            if (slow_clk == SLOW_CLK_32K_XTAL) {
+                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);
                 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;
+                    ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 150 kHz oscillator");
+                    rtc_slow_freq = RTC_SLOW_FREQ_RTC;
                 }
             }
+        } else if (rtc_slow_freq == RTC_SLOW_FREQ_8MD256) {
+            rtc_clk_8m_enable(true, 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);
-        }
+        rtc_clk_slow_freq_set(rtc_slow_freq);
 
         if (SLOW_CLK_CAL_CYCLES > 0) {
             /* TODO: 32k XTAL oscillator has some frequency drift at startup.
@@ -164,9 +178,6 @@ 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);

+ 5 - 0
components/soc/esp32/include/soc/rtc.h

@@ -193,6 +193,11 @@ void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq);
  */
 void rtc_clk_32k_enable(bool en);
 
+/**
+ * @brief Configure 32 kHz XTAL oscillator to accept external clock signal
+ */
+void rtc_clk_32k_enable_external();
+
 /**
  * @brief Get the state of 32k XTAL oscillator
  * @return true if 32k XTAL oscillator has been enabled

+ 12 - 3
components/soc/esp32/rtc_clk.c

@@ -62,6 +62,10 @@
 #define XTAL_32K_BOOTSTRAP_DBIAS_VAL    0
 #define XTAL_32K_BOOTSTRAP_TIME_US      7
 
+#define XTAL_32K_EXT_DAC_VAL    2
+#define XTAL_32K_EXT_DRES_VAL   3
+#define XTAL_32K_EXT_DBIAS_VAL  1
+
 /* Delays for various clock sources to be enabled/switched.
  * All values are in microseconds.
  * TODO: some of these are excessive, and should be reduced.
@@ -98,7 +102,7 @@ static bool rtc_clk_cpu_freq_from_mhz_internal(int mhz, rtc_cpu_freq_t* out_val)
 // Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled.
 static int s_cur_pll_freq;
 
-static void rtc_clk_32k_enable_internal(int dac, int dres, int dbias)
+static void rtc_clk_32k_enable_common(int dac, int dres, int dbias)
 {
     SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
     CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG,
@@ -113,12 +117,17 @@ static void rtc_clk_32k_enable_internal(int dac, int dres, int dbias)
 void rtc_clk_32k_enable(bool enable)
 {
     if (enable) {
-        rtc_clk_32k_enable_internal(XTAL_32K_DAC_VAL, XTAL_32K_DRES_VAL, XTAL_32K_DBIAS_VAL);
+        rtc_clk_32k_enable_common(XTAL_32K_DAC_VAL, XTAL_32K_DRES_VAL, XTAL_32K_DBIAS_VAL);
     } else {
         CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K);
     }
 }
 
+void rtc_clk_32k_enable_external()
+{
+    rtc_clk_32k_enable_common(XTAL_32K_EXT_DAC_VAL, XTAL_32K_EXT_DRES_VAL, XTAL_32K_EXT_DBIAS_VAL);
+}
+
 /* Helping external 32kHz crystal to start up.
  * External crystal connected to outputs GPIO32 GPIO33.
  * Forms N pulses with a frequency of about 32KHz on the outputs of the crystal.
@@ -150,7 +159,7 @@ void rtc_clk_32k_bootstrap(uint32_t cycle)
     SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RUE | RTC_IO_X32N_RDE);
     ets_delay_us(XTAL_32K_BOOTSTRAP_TIME_US);
 
-    rtc_clk_32k_enable_internal(XTAL_32K_BOOTSTRAP_DAC_VAL,
+    rtc_clk_32k_enable_common(XTAL_32K_BOOTSTRAP_DAC_VAL,
             XTAL_32K_BOOTSTRAP_DRES_VAL, XTAL_32K_BOOTSTRAP_DBIAS_VAL);
 }
 

+ 6 - 0
components/soc/esp32/rtc_sleep.c

@@ -197,6 +197,12 @@ void rtc_sleep_init(rtc_sleep_config_t cfg)
 
     REG_SET_FIELD(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_XTL_FORCE_PU, cfg.xtal_fpu);
 
+    if (REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL) == RTC_SLOW_FREQ_8MD256) {
+        REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU);
+    } else {
+        REG_CLR_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU);
+    }
+
     /* enable VDDSDIO control by state machine */
     REG_CLR_BIT(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_FORCE);
     REG_SET_FIELD(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_PD_EN, cfg.vddsdio_pd_en);