]> granicus.if.org Git - esp-idf/commitdiff
esp32: use new CPU frequency setting API
authorIvan Grokhotkov <ivan@espressif.com>
Sun, 29 Jul 2018 07:50:49 +0000 (10:50 +0300)
committerIvan Grokhotkov <ivan@espressif.com>
Tue, 21 Aug 2018 05:02:46 +0000 (13:02 +0800)
components/esp32/clk.c
components/esp32/include/esp32/pm.h
components/esp32/panic.c
components/esp32/pm_esp32.c
components/esp32/sleep_modes.c
components/esp32/system_api.c
components/soc/esp32/include/soc/rtc.h

index 9b00977744a542d34c517d1afa8882240b553fe3..bb348fd6721cd772c09bffc49474614fd603ca0a 100644 (file)
@@ -77,34 +77,22 @@ void esp_clk_init(void)
     select_rtc_slow_clk(RTC_SLOW_FREQ_RTC);
 #endif
 
-    uint32_t freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
-    rtc_cpu_freq_t freq = RTC_CPU_FREQ_80M;
-    switch(freq_mhz) {
-        case 240:
-            freq = RTC_CPU_FREQ_240M;
-            break;
-        case 160:
-            freq = RTC_CPU_FREQ_160M;
-            break;
-        default:
-            freq_mhz = 80;
-            /* falls through */
-        case 80:
-            freq = RTC_CPU_FREQ_80M;
-            break;
-    }
+    rtc_cpu_freq_config_t old_config, new_config;
+    rtc_clk_cpu_freq_get_config(&old_config);
+    const uint32_t old_freq_mhz = old_config.freq_mhz;
+    const uint32_t new_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
+
+    bool res = rtc_clk_cpu_freq_mhz_to_config(new_freq_mhz, &new_config);
+    assert(res);
 
     // Wait for UART TX to finish, otherwise some UART output will be lost
     // when switching APB frequency
     uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM);
     
-    uint32_t freq_before = rtc_clk_cpu_freq_value(rtc_clk_cpu_freq_get()) / MHZ ;
-    
-    rtc_clk_cpu_freq_set(freq);
+    rtc_clk_cpu_freq_set_config(&new_config);
 
     // Re calculate the ccount to make time calculation correct. 
-    uint32_t freq_after = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
-    XTHAL_SET_CCOUNT( XTHAL_GET_CCOUNT() * freq_after / freq_before );
+    XTHAL_SET_CCOUNT( XTHAL_GET_CCOUNT() * new_freq_mhz / old_freq_mhz );
 }
 
 int IRAM_ATTR esp_clk_cpu_freq(void)
index a7cbf0eac719cf21fba403987e9b65d5c60fcf54..f64045fb31b29e2f9723514bcfed1636b71c7ce5 100644 (file)
@@ -31,8 +31,10 @@ extern "C" {
  * Pass a pointer to this structure as an argument to esp_pm_configure function.
  */
 typedef struct {
-    rtc_cpu_freq_t max_cpu_freq;    /*!< Maximum CPU frequency to use */
-    rtc_cpu_freq_t min_cpu_freq;    /*!< Minimum CPU frequency to use when no frequency locks are taken */
+    rtc_cpu_freq_t max_cpu_freq __attribute__((deprecated));    /*!< Maximum CPU frequency to use. Deprecated, use max_freq_mhz instead. */
+    int max_freq_mhz;   /*!< Maximum CPU frequency, in MHz */
+    rtc_cpu_freq_t min_cpu_freq __attribute__((deprecated));    /*!< Minimum CPU frequency to use when no frequency locks are taken.  Deprecated, use min_freq_mhz instead. */
+    int min_freq_mhz;   /*!< Minimum CPU frequency to use when no locks are taken, in MHz */
     bool light_sleep_enable;        /*!< Enter light sleep when no locks are taken */
 } esp_pm_config_esp32_t;
 
index 5a000574be081b3044b44eba7fcb06928fd87ec1..bbb359c9f32d49be2b937f94f4acde3c7b6e5329 100644 (file)
@@ -382,7 +382,7 @@ static void esp_panic_dig_reset()
     // make sure all the panic handler output is sent from UART FIFO
     uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM);
     // switch to XTAL (otherwise we will keep running from the PLL)
