Merge branch 'bugfix/esp32s2_wifi_skip_light_sleep' into 'master'
esp_wifi: When WiFi TSF is active, skip light sleep Closes WIFI-2305 and WIFI-2306 See merge request espressif/esp-idf!8639
This commit is contained in:
commit
26ab1c54ec
12 changed files with 140 additions and 10 deletions
|
@ -320,6 +320,11 @@ void esp_perip_clk_init(void)
|
|||
/* Enable WiFi MAC and POWER clocks */
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN);
|
||||
|
||||
/* Set WiFi light sleep clock source to RTC slow clock */
|
||||
DPORT_REG_SET_FIELD(DPORT_BT_LPCK_DIV_INT_REG, DPORT_BT_LPCK_DIV_NUM, 0);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_BT_LPCK_DIV_FRAC_REG, DPORT_LPCLK_SEL_8M);
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_BT_LPCK_DIV_FRAC_REG, DPORT_LPCLK_SEL_RTC_SLOW);
|
||||
|
||||
/* Enable RNG clock. */
|
||||
periph_module_enable(PERIPH_RNG_MODULE);
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ typedef enum {
|
|||
ESP_SLEEP_WAKEUP_ULP, //!< Wakeup caused by ULP program
|
||||
ESP_SLEEP_WAKEUP_GPIO, //!< Wakeup caused by GPIO (light sleep only)
|
||||
ESP_SLEEP_WAKEUP_UART, //!< Wakeup caused by UART (light sleep only)
|
||||
ESP_SLEEP_WAKEUP_WIFI, //!< Wakeup caused by WIFI (light sleep only)
|
||||
} esp_sleep_source_t;
|
||||
|
||||
/* Leave this type define for compatibility */
|
||||
|
@ -239,6 +240,13 @@ esp_err_t esp_sleep_enable_uart_wakeup(int uart_num);
|
|||
*/
|
||||
uint64_t esp_sleep_get_ext1_wakeup_status(void);
|
||||
|
||||
/**
|
||||
* @brief Enable wakeup by WiFi MAC
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_sleep_enable_wifi_wakeup(void);
|
||||
|
||||
/**
|
||||
* @brief Set power down mode for an RTC power domain in sleep mode
|
||||
*
|
||||
|
@ -349,7 +357,6 @@ esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void);
|
|||
*/
|
||||
void esp_default_wake_deep_sleep(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -80,6 +80,11 @@ static uint32_t s_ccount_div;
|
|||
static uint32_t s_ccount_mul;
|
||||
|
||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
#define PERIPH_SKIP_LIGHT_SLEEP_NO 1
|
||||
|
||||
/* Indicates if light sleep shoule be skipped by peripherals. */
|
||||
static skip_light_sleep_cb_t s_periph_skip_light_sleep_cb[PERIPH_SKIP_LIGHT_SLEEP_NO];
|
||||
|
||||
/* 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.
|
||||
|
@ -477,6 +482,42 @@ void esp_pm_impl_waiti(void)
|
|||
|
||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
|
||||
esp_err_t esp_pm_register_skip_light_sleep_callback(skip_light_sleep_cb_t cb)
|
||||
{
|
||||
for (int i = 0; i < PERIPH_SKIP_LIGHT_SLEEP_NO; i++) {
|
||||
if (s_periph_skip_light_sleep_cb[i] == cb) {
|
||||
return ESP_OK;
|
||||
} else if (s_periph_skip_light_sleep_cb[i] == NULL) {
|
||||
s_periph_skip_light_sleep_cb[i] = cb;
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
esp_err_t esp_pm_unregister_skip_light_sleep_callback(skip_light_sleep_cb_t cb)
|
||||
{
|
||||
for (int i = 0; i < PERIPH_SKIP_LIGHT_SLEEP_NO; i++) {
|
||||
if (s_periph_skip_light_sleep_cb[i] == cb) {
|
||||
s_periph_skip_light_sleep_cb[i] = NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
static inline bool IRAM_ATTR periph_should_skip_light_sleep(void)
|
||||
{
|
||||
for (int i = 0; i < PERIPH_SKIP_LIGHT_SLEEP_NO; i++) {
|
||||
if (s_periph_skip_light_sleep_cb[i]) {
|
||||
if (s_periph_skip_light_sleep_cb[i]() == true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool IRAM_ATTR should_skip_light_sleep(int core_id)
|
||||
{
|
||||
#if portNUM_PROCESSORS == 2
|
||||
|
@ -486,7 +527,7 @@ static inline bool IRAM_ATTR should_skip_light_sleep(int core_id)
|
|||
return true;
|
||||
}
|
||||
#endif // portNUM_PROCESSORS == 2
|
||||
if (s_mode != PM_MODE_LIGHT_SLEEP || s_is_switching) {
|
||||
if (s_mode != PM_MODE_LIGHT_SLEEP || s_is_switching || periph_should_skip_light_sleep()) {
|
||||
s_skipped_light_sleep[core_id] = true;
|
||||
} else {
|
||||
s_skipped_light_sleep[core_id] = false;
|
||||
|
|
|
@ -582,6 +582,12 @@ esp_err_t esp_sleep_enable_uart_wakeup(int uart_num)
|
|||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_sleep_enable_wifi_wakeup(void)
|
||||
{
|
||||
s_config.wakeup_triggers |= RTC_WIFI_TRIG_EN;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void)
|
||||
{
|
||||
if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET && !s_light_sleep_wakeup) {
|
||||
|
@ -603,6 +609,8 @@ esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void)
|
|||
return ESP_SLEEP_WAKEUP_GPIO;
|
||||
} else if (wakeup_cause & (RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN)) {
|
||||
return ESP_SLEEP_WAKEUP_UART;
|
||||
} else if (wakeup_cause & RTC_WIFI_TRIG_EN) {
|
||||
return ESP_SLEEP_WAKEUP_WIFI;
|
||||
} else {
|
||||
return ESP_SLEEP_WAKEUP_UNDEFINED;
|
||||
}
|
||||
|
|
|
@ -109,6 +109,38 @@ void esp_pm_impl_dump_stats(FILE* out);
|
|||
*/
|
||||
void esp_pm_impl_waiti(void);
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
/**
|
||||
* @brief Callback function type for peripherals to skip light sleep.
|
||||
*
|
||||
*/
|
||||
typedef bool (* skip_light_sleep_cb_t)(void);
|
||||
|
||||
/**
|
||||
* @brief Register peripherals skip light sleep callback
|
||||
*
|
||||
* This function allows you to register a callback that gets the result
|
||||
* that if light sleep should be skipped by peripherals.
|
||||
* @param cb function to get the result
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_NO_MEM if no more callback slots are available
|
||||
*/
|
||||
esp_err_t esp_pm_register_skip_light_sleep_callback(skip_light_sleep_cb_t cb);
|
||||
|
||||
/**
|
||||
* @brief Unregisterperipherals skip light sleep callback
|
||||
*
|
||||
* This function allows you to unregister a callback which was previously
|
||||
* registered using esp_register_skip_light_sleep_callback.
|
||||
* @param cb function to get the result
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE if the given callback hasn't been registered before
|
||||
*/
|
||||
esp_err_t esp_pm_unregister_skip_light_sleep_callback(skip_light_sleep_cb_t cb);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_PROFILING
|
||||
#define WITH_PROFILING
|
||||
#endif
|
||||
|
|
|
@ -422,6 +422,14 @@ static int get_time_wrapper(void *t)
|
|||
return os_get_time(t);
|
||||
}
|
||||
|
||||
static uint32_t esp_clk_slowclk_cal_get_wrapper(void)
|
||||
{
|
||||
/* The bit width of WiFi light sleep clock calibration is 12 while the one of
|
||||
* system is 19. It should shift 19 - 12 = 7.
|
||||
*/
|
||||
return (esp_clk_slowclk_cal_get() >> 7);
|
||||
}
|
||||
|
||||
static void * IRAM_ATTR malloc_internal_wrapper(size_t size)
|
||||
{
|
||||
return heap_caps_malloc(size, MALLOC_CAP_8BIT|MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL);
|
||||
|
@ -604,7 +612,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
|
|||
._get_time = get_time_wrapper,
|
||||
._random = os_random,
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
._slowclk_cal_get = esp_clk_slowclk_cal_get,
|
||||
._slowclk_cal_get = esp_clk_slowclk_cal_get_wrapper,
|
||||
#endif
|
||||
._log_write = esp_log_write,
|
||||
._log_writev = esp_log_writev,
|
||||
|
|
|
@ -414,6 +414,17 @@ esp_err_t esp_wifi_internal_get_negotiated_channel(wifi_interface_t ifx, uint8_t
|
|||
*/
|
||||
esp_err_t esp_wifi_internal_get_negotiated_bandwidth(wifi_interface_t ifx, uint8_t aid, uint8_t *bw);
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
/**
|
||||
* @brief Check if WiFi TSF is active
|
||||
*
|
||||
* @return
|
||||
* - true: Active
|
||||
* - false: Not active
|
||||
*/
|
||||
bool esp_wifi_internal_is_tsf_active(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "esp_log.h"
|
||||
#include "esp_private/wifi.h"
|
||||
#include "esp_pm.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_private/pm_impl.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "esp_wpa.h"
|
||||
#include "esp_netif.h"
|
||||
|
@ -121,6 +123,11 @@ esp_err_t esp_wifi_deinit(void)
|
|||
|
||||
#if CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER
|
||||
tcpip_adapter_clear_default_wifi_handlers();
|
||||
#endif
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
esp_pm_unregister_skip_light_sleep_callback(esp_wifi_internal_is_tsf_active);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return err;
|
||||
|
@ -137,6 +144,16 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
esp_err_t ret = esp_pm_register_skip_light_sleep_callback(esp_wifi_internal_is_tsf_active);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to register skip light sleep callback (0x%x)", ret);
|
||||
return ret;
|
||||
}
|
||||
esp_sleep_enable_wifi_wakeup();
|
||||
#endif
|
||||
#endif
|
||||
#if CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER
|
||||
esp_err_t err = tcpip_adapter_set_default_wifi_handlers();
|
||||
if (err != ESP_OK) {
|
||||
|
|
|
@ -700,7 +700,7 @@ void rtc_sleep_set_wakeup_time(uint64_t t);
|
|||
#define RTC_GPIO_TRIG_EN BIT(2) //!< GPIO wakeup (light sleep only)
|
||||
#define RTC_TIMER_TRIG_EN BIT(3) //!< Timer wakeup
|
||||
#define RTC_SDIO_TRIG_EN BIT(4) //!< SDIO wakeup (light sleep only)
|
||||
#define RTC_MAC_TRIG_EN BIT(5) //!< MAC wakeup (light sleep only)
|
||||
#define RTC_WIFI_TRIG_EN BIT(5) //!< WIFI wakeup (light sleep only)
|
||||
#define RTC_UART0_TRIG_EN BIT(6) //!< UART0 wakeup (light sleep only)
|
||||
#define RTC_UART1_TRIG_EN BIT(7) //!< UART1 wakeup (light sleep only)
|
||||
#define RTC_TOUCH_TRIG_EN BIT(8) //!< Touch wakeup
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# Wifi Power Save Example
|
||||
|
||||
This example shows how to use power save mode of wifi.
|
||||
|
|
|
@ -70,13 +70,13 @@ menu "Example Configuration"
|
|||
|
||||
config EXAMPLE_MIN_CPU_FREQ_40M
|
||||
bool "40 MHz (use with 40MHz XTAL)"
|
||||
depends on ESP32_XTAL_FREQ_40 || ESP32_XTAL_FREQ_AUTO
|
||||
depends on IDF_TARGET_ESP32S2 || ESP32_XTAL_FREQ_40 || ESP32_XTAL_FREQ_AUTO
|
||||
config EXAMPLE_MIN_CPU_FREQ_20M
|
||||
bool "20 MHz (use with 40MHz XTAL)"
|
||||
depends on ESP32_XTAL_FREQ_40 || ESP32_XTAL_FREQ_AUTO
|
||||
depends on IDF_TARGET_ESP32S2 || ESP32_XTAL_FREQ_40 || ESP32_XTAL_FREQ_AUTO
|
||||
config EXAMPLE_MIN_CPU_FREQ_10M
|
||||
bool "10 MHz (use with 40MHz XTAL)"
|
||||
depends on ESP32_XTAL_FREQ_40 || ESP32_XTAL_FREQ_AUTO
|
||||
depends on IDF_TARGET_ESP32S2 || ESP32_XTAL_FREQ_40 || ESP32_XTAL_FREQ_AUTO
|
||||
config EXAMPLE_MIN_CPU_FREQ_26M
|
||||
bool "26 MHz (use with 26MHz XTAL)"
|
||||
depends on ESP32_XTAL_FREQ_26 || ESP32_XTAL_FREQ_AUTO
|
||||
|
|
|
@ -95,7 +95,11 @@ void app_main(void)
|
|||
// Configure dynamic frequency scaling:
|
||||
// maximum and minimum frequencies are set in sdkconfig,
|
||||
// automatic light sleep is enabled if tickless idle support is enabled.
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
esp_pm_config_esp32_t pm_config = {
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
esp_pm_config_esp32s2_t pm_config = {
|
||||
#endif
|
||||
.max_freq_mhz = CONFIG_EXAMPLE_MAX_CPU_FREQ_MHZ,
|
||||
.min_freq_mhz = CONFIG_EXAMPLE_MIN_CPU_FREQ_MHZ,
|
||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
|
|
Loading…
Reference in a new issue