esp32s2: sync esp_pm code from esp32
This commit is contained in:
parent
d37a419dfc
commit
d2d3269159
|
@ -317,11 +317,10 @@ void start_cpu0_default(void)
|
||||||
#ifdef CONFIG_PM_ENABLE
|
#ifdef CONFIG_PM_ENABLE
|
||||||
esp_pm_impl_init();
|
esp_pm_impl_init();
|
||||||
#ifdef CONFIG_PM_DFS_INIT_AUTO
|
#ifdef CONFIG_PM_DFS_INIT_AUTO
|
||||||
rtc_cpu_freq_t max_freq;
|
int xtal_freq = (int) rtc_clk_xtal_freq_get();
|
||||||
rtc_clk_cpu_freq_from_mhz(CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ, &max_freq);
|
esp_pm_config_esp32s2_t cfg = {
|
||||||
esp_pm_config_esp32_t cfg = {
|
.max_freq_mhz = CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ,
|
||||||
.max_cpu_freq = max_freq,
|
.min_freq_mhz = xtal_freq,
|
||||||
.min_cpu_freq = RTC_CPU_FREQ_XTAL
|
|
||||||
};
|
};
|
||||||
esp_pm_configure(&cfg);
|
esp_pm_configure(&cfg);
|
||||||
#endif //CONFIG_PM_DFS_INIT_AUTO
|
#endif //CONFIG_PM_DFS_INIT_AUTO
|
||||||
|
|
|
@ -31,10 +31,10 @@ extern "C" {
|
||||||
* Pass a pointer to this structure as an argument to esp_pm_configure function.
|
* Pass a pointer to this structure as an argument to esp_pm_configure function.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
rtc_cpu_freq_t max_cpu_freq; /*!< Maximum CPU frequency to use */
|
int max_freq_mhz; /*!< Maximum CPU frequency, in MHz */
|
||||||
rtc_cpu_freq_t min_cpu_freq; /*!< Minimum CPU frequency to use when no frequency locks are taken */
|
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 */
|
bool light_sleep_enable; /*!< Enter light sleep when no locks are taken */
|
||||||
} esp_pm_config_esp32_t;
|
} esp_pm_config_esp32s2_t;
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2016-2017 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2016-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -35,6 +35,7 @@
|
||||||
#include "esp_private/pm_trace.h"
|
#include "esp_private/pm_trace.h"
|
||||||
#include "esp_private/esp_timer_private.h"
|
#include "esp_private/esp_timer_private.h"
|
||||||
#include "esp32s2/pm.h"
|
#include "esp32s2/pm.h"
|
||||||
|
#include "esp_sleep.h"
|
||||||
|
|
||||||
/* CCOMPARE update timeout, in CPU cycles. Any value above ~600 cycles will work
|
/* CCOMPARE update timeout, in CPU cycles. Any value above ~600 cycles will work
|
||||||
* for the purpose of detecting a deadlock.
|
* for the purpose of detecting a deadlock.
|
||||||
|
@ -51,6 +52,9 @@
|
||||||
*/
|
*/
|
||||||
#define LIGHT_SLEEP_EARLY_WAKEUP_US 100
|
#define LIGHT_SLEEP_EARLY_WAKEUP_US 100
|
||||||
|
|
||||||
|
/* Minimal divider at which REF_CLK_FREQ can be obtained */
|
||||||
|
#define REF_CLK_DIV_MIN 2
|
||||||
|
|
||||||
#ifdef CONFIG_PM_PROFILING
|
#ifdef CONFIG_PM_PROFILING
|
||||||
#define WITH_PROFILING
|
#define WITH_PROFILING
|
||||||
#endif
|
#endif
|
||||||
|
@ -75,49 +79,42 @@ static uint32_t s_mode_mask;
|
||||||
static uint32_t s_ccount_div;
|
static uint32_t s_ccount_div;
|
||||||
static uint32_t s_ccount_mul;
|
static uint32_t s_ccount_mul;
|
||||||
|
|
||||||
|
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||||
|
/* Indicates if light sleep entry was skipped in vApplicationSleep for given CPU.
|
||||||
|
* This in turn gets used in IDLE hook to decide if `waiti` needs
|
||||||
|
* to be invoked or not.
|
||||||
|
*/
|
||||||
|
static bool s_skipped_light_sleep[portNUM_PROCESSORS];
|
||||||
|
|
||||||
|
#if portNUM_PROCESSORS == 2
|
||||||
|
/* When light sleep is finished on one CPU, it is possible that the other CPU
|
||||||
|
* will enter light sleep again very soon, before interrupts on the first CPU
|
||||||
|
* get a chance to run. To avoid such situation, set a flag for the other CPU to
|
||||||
|
* skip light sleep attempt.
|
||||||
|
*/
|
||||||
|
static bool s_skip_light_sleep[portNUM_PROCESSORS];
|
||||||
|
#endif // portNUM_PROCESSORS == 2
|
||||||
|
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||||
|
|
||||||
/* Indicates to the ISR hook that CCOMPARE needs to be updated on the given CPU.
|
/* Indicates to the ISR hook that CCOMPARE needs to be updated on the given CPU.
|
||||||
* Used in conjunction with cross-core interrupt to update CCOMPARE on the other CPU.
|
* Used in conjunction with cross-core interrupt to update CCOMPARE on the other CPU.
|
||||||
*/
|
*/
|
||||||
static volatile bool s_need_update_ccompare[portNUM_PROCESSORS];
|
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;
|
/* A flag indicating that Idle hook has run on a given CPU;
|
||||||
* Next interrupt on the same CPU will take s_rtos_lock_handle.
|
* Next interrupt on the same CPU will take s_rtos_lock_handle.
|
||||||
*/
|
*/
|
||||||
static bool s_core_idle[portNUM_PROCESSORS];
|
static bool s_core_idle[portNUM_PROCESSORS];
|
||||||
|
|
||||||
/* g_ticks_us defined in ROM for PRO CPU */
|
/* When no RTOS tasks are active, these locks are released to allow going into
|
||||||
extern uint32_t g_ticks_per_us_pro;
|
* a lower power mode. Used by ISR hook and idle hook.
|
||||||
|
*/
|
||||||
|
static esp_pm_lock_handle_t s_rtos_lock_handle[portNUM_PROCESSORS];
|
||||||
|
|
||||||
/* Lookup table of CPU frequencies to be used in each mode.
|
/* Lookup table of CPU frequency configs to be used in each mode.
|
||||||
* Initialized by esp_pm_impl_init and modified by esp_pm_configure.
|
* Initialized by esp_pm_impl_init and modified by esp_pm_configure.
|
||||||
*/
|
*/
|
||||||
rtc_cpu_freq_t s_cpu_freq_by_mode[PM_MODE_COUNT];
|
rtc_cpu_freq_config_t s_cpu_freq_by_mode[PM_MODE_COUNT];
|
||||||
|
|
||||||
/* 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.
|
|
||||||
*/
|
|
||||||
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"
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Whether automatic light sleep is enabled */
|
/* Whether automatic light sleep is enabled */
|
||||||
static bool s_light_sleep_en = false;
|
static bool s_light_sleep_en = false;
|
||||||
|
@ -144,7 +141,7 @@ static const char* s_mode_names[] = {
|
||||||
#endif // WITH_PROFILING
|
#endif // WITH_PROFILING
|
||||||
|
|
||||||
|
|
||||||
static const char* TAG = "pm_esp32";
|
static const char* TAG = "pm_esp32s2";
|
||||||
|
|
||||||
static void update_ccompare(void);
|
static void update_ccompare(void);
|
||||||
static void do_switch(pm_mode_t new_mode);
|
static void do_switch(pm_mode_t new_mode);
|
||||||
|
@ -167,74 +164,62 @@ 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)
|
esp_err_t esp_pm_configure(const void* vconfig)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_PM_ENABLE
|
#ifndef CONFIG_PM_ENABLE
|
||||||
return ESP_ERR_NOT_SUPPORTED;
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const esp_pm_config_esp32_t* config = (const esp_pm_config_esp32_t*) vconfig;
|
const esp_pm_config_esp32s2_t* config = (const esp_pm_config_esp32s2_t*) vconfig;
|
||||||
#ifndef CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
#ifndef CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||||
if (config->light_sleep_enable) {
|
if (config->light_sleep_enable) {
|
||||||
return ESP_ERR_NOT_SUPPORTED;
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (config->min_cpu_freq == RTC_CPU_FREQ_2M) {
|
int min_freq_mhz = config->min_freq_mhz;
|
||||||
/* Minimal APB frequency to achieve 1MHz REF_TICK frequency is 5 MHz */
|
int max_freq_mhz = config->max_freq_mhz;
|
||||||
return ESP_ERR_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
if (min_freq_mhz > max_freq_mhz) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_cpu_freq_t apb_max_freq = max_freq; /* CPU frequency in APB_MAX mode */
|
rtc_cpu_freq_config_t freq_config;
|
||||||
if (max_freq == RTC_CPU_FREQ_240M) {
|
if (!rtc_clk_cpu_freq_mhz_to_config(min_freq_mhz, &freq_config)) {
|
||||||
/* We can't switch between 240 and 80/160 without disabling PLL,
|
ESP_LOGW(TAG, "invalid min_freq_mhz value (%d)", min_freq_mhz);
|
||||||
* so use 240MHz CPU frequency when 80MHz APB frequency is requested.
|
return ESP_ERR_INVALID_ARG;
|
||||||
*/
|
|
||||||
apb_max_freq = RTC_CPU_FREQ_240M;
|
|
||||||
} else if (max_freq == RTC_CPU_FREQ_160M || max_freq == RTC_CPU_FREQ_80M) {
|
|
||||||
/* Otherwise, can use 80MHz
|
|
||||||
* CPU frequency when 80MHz APB frequency is requested.
|
|
||||||
*/
|
|
||||||
apb_max_freq = RTC_CPU_FREQ_80M;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apb_max_freq = max_freq_of(apb_max_freq, min_freq);
|
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 = MIN(max_freq_mhz, 80); /* CPU frequency in APB_MAX mode */
|
||||||
|
apb_max_freq = MAX(apb_max_freq, min_freq_mhz);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Frequency switching config: "
|
ESP_LOGI(TAG, "Frequency switching config: "
|
||||||
"CPU_MAX: %s, APB_MAX: %s, APB_MIN: %s, Light sleep: %s",
|
"CPU_MAX: %d, APB_MAX: %d, APB_MIN: %d, Light sleep: %s",
|
||||||
s_freq_names[max_freq],
|
max_freq_mhz,
|
||||||
s_freq_names[apb_max_freq],
|
apb_max_freq,
|
||||||
s_freq_names[min_freq],
|
min_freq_mhz,
|
||||||
config->light_sleep_enable ? "ENABLED" : "DISABLED");
|
config->light_sleep_enable ? "ENABLED" : "DISABLED");
|
||||||
|
|
||||||
portENTER_CRITICAL(&s_switch_lock);
|
portENTER_CRITICAL(&s_switch_lock);
|
||||||
s_cpu_freq_by_mode[PM_MODE_CPU_MAX] = max_freq;
|
bool res;
|
||||||
s_cpu_freq_by_mode[PM_MODE_APB_MAX] = apb_max_freq;
|
res = rtc_clk_cpu_freq_mhz_to_config(max_freq_mhz, &s_cpu_freq_by_mode[PM_MODE_CPU_MAX]);
|
||||||
s_cpu_freq_by_mode[PM_MODE_APB_MIN] = min_freq;
|
assert(res);
|
||||||
s_cpu_freq_by_mode[PM_MODE_LIGHT_SLEEP] = min_freq;
|
res = rtc_clk_cpu_freq_mhz_to_config(apb_max_freq, &s_cpu_freq_by_mode[PM_MODE_APB_MAX]);
|
||||||
|
assert(res);
|
||||||
|
res = rtc_clk_cpu_freq_mhz_to_config(min_freq_mhz, &s_cpu_freq_by_mode[PM_MODE_APB_MIN]);
|
||||||
|
assert(res);
|
||||||
|
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_light_sleep_en = config->light_sleep_enable;
|
||||||
s_config_changed = true;
|
s_config_changed = true;
|
||||||
portEXIT_CRITICAL(&s_switch_lock);
|
portEXIT_CRITICAL(&s_switch_lock);
|
||||||
|
@ -261,7 +246,7 @@ void IRAM_ATTR esp_pm_impl_switch_mode(pm_mode_t mode,
|
||||||
{
|
{
|
||||||
bool need_switch = false;
|
bool need_switch = false;
|
||||||
uint32_t mode_mask = BIT(mode);
|
uint32_t mode_mask = BIT(mode);
|
||||||
portENTER_CRITICAL(&s_switch_lock);
|
portENTER_CRITICAL_SAFE(&s_switch_lock);
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
if (lock_or_unlock == MODE_LOCK) {
|
if (lock_or_unlock == MODE_LOCK) {
|
||||||
count = ++s_mode_lock_counts[mode];
|
count = ++s_mode_lock_counts[mode];
|
||||||
|
@ -288,7 +273,7 @@ void IRAM_ATTR esp_pm_impl_switch_mode(pm_mode_t mode,
|
||||||
s_last_mode_change_time = now;
|
s_last_mode_change_time = now;
|
||||||
#endif // WITH_PROFILING
|
#endif // WITH_PROFILING
|
||||||
}
|
}
|
||||||
portEXIT_CRITICAL(&s_switch_lock);
|
portEXIT_CRITICAL_SAFE(&s_switch_lock);
|
||||||
if (need_switch && new_mode != s_mode) {
|
if (need_switch && new_mode != s_mode) {
|
||||||
do_switch(new_mode);
|
do_switch(new_mode);
|
||||||
}
|
}
|
||||||
|
@ -310,7 +295,7 @@ static void IRAM_ATTR on_freq_update(uint32_t old_ticks_per_us, uint32_t ticks_p
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate new tick divisor */
|
/* 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();
|
int core_id = xPortGetCoreID();
|
||||||
if (s_rtos_lock_handle[core_id] != NULL) {
|
if (s_rtos_lock_handle[core_id] != NULL) {
|
||||||
|
@ -375,17 +360,18 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode)
|
||||||
s_config_changed = false;
|
s_config_changed = false;
|
||||||
portEXIT_CRITICAL_ISR(&s_switch_lock);
|
portEXIT_CRITICAL_ISR(&s_switch_lock);
|
||||||
|
|
||||||
rtc_cpu_freq_t new_freq = s_cpu_freq_by_mode[new_mode];
|
rtc_cpu_freq_config_t new_config = s_cpu_freq_by_mode[new_mode];
|
||||||
rtc_cpu_freq_t old_freq;
|
rtc_cpu_freq_config_t old_config;
|
||||||
|
|
||||||
if (!config_changed) {
|
if (!config_changed) {
|
||||||
old_freq = s_cpu_freq_by_mode[s_mode];
|
old_config = s_cpu_freq_by_mode[s_mode];
|
||||||
} else {
|
} else {
|
||||||
old_freq = rtc_clk_cpu_freq_get();
|
rtc_clk_cpu_freq_get_config(&old_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_freq != old_freq) {
|
if (new_config.freq_mhz != old_config.freq_mhz) {
|
||||||
uint32_t old_ticks_per_us = g_ticks_per_us_pro;
|
uint32_t old_ticks_per_us = old_config.freq_mhz;
|
||||||
uint32_t new_ticks_per_us = s_cpu_freq_to_ticks[new_freq];
|
uint32_t new_ticks_per_us = new_config.freq_mhz;
|
||||||
|
|
||||||
bool switch_down = new_ticks_per_us < old_ticks_per_us;
|
bool switch_down = new_ticks_per_us < old_ticks_per_us;
|
||||||
|
|
||||||
|
@ -393,7 +379,7 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode)
|
||||||
if (switch_down) {
|
if (switch_down) {
|
||||||
on_freq_update(old_ticks_per_us, new_ticks_per_us);
|
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) {
|
if (!switch_down) {
|
||||||
on_freq_update(old_ticks_per_us, new_ticks_per_us);
|
on_freq_update(old_ticks_per_us, new_ticks_per_us);
|
||||||
}
|
}
|
||||||
|
@ -449,6 +435,28 @@ void esp_pm_impl_idle_hook(void)
|
||||||
ESP_PM_TRACE_ENTER(IDLE, core_id);
|
ESP_PM_TRACE_ENTER(IDLE, core_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR esp_pm_impl_isr_hook(void)
|
||||||
|
{
|
||||||
|
int core_id = xPortGetCoreID();
|
||||||
|
ESP_PM_TRACE_ENTER(ISR_HOOK, core_id);
|
||||||
|
/* Prevent higher level interrupts (than the one this function was called from)
|
||||||
|
* from happening in this section, since they will also call into esp_pm_impl_isr_hook.
|
||||||
|
*/
|
||||||
|
uint32_t state = portENTER_CRITICAL_NESTED();
|
||||||
|
#if portNUM_PROCESSORS == 2
|
||||||
|
if (s_need_update_ccompare[core_id]) {
|
||||||
|
update_ccompare();
|
||||||
|
s_need_update_ccompare[core_id] = false;
|
||||||
|
} else {
|
||||||
|
leave_idle();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
leave_idle();
|
||||||
|
#endif // portNUM_PROCESSORS == 2
|
||||||
|
portEXIT_CRITICAL_NESTED(state);
|
||||||
|
ESP_PM_TRACE_EXIT(ISR_HOOK, core_id);
|
||||||
|
}
|
||||||
|
|
||||||
void esp_pm_impl_waiti(void)
|
void esp_pm_impl_waiti(void)
|
||||||
{
|
{
|
||||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||||
|
@ -467,30 +475,37 @@ void esp_pm_impl_waiti(void)
|
||||||
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR esp_pm_impl_isr_hook(void)
|
|
||||||
{
|
|
||||||
int core_id = xPortGetCoreID();
|
|
||||||
ESP_PM_TRACE_ENTER(ISR_HOOK, core_id);
|
|
||||||
#if portNUM_PROCESSORS == 2
|
|
||||||
if (s_need_update_ccompare[core_id]) {
|
|
||||||
update_ccompare();
|
|
||||||
s_need_update_ccompare[core_id] = false;
|
|
||||||
} else {
|
|
||||||
leave_idle();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
leave_idle();
|
|
||||||
#endif // portNUM_PROCESSORS == 2
|
|
||||||
ESP_PM_TRACE_EXIT(ISR_HOOK, core_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||||
|
|
||||||
bool IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
|
static inline bool IRAM_ATTR should_skip_light_sleep(int core_id)
|
||||||
|
{
|
||||||
|
#if portNUM_PROCESSORS == 2
|
||||||
|
if (s_skip_light_sleep[core_id]) {
|
||||||
|
s_skip_light_sleep[core_id] = false;
|
||||||
|
s_skipped_light_sleep[core_id] = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif // portNUM_PROCESSORS == 2
|
||||||
|
if (s_mode != PM_MODE_LIGHT_SLEEP || s_is_switching) {
|
||||||
|
s_skipped_light_sleep[core_id] = true;
|
||||||
|
} else {
|
||||||
|
s_skipped_light_sleep[core_id] = false;
|
||||||
|
}
|
||||||
|
return s_skipped_light_sleep[core_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void IRAM_ATTR other_core_should_skip_light_sleep(int core_id)
|
||||||
|
{
|
||||||
|
#if portNUM_PROCESSORS == 2
|
||||||
|
s_skip_light_sleep[!core_id] = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
|
||||||
{
|
{
|
||||||
bool result = false;
|
|
||||||
portENTER_CRITICAL(&s_switch_lock);
|
portENTER_CRITICAL(&s_switch_lock);
|
||||||
if (s_mode == PM_MODE_LIGHT_SLEEP && !s_is_switching) {
|
int core_id = xPortGetCoreID();
|
||||||
|
if (!should_skip_light_sleep(core_id)) {
|
||||||
/* Calculate how much we can sleep */
|
/* Calculate how much we can sleep */
|
||||||
int64_t next_esp_timer_alarm = esp_timer_get_next_alarm();
|
int64_t next_esp_timer_alarm = esp_timer_get_next_alarm();
|
||||||
int64_t now = esp_timer_get_time();
|
int64_t now = esp_timer_get_time();
|
||||||
|
@ -504,7 +519,6 @@ bool IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
|
||||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||||
#endif
|
#endif
|
||||||
/* Enter sleep */
|
/* Enter sleep */
|
||||||
int core_id = xPortGetCoreID();
|
|
||||||
ESP_PM_TRACE_ENTER(SLEEP, core_id);
|
ESP_PM_TRACE_ENTER(SLEEP, core_id);
|
||||||
int64_t sleep_start = esp_timer_get_time();
|
int64_t sleep_start = esp_timer_get_time();
|
||||||
esp_light_sleep_start();
|
esp_light_sleep_start();
|
||||||
|
@ -526,11 +540,10 @@ bool IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = true;
|
other_core_should_skip_light_sleep(core_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
portEXIT_CRITICAL(&s_switch_lock);
|
portEXIT_CRITICAL(&s_switch_lock);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
#endif //CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
#endif //CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||||
|
|
||||||
|
@ -554,9 +567,9 @@ void esp_pm_impl_dump_stats(FILE* out)
|
||||||
/* don't display light sleep mode if it's not enabled */
|
/* don't display light sleep mode if it's not enabled */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
fprintf(out, "%8s %6s %12lld %2d%%\n",
|
fprintf(out, "%8s %3dM %12lld %2d%%\n",
|
||||||
s_mode_names[i],
|
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],
|
time_in_mode[i],
|
||||||
(int) (time_in_mode[i] * 100 / now));
|
(int) (time_in_mode[i] * 100 / now));
|
||||||
}
|
}
|
||||||
|
@ -565,7 +578,6 @@ void esp_pm_impl_dump_stats(FILE* out)
|
||||||
|
|
||||||
void esp_pm_impl_init(void)
|
void esp_pm_impl_init(void)
|
||||||
{
|
{
|
||||||
s_cpu_freq_to_ticks[RTC_CPU_FREQ_XTAL] = rtc_clk_xtal_freq_get();
|
|
||||||
#ifdef CONFIG_PM_TRACE
|
#ifdef CONFIG_PM_TRACE
|
||||||
esp_pm_trace_init();
|
esp_pm_trace_init();
|
||||||
#endif
|
#endif
|
||||||
|
@ -581,11 +593,11 @@ void esp_pm_impl_init(void)
|
||||||
/* Configure all modes to use the default CPU frequency.
|
/* Configure all modes to use the default CPU frequency.
|
||||||
* This will be modified later by a call to esp_pm_configure.
|
* This will be modified later by a call to esp_pm_configure.
|
||||||
*/
|
*/
|
||||||
rtc_cpu_freq_t default_freq;
|
rtc_cpu_freq_config_t default_config;
|
||||||
if (!rtc_clk_cpu_freq_from_mhz(CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ, &default_freq)) {
|
if (!rtc_clk_cpu_freq_mhz_to_config(CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ, &default_config)) {
|
||||||
assert(false && "unsupported frequency");
|
assert(false && "unsupported frequency");
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < PM_MODE_COUNT; ++i) {
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,12 @@
|
||||||
* Feel free to change when debugging.
|
* Feel free to change when debugging.
|
||||||
*/
|
*/
|
||||||
static const int DRAM_ATTR s_trace_io[] = {
|
static const int DRAM_ATTR s_trace_io[] = {
|
||||||
BIT(4), BIT(5), // ESP_PM_TRACE_IDLE
|
BIT(2), 0, // ESP_PM_TRACE_IDLE
|
||||||
BIT(16), BIT(17), // ESP_PM_TRACE_TICK
|
BIT(3), 0, // ESP_PM_TRACE_TICK
|
||||||
BIT(18), BIT(18), // ESP_PM_TRACE_FREQ_SWITCH
|
BIT(4), 0, // ESP_PM_TRACE_FREQ_SWITCH
|
||||||
BIT(19), BIT(19), // ESP_PM_TRACE_CCOMPARE_UPDATE
|
BIT(5), 0, // ESP_PM_TRACE_CCOMPARE_UPDATE
|
||||||
BIT(25), BIT(26), // ESP_PM_TRACE_ISR_HOOK
|
BIT(6), 0, // ESP_PM_TRACE_ISR_HOOK
|
||||||
BIT(27), BIT(27), // ESP_PM_TRACE_SLEEP
|
BIT(7), 0, // ESP_PM_TRACE_SLEEP
|
||||||
};
|
};
|
||||||
|
|
||||||
void esp_pm_trace_init(void)
|
void esp_pm_trace_init(void)
|
||||||
|
|
Loading…
Reference in a new issue