-    rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL);
+    rtc_clk_cpu_freq_set_xtal();
     // reset the digital part
     esp_cpu_unstall(PRO_CPU_NUM);
     SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST);
index f75b3fe8115aed4c189695ca8d9c7a08b922df11..5d77dd8db669ec5f369d17f453c133f9de866c60 100644 (file)
  */
 #define LIGHT_SLEEP_EARLY_WAKEUP_US 100
 
+/* Minimal divider at which REF_CLK_FREQ can be obtained */
+#define REF_CLK_DIV_MIN 10
+
+#define MHZ 1000000
+
 #ifdef CONFIG_PM_PROFILING
 #define WITH_PROFILING
 #endif
@@ -80,44 +85,20 @@ static uint32_t s_ccount_mul;
  */
 static volatile bool s_need_update_ccompare[portNUM_PROCESSORS];
 
-/* When no RTOS tasks are active, these locks are released to allow going into
- * a lower power mode. Used by ISR hook and idle hook.
- */
-static esp_pm_lock_handle_t s_rtos_lock_handle[portNUM_PROCESSORS];
-
 /* A flag indicating that Idle hook has run on a given CPU;
  * Next interrupt on the same CPU will take s_rtos_lock_handle.
  */
 static bool s_core_idle[portNUM_PROCESSORS];
 
-/* g_ticks_us defined in ROM for PRO CPU */
-extern uint32_t g_ticks_per_us_pro;
-
-/* Lookup table of CPU frequencies to be used in each mode.
- * Initialized by esp_pm_impl_init and modified by esp_pm_configure.
+/* When no RTOS tasks are active, these locks are released to allow going into
+ * a lower power mode. Used by ISR hook and idle hook.
  */
-rtc_cpu_freq_t s_cpu_freq_by_mode[PM_MODE_COUNT];
+static esp_pm_lock_handle_t s_rtos_lock_handle[portNUM_PROCESSORS];
 
-/* Lookup table of CPU ticks per microsecond for each RTC_CPU_FREQ_ value.
- * Essentially the same as returned by rtc_clk_cpu_freq_value(), but without
- * the function call. Not const because XTAL frequency is only known at run time.
+/* Lookup table of CPU frequency configs to be used in each mode.
+ * Initialized by esp_pm_impl_init and modified by esp_pm_configure.
  */
-static uint32_t s_cpu_freq_to_ticks[] = {
-       [RTC_CPU_FREQ_XTAL] = 0, /* This is set by esp_pm_impl_init */
-       [RTC_CPU_FREQ_80M]  = 80,
-       [RTC_CPU_FREQ_160M] = 160,
-       [RTC_CPU_FREQ_240M] = 240,
-       [RTC_CPU_FREQ_2M]   = 2
-};
-
-/* Lookup table of names for each RTC_CPU_FREQ_ value. Used for logging only. */
-static const char* s_freq_names[] __attribute__((unused)) = {
-        [RTC_CPU_FREQ_XTAL] = "XTAL",
-        [RTC_CPU_FREQ_80M] = "80",
-        [RTC_CPU_FREQ_160M] = "160",
-        [RTC_CPU_FREQ_240M] = "240",
-        [RTC_CPU_FREQ_2M] = "2"
-};
+rtc_cpu_freq_config_t s_cpu_freq_by_mode[PM_MODE_COUNT];
 
 /* Whether automatic light sleep is enabled */
 static bool s_light_sleep_en = false;
@@ -167,21 +148,6 @@ pm_mode_t esp_pm_impl_get_mode(esp_pm_lock_type_t type, int arg)
     }
 }
 
