mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 01:29:21 -04:00
feat(sleep_retention): allow drivers taking TOP power lock
Also add a dump function
This commit is contained in:
parent
116c3d6ddb
commit
df2d09e3e0
@ -59,6 +59,11 @@ typedef enum {
|
||||
*/
|
||||
esp_err_t sleep_retention_entries_create(const sleep_retention_entries_config_t retent[], int num, regdma_link_priority_t priority, sleep_retention_module_t module);
|
||||
|
||||
/**
|
||||
* @brief Dump the initialization status of all modules.
|
||||
*/
|
||||
void sleep_retention_dump_modules(FILE *out);
|
||||
|
||||
/**
|
||||
* @brief Dump all runtime sleep retention linked lists
|
||||
*/
|
||||
@ -139,6 +144,23 @@ esp_err_t sleep_retention_module_allocate(sleep_retention_module_t module);
|
||||
*/
|
||||
esp_err_t sleep_retention_module_free(sleep_retention_module_t module);
|
||||
|
||||
/**
|
||||
* @brief Force take the power lock so that during sleep the power domain won't be powered off.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if success
|
||||
* - other value when the internal `sleep_retention_module_init` fails.
|
||||
*/
|
||||
esp_err_t sleep_retention_power_lock_acquire(void);
|
||||
|
||||
/**
|
||||
* @brief Release the power lock so that the peripherals' power domain can be powered off.
|
||||
* Please note that there is an internal reference counter and the power domain will be kept on until same number
|
||||
* of `sleep_retention_power_lock_release` is called as `sleep_retention_power_lock_acquire`.
|
||||
* @return always ESP_OK
|
||||
*/
|
||||
esp_err_t sleep_retention_power_lock_release(void);
|
||||
|
||||
/**
|
||||
* @brief Get all initialized modules that require sleep retention
|
||||
*
|
||||
|
@ -29,6 +29,8 @@
|
||||
#endif
|
||||
|
||||
static __attribute__((unused)) const char *TAG = "sleep";
|
||||
static int acquire_cnt; //for the force acquire lock
|
||||
|
||||
|
||||
struct sleep_retention_module_object {
|
||||
sleep_retention_module_callbacks_t cbs; /* A callback list that can extend more sleep retention event callbacks */
|
||||
@ -319,6 +321,23 @@ static void sleep_retention_entries_stats(void)
|
||||
_lock_release_recursive(&s_retention.lock);
|
||||
}
|
||||
|
||||
void sleep_retention_dump_modules(FILE *out)
|
||||
{
|
||||
uint32_t inited_modules = sleep_retention_get_inited_modules();
|
||||
uint32_t created_modules = sleep_retention_get_created_modules();
|
||||
for (int i = SLEEP_RETENTION_MODULE_MIN; i <= SLEEP_RETENTION_MODULE_MAX; i++) {
|
||||
bool inited = (inited_modules & BIT(i)) != 0;
|
||||
bool created = (created_modules & BIT(i)) != 0;
|
||||
bool is_top = (TOP_DOMAIN_PERIPHERALS_BM & BIT(i)) != 0;
|
||||
|
||||
const char* status = !inited? "-":
|
||||
created? "CREATED":
|
||||
"INITED";
|
||||
const char* domain = is_top? "TOP": "-";
|
||||
fprintf(out, "%2d: %4s %8s\n", i, domain, status);
|
||||
}
|
||||
}
|
||||
|
||||
void sleep_retention_dump_entries(FILE *out)
|
||||
{
|
||||
_lock_acquire_recursive(&s_retention.lock);
|
||||
@ -820,6 +839,42 @@ esp_err_t sleep_retention_module_free(sleep_retention_module_t module)
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t empty_create(void *args)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t sleep_retention_power_lock_acquire(void)
|
||||
{
|
||||
_lock_acquire_recursive(&s_retention.lock);
|
||||
if (acquire_cnt == 0) {
|
||||
sleep_retention_module_init_param_t init_param = {
|
||||
.cbs = { .create = {.handle = empty_create},},
|
||||
};
|
||||
esp_err_t ret = sleep_retention_module_init(SLEEP_RETENTION_MODULE_NULL, &init_param);
|
||||
if (ret != ESP_OK) {
|
||||
_lock_release_recursive(&s_retention.lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
acquire_cnt++;
|
||||
_lock_release_recursive(&s_retention.lock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t sleep_retention_power_lock_release(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
_lock_acquire_recursive(&s_retention.lock);
|
||||
acquire_cnt--;
|
||||
assert(acquire_cnt >= 0);
|
||||
if (acquire_cnt == 0) {
|
||||
ret = sleep_retention_module_deinit(SLEEP_RETENTION_MODULE_NULL);
|
||||
}
|
||||
_lock_release_recursive(&s_retention.lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void IRAM_ATTR sleep_retention_do_extra_retention(bool backup_or_restore)
|
||||
{
|
||||
if (s_retention.highpri < SLEEP_RETENTION_REGDMA_LINK_HIGHEST_PRIORITY ||
|
||||
|
@ -42,6 +42,11 @@ components/esp_hw_support/test_apps/rtc_power_modes:
|
||||
temporary: true
|
||||
reason: the other targets are not tested yet
|
||||
|
||||
components/esp_hw_support/test_apps/sleep_retention:
|
||||
enable:
|
||||
- if: SOC_PAU_SUPPORTED == 1 and CONFIG_NAME != "xip_psram"
|
||||
- if: SOC_PAU_SUPPORTED == 1 and (SOC_SPIRAM_XIP_SUPPORTED == 1 and CONFIG_NAME == "xip_psram")
|
||||
|
||||
components/esp_hw_support/test_apps/vad_wakeup:
|
||||
disable:
|
||||
- if: SOC_LP_VAD_SUPPORTED != 1
|
||||
|
@ -0,0 +1,10 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on esp_psram
|
||||
# as we set CONFIG_SPIRAM_... options.
|
||||
set(COMPONENTS main esp_psram)
|
||||
|
||||
project(test_retention)
|
@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 |
|
||||
| ----------------- | -------- | -------- | --------- | -------- | -------- |
|
@ -0,0 +1,7 @@
|
||||
set(srcs "test_app_main.c" "test_retention.c")
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
# the component can be registered as WHOLE_ARCHIVE
|
||||
idf_component_register(SRCS ${srcs}
|
||||
PRIV_REQUIRES unity esp_mm esp_psram
|
||||
WHOLE_ARCHIVE)
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-300)
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
unity_run_menu();
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "esp_private/sleep_sys_periph.h"
|
||||
#include "esp_private/sleep_retention.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_private/sleep_cpu.h"
|
||||
|
||||
const char TAG[] = "retention";
|
||||
|
||||
TEST_CASE("retention: can go to retention", "[retention]")
|
||||
{
|
||||
// Prepare a TOP PD sleep
|
||||
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000));
|
||||
sleep_cpu_configure(true);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT32(true, peripheral_domain_pd_allowed());
|
||||
sleep_retention_dump_modules(stdout);
|
||||
vTaskDelay(1000/portTICK_PERIOD_MS);
|
||||
|
||||
ESP_LOGI(TAG, "Going to sleep...");
|
||||
esp_light_sleep_start();
|
||||
|
||||
ESP_LOGI(TAG, "After wakeup");
|
||||
TEST_ASSERT_EQUAL_INT32(true, peripheral_domain_pd_allowed());
|
||||
sleep_retention_dump_modules(stdout);
|
||||
|
||||
sleep_cpu_configure(false);
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import functools
|
||||
from typing import Callable
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
def target_list(targets: List[str]) -> Callable:
|
||||
|
||||
def decorator(func: Callable) -> Callable:
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args: List, **kwargs: Dict) -> Callable:
|
||||
return func(*args, **kwargs) # type: ignore
|
||||
|
||||
for target in targets:
|
||||
wrapper = pytest.mark.__getattr__(target)(wrapper)
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
# SOC_PAU_SUPPORTED == 1
|
||||
retention_targets = ['esp32c6', 'esp32h2', 'esp32p4', 'esp32c5', 'esp32c61']
|
||||
|
||||
|
||||
@target_list(retention_targets)
|
||||
@pytest.mark.generic
|
||||
def test_sleep_retention(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
@ -0,0 +1,2 @@
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_XIP_FROM_PSRAM=y
|
@ -0,0 +1,6 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
|
||||
CONFIG_PM_ENABLE=y
|
||||
CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y
|
||||
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
|
@ -15,6 +15,7 @@ extern "C" {
|
||||
|
||||
typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_MIN = 0,
|
||||
SLEEP_RETENTION_MODULE_NULL = SLEEP_RETENTION_MODULE_MIN, /* This module is for all peripherals that can't survive from PD_TOP to call init only. Shouldn't have any dependency. */
|
||||
/* clock module, which includes system and modem */
|
||||
SLEEP_RETENTION_MODULE_CLOCK_SYSTEM = 1,
|
||||
SLEEP_RETENTION_MODULE_CLOCK_MODEM = 2,
|
||||
@ -55,6 +56,8 @@ typedef enum periph_retention_module {
|
||||
} periph_retention_module_t;
|
||||
|
||||
typedef enum periph_retention_module_bitmap {
|
||||
SLEEP_RETENTION_MODULE_BM_NULL = BIT(SLEEP_RETENTION_MODULE_NULL),
|
||||
|
||||
/* clock module, which includes system and modem */
|
||||
SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM),
|
||||
SLEEP_RETENTION_MODULE_BM_CLOCK_MODEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM),
|
||||
@ -115,6 +118,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
| SLEEP_RETENTION_MODULE_BM_GPSPI2 \
|
||||
| SLEEP_RETENTION_MODULE_BM_LEDC \
|
||||
| SLEEP_RETENTION_MODULE_BM_PCNT0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_NULL \
|
||||
)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ extern "C" {
|
||||
|
||||
typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_MIN = 0,
|
||||
SLEEP_RETENTION_MODULE_NULL = SLEEP_RETENTION_MODULE_MIN, /* This module is for all peripherals that can't survive from PD_TOP to call init only. Shouldn't have any dependency. */
|
||||
/* clock module, which includes system and modem */
|
||||
SLEEP_RETENTION_MODULE_CLOCK_SYSTEM = 1,
|
||||
SLEEP_RETENTION_MODULE_CLOCK_MODEM = 2,
|
||||
@ -56,6 +57,8 @@ typedef enum periph_retention_module {
|
||||
} periph_retention_module_t;
|
||||
|
||||
typedef enum periph_retention_module_bitmap {
|
||||
SLEEP_RETENTION_MODULE_BM_NULL = BIT(SLEEP_RETENTION_MODULE_NULL),
|
||||
|
||||
/* clock module, which includes system and modem */
|
||||
SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM),
|
||||
SLEEP_RETENTION_MODULE_BM_CLOCK_MODEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM),
|
||||
@ -117,6 +120,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
| SLEEP_RETENTION_MODULE_BM_GPSPI2 \
|
||||
| SLEEP_RETENTION_MODULE_BM_LEDC \
|
||||
| SLEEP_RETENTION_MODULE_BM_PCNT0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_NULL \
|
||||
)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -15,6 +15,7 @@ extern "C" {
|
||||
|
||||
typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_MIN = 0,
|
||||
SLEEP_RETENTION_MODULE_NULL = SLEEP_RETENTION_MODULE_MIN, /* This module is for all peripherals that can't survive from PD_TOP to call init only. Shouldn't have any dependency. */
|
||||
/* clock module, which includes system and modem */
|
||||
SLEEP_RETENTION_MODULE_CLOCK_SYSTEM = 1,
|
||||
SLEEP_RETENTION_MODULE_CLOCK_MODEM = 2,
|
||||
@ -48,6 +49,8 @@ typedef enum periph_retention_module {
|
||||
} periph_retention_module_t;
|
||||
|
||||
typedef enum periph_retention_module_bitmap {
|
||||
SLEEP_RETENTION_MODULE_BM_NULL = BIT(SLEEP_RETENTION_MODULE_NULL),
|
||||
|
||||
/* clock module, which includes system and modem */
|
||||
SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM),
|
||||
SLEEP_RETENTION_MODULE_BM_CLOCK_MODEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM),
|
||||
@ -93,6 +96,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
| SLEEP_RETENTION_MODULE_BM_GPSPI2 \
|
||||
| SLEEP_RETENTION_MODULE_BM_LEDC \
|
||||
| SLEEP_RETENTION_MODULE_BM_I2S0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_NULL \
|
||||
)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -15,6 +15,7 @@ extern "C" {
|
||||
|
||||
typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_MIN = 0,
|
||||
SLEEP_RETENTION_MODULE_NULL = SLEEP_RETENTION_MODULE_MIN, /* This module is for all peripherals that can't survive from PD_TOP to call init only. Shouldn't have any dependency. */
|
||||
/* clock module, which includes system and modem */
|
||||
SLEEP_RETENTION_MODULE_CLOCK_SYSTEM = 1,
|
||||
SLEEP_RETENTION_MODULE_CLOCK_MODEM = 2,
|
||||
@ -54,6 +55,8 @@ typedef enum periph_retention_module {
|
||||
} periph_retention_module_t;
|
||||
|
||||
typedef enum periph_retention_module_bitmap {
|
||||
SLEEP_RETENTION_MODULE_BM_NULL = BIT(SLEEP_RETENTION_MODULE_NULL),
|
||||
|
||||
/* clock module, which includes system and modem */
|
||||
SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM),
|
||||
SLEEP_RETENTION_MODULE_BM_CLOCK_MODEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM),
|
||||
@ -113,6 +116,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
| SLEEP_RETENTION_MODULE_BM_GPSPI2 \
|
||||
| SLEEP_RETENTION_MODULE_BM_LEDC \
|
||||
| SLEEP_RETENTION_MODULE_BM_PCNT0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_NULL \
|
||||
)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -15,6 +15,7 @@ extern "C" {
|
||||
|
||||
typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_MIN = 0,
|
||||
SLEEP_RETENTION_MODULE_NULL = SLEEP_RETENTION_MODULE_MIN, /* This module is for all peripherals that can't survive from PD_TOP to call init only. Shouldn't have any dependency. */
|
||||
/* clock module, which includes system and modem */
|
||||
SLEEP_RETENTION_MODULE_CLOCK_SYSTEM = 1,
|
||||
/* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM,
|
||||
@ -58,6 +59,8 @@ typedef enum periph_retention_module {
|
||||
} periph_retention_module_t;
|
||||
|
||||
typedef enum periph_retention_module_bitmap {
|
||||
SLEEP_RETENTION_MODULE_BM_NULL = BIT(SLEEP_RETENTION_MODULE_NULL),
|
||||
|
||||
/* clock module, which includes system and modem */
|
||||
SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM),
|
||||
/* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM,
|
||||
@ -130,6 +133,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
| SLEEP_RETENTION_MODULE_BM_GPSPI2 \
|
||||
| SLEEP_RETENTION_MODULE_BM_GPSPI3 \
|
||||
| SLEEP_RETENTION_MODULE_BM_LEDC \
|
||||
| SLEEP_RETENTION_MODULE_BM_NULL \
|
||||
)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
Loading…
x
Reference in New Issue
Block a user