-/* rtc_cpu_freq_t enum is not ordered by frequency, so convert to MHz,
- * figure out the maximum value, then convert back to rtc_cpu_freq_t.
- */
-static rtc_cpu_freq_t max_freq_of(rtc_cpu_freq_t f1, rtc_cpu_freq_t f2)
-{
-    int f1_hz = rtc_clk_cpu_freq_value(f1);
-    int f2_hz = rtc_clk_cpu_freq_value(f2);
-    int f_max_hz = MAX(f1_hz, f2_hz);
-    rtc_cpu_freq_t result = RTC_CPU_FREQ_XTAL;
-    if (!rtc_clk_cpu_freq_from_mhz(f_max_hz/1000000, &result)) {
-        assert(false && "unsupported frequency");
-    }
-    return result;
-}
-
 esp_err_t esp_pm_configure(const void* vconfig)
 {
 #ifndef CONFIG_PM_ENABLE
@@ -195,46 +161,66 @@ esp_err_t esp_pm_configure(const void* vconfig)
     }
 #endif
 
-    if (config->min_cpu_freq == RTC_CPU_FREQ_2M) {
-        /* Minimal APB frequency to achieve 1MHz REF_TICK frequency is 5 MHz */
-        return ESP_ERR_NOT_SUPPORTED;
+    int min_freq_mhz = config->min_freq_mhz;
+    int max_freq_mhz = config->max_freq_mhz;
+
+    if (min_freq_mhz == 0 && max_freq_mhz == 0) {
+        /* For compatibility, handle deprecated fields, min_cpu_freq and max_cpu_freq. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+        min_freq_mhz = rtc_clk_cpu_freq_value(config->min_cpu_freq) / MHZ;
+        max_freq_mhz = rtc_clk_cpu_freq_value(config->max_cpu_freq) / MHZ;
+#pragma GCC diagnostic pop
     }
 
-    rtc_cpu_freq_t min_freq = config->min_cpu_freq;
-    rtc_cpu_freq_t max_freq = config->max_cpu_freq;
-    int min_freq_mhz = rtc_clk_cpu_freq_value(min_freq);
-    int max_freq_mhz = rtc_clk_cpu_freq_value(max_freq);
     if (min_freq_mhz > max_freq_mhz) {
         return ESP_ERR_INVALID_ARG;
     }
 
-    rtc_cpu_freq_t apb_max_freq = max_freq; /* CPU frequency in APB_MAX mode */
-    if (max_freq == RTC_CPU_FREQ_240M) {
+    rtc_cpu_freq_config_t freq_config;
+    if (!rtc_clk_cpu_freq_mhz_to_config(min_freq_mhz, &freq_config)) {
+        ESP_LOGW(TAG, "invalid min_freq_mhz value (%d)", min_freq_mhz);
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    int xtal_freq_mhz = (int) rtc_clk_xtal_freq_get();
+    if (min_freq_mhz < xtal_freq_mhz && min_freq_mhz * MHZ / REF_CLK_FREQ < REF_CLK_DIV_MIN) {
+        ESP_LOGW(TAG, "min_freq_mhz should be >= %d", REF_CLK_FREQ * REF_CLK_DIV_MIN / MHZ);
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    if (!rtc_clk_cpu_freq_mhz_to_config(max_freq_mhz, &freq_config)) {
+        ESP_LOGW(TAG, "invalid max_freq_mhz value (%d)", max_freq_mhz);
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    int apb_max_freq = max_freq_mhz; /* CPU frequency in APB_MAX mode */
+    if (max_freq_mhz == 240) {
         /* We can't switch between 240 and 80/160 without disabling PLL,
          * so use 240MHz CPU frequency when 80MHz APB frequency is requested.
          */
-        apb_max_freq = RTC_CPU_FREQ_240M;
-    } else if (max_freq == RTC_CPU_FREQ_160M || max_freq == RTC_CPU_FREQ_80M) {
+        apb_max_freq = 240;
+    } else if (max_freq_mhz == 160 || max_freq_mhz == 80) {
         /* Otherwise, can use 80MHz
          * CPU frequency when 80MHz APB frequency is requested.
          */
-        apb_max_freq = RTC_CPU_FREQ_80M;
+        apb_max_freq = 80;
     }
 
-    apb_max_freq = max_freq_of(apb_max_freq, min_freq);
+    apb_max_freq = MAX(apb_max_freq, min_freq_mhz);
 
     ESP_LOGI(TAG, "Frequency switching config: "
-                  "CPU_MAX: %s, APB_MAX: %s, APB_MIN: %s, Light sleep: %s",
-                  s_freq_names[max_freq],
-                  s_freq_names[apb_max_freq],
-                  s_freq_names[min_freq],
+                  "CPU_MAX: %d, APB_MAX: %d, APB_MIN: %d, Light sleep: %s",
+                  max_freq_mhz,
+                  apb_max_freq,
+                  min_freq_mhz,
                   config->light_sleep_enable ? "ENABLED" : "DISABLED");
 
     portENTER_CRITICAL(&s_switch_lock);
-    s_cpu_freq_by_mode[PM_MODE_CPU_MAX] = max_freq;
-    s_cpu_freq_by_mode[PM_MODE_APB_MAX] = apb_max_freq;
-    s_cpu_freq_by_mode[PM_MODE_APB_MIN] = min_freq;
-    s_cpu_freq_by_mode[PM_MODE_LIGHT_SLEEP] = min_freq;
+    rtc_clk_cpu_freq_mhz_to_config(max_freq_mhz, &s_cpu_freq_by_mode[PM_MODE_CPU_MAX]);
+    rtc_clk_cpu_freq_mhz_to_config(apb_max_freq, &s_cpu_freq_by_mode[PM_MODE_APB_MAX]);
+    rtc_clk_cpu_freq_mhz_to_config(min_freq_mhz, &s_cpu_freq_by_mode[PM_MODE_APB_MIN]);
+    s_cpu_freq_by_mode[PM_MODE_LIGHT_SLEEP] = s_cpu_freq_by_mode[PM_MODE_APB_MIN];
     s_light_sleep_en = config->light_sleep_enable;
     s_config_changed = true;
     portEXIT_CRITICAL(&s_switch_lock);
@@ -310,7 +296,7 @@ static void IRAM_ATTR on_freq_update(uint32_t old_ticks_per_us, uint32_t ticks_p
     }
 
     /* Calculate new tick divisor */
-    _xt_tick_divisor = ticks_per_us * 1000000 / XT_TICK_PER_SEC;
+    _xt_tick_divisor = ticks_per_us * MHZ / XT_TICK_PER_SEC;
 
     int core_id = xPortGetCoreID();
     if (s_rtos_lock_handle[core_id] != NULL) {
@@ -375,17 +361,18 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode)
     s_config_changed = false;
     portEXIT_CRITICAL_ISR(&s_switch_lock);
 
-    rtc_cpu_freq_t new_freq = s_cpu_freq_by_mode[new_mode];
-    rtc_cpu_freq_t old_freq;
+    rtc_cpu_freq_config_t new_config = s_cpu_freq_by_mode[new_mode];
+    rtc_cpu_freq_config_t old_config;
+
     if (!config_changed) {
-        old_freq = s_cpu_freq_by_mode[s_mode];
+        old_config = s_cpu_freq_by_mode[s_mode];
     } else {
-        old_freq = rtc_clk_cpu_freq_get();
+        rtc_clk_cpu_freq_get_config(&old_config);
     }
 
-    if (new_freq != old_freq) {
-        uint32_t old_ticks_per_us = g_ticks_per_us_pro;
-        uint32_t new_ticks_per_us = s_cpu_freq_to_ticks[new_freq];
+    if (new_config.freq_mhz != old_config.freq_mhz) {
+        uint32_t old_ticks_per_us = old_config.freq_mhz;
+        uint32_t new_ticks_per_us = new_config.freq_mhz;
 
         bool switch_down = new_ticks_per_us < old_ticks_per_us;
 
@@ -393,7 +380,7 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode)
         if (switch_down) {
             on_freq_update(old_ticks_per_us, new_ticks_per_us);
         }
-        rtc_clk_cpu_freq_set_fast(new_freq);
+        rtc_clk_cpu_freq_set_config_fast(&new_config);
         if (!switch_down) {
             on_freq_update(old_ticks_per_us, new_ticks_per_us);
         }
@@ -536,9 +523,9 @@ void esp_pm_impl_dump_stats(FILE* out)
             /* don't display light sleep mode if it's not enabled */
             continue;
         }
-        fprintf(out, "%8s %6s %12lld  %2d%%\n",
+        fprintf(out, "%8s  %3dM %12lld  %2d%%\n",
                 s_mode_names[i],
-                s_freq_names[s_cpu_freq_by_mode[i]],
+                s_cpu_freq_by_mode[i].freq_mhz,
                 time_in_mode[i],
                 (int) (time_in_mode[i] * 100 / now));
     }
@@ -547,7 +534,6 @@ void esp_pm_impl_dump_stats(FILE* out)
 
 void esp_pm_impl_init()
 {
-    s_cpu_freq_to_ticks[RTC_CPU_FREQ_XTAL] = rtc_clk_xtal_freq_get();
 #ifdef CONFIG_PM_TRACE
     esp_pm_trace_init();
 #endif
@@ -563,11 +549,11 @@ void esp_pm_impl_init()
     /* Configure all modes to use the default CPU frequency.
      * This will be modified later by a call to esp_pm_configure.
      */
-    rtc_cpu_freq_t default_freq;
-    if (!rtc_clk_cpu_freq_from_mhz(CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ, &default_freq)) {
+    rtc_cpu_freq_config_t default_config;
+    if (!rtc_clk_cpu_freq_mhz_to_config(CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ, &default_config)) {
         assert(false && "unsupported frequency");
     }
     for (size_t i = 0; i < PM_MODE_COUNT; ++i) {
-        s_cpu_freq_by_mode[i] = default_freq;
+        s_cpu_freq_by_mode[i] = default_config;
     }
 }
index 91713ad6bb1640e7da4b1e4756a49c454d28736f..2fda37a5ddb3ba32680e604a1ea260309cca45e8 100644 (file)
@@ -178,8 +178,9 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
     }
 
     // Save current frequency and switch to XTAL
-    rtc_cpu_freq_t cpu_freq = rtc_clk_cpu_freq_get();
-    rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL);
+    rtc_cpu_freq_config_t cpu_freq_config;
+    rtc_clk_cpu_freq_get_config(&cpu_freq_config);
+    rtc_clk_cpu_freq_set_xtal();
 
     // Configure pins for external wakeup
     if (s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) {
@@ -205,7 +206,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
     uint32_t result = rtc_sleep_start(s_config.wakeup_triggers, 0);
 
     // Restore CPU frequency
-    rtc_clk_cpu_freq_set(cpu_freq);
+    rtc_clk_cpu_freq_set_config(&cpu_freq_config);
 
     // re-enable UART output
     resume_uarts();
index f56bf622e2c0b5eae2c9852336f7044a5b0c66a0..1208de48320dce62292c5fb352c586907da6198e 100644 (file)
@@ -333,7 +333,7 @@ void IRAM_ATTR esp_restart_noos()
     DPORT_REG_WRITE(DPORT_PERIP_RST_EN_REG, 0);
 
     // Set CPU back to XTAL source, no PLL, same as hard reset
-    rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL);
+    rtc_clk_cpu_freq_set_xtal();
 
     // Clear entry point for APP CPU
     DPORT_REG_WRITE(DPORT_APPCPU_CTRL_D_REG, 0);
index e7e1c1d14b3ba605b1ab817b9649005327e0dc80..b02d31eac3ed65bb9fa9f451b4dbf94e3d213d7f 100644 (file)
@@ -417,6 +417,10 @@ uint32_t rtc_clk_cpu_freq_value(rtc_cpu_freq_t cpu_freq)  __attribute__((depreca
   * so it is less safe to use it e.g. from a panic handler (when memory might
   * be corrupted).
   *
+  * @note This function in not intended to be called by applications in FreeRTOS
+  * environment. This is because it does not adjust various timers based on the
+  * new CPU frequency.
+  *
   * @param config  CPU frequency configuration structure
   */
  void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t* config);