Merge branch 'fix/sdio_slave_add_pm_lock_v5.4' into 'release/v5.4'

fix(sdio_slave): fix issue that auto light sleep can happen SDIO slave enabled (v5.4)

See merge request espressif/esp-idf!34646
This commit is contained in:
Michael (XIAO Xufeng)
2024-11-07 02:31:38 +08:00
26 changed files with 375 additions and 52 deletions

View File

@@ -76,20 +76,24 @@ The driver of FIFOs works as below:
*/
#include <string.h>
#include "driver/sdio_slave.h"
#include "soc/sdio_slave_periph.h"
#include "esp_log.h"
#include "esp_intr_alloc.h"
#include "freertos/FreeRTOS.h"
#include "soc/soc_memory_layout.h"
#include "soc/gpio_periph.h"
#include "soc/soc_caps.h"
#include "soc/sdio_slave_periph.h"
#include "esp_cpu.h"
#include "freertos/semphr.h"
#include "esp_private/periph_ctrl.h"
#include "driver/gpio.h"
#include "esp_intr_alloc.h"
#include "esp_log.h"
#include "hal/sdio_slave_hal.h"
#include "hal/gpio_hal.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "esp_private/periph_ctrl.h"
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
#include "esp_private/sleep_retention.h"
#endif
#include "driver/gpio.h"
#include "driver/sdio_slave.h"
#define SDIO_SLAVE_CHECK(res, str, ret_val) do { if(!(res)){\
SDIO_SLAVE_LOGE("%s", str);\
@@ -365,6 +369,13 @@ esp_err_t sdio_slave_initialize(sdio_slave_config_t *config)
}
context.intr_handle = intr_handle;
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
r = sleep_retention_power_lock_acquire();
if (r != ESP_OK) {
return r;
}
#endif
r = sdio_slave_hw_init(config);
if (r != ESP_OK) {
return r;
@@ -378,6 +389,11 @@ void sdio_slave_deinit(void)
{
sdio_slave_hw_deinit();
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
esp_err_t r = sleep_retention_power_lock_release();
assert(r == ESP_OK);
#endif
//unregister all buffers registered but returned (not loaded)
recv_desc_t *temp_desc;
recv_desc_t *desc;

View File

@@ -1,7 +1,6 @@
components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/host_sdmmc:
enable:
- if: IDF_TARGET == "esp32"
temporary: false
reason: always use ESP32 SDMMC as host
depends_components:
- sdmmc
@@ -9,6 +8,10 @@ components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/host_sdmmc:
- esp_driver_sdio
components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/sdio:
enable:
# There is no retention support for SDIO slave, just build and test if driver can forbid from auto light sleep.
- if: CONFIG_NAME == "sleep_retention" and SOC_PAU_SUPPORTED == 1
- if: CONFIG_NAME != "sleep_retention"
disable:
- if: SOC_SDIO_SLAVE_SUPPORTED != 1
depends_components:

View File

@@ -418,6 +418,20 @@ TEST_CASE("SDIO_SDMMC: test to host", "[sdio]")
test_to_host(true);
}
TEST_CASE("SDIO_SDMMC: test sleep retention", "[sdio_retention]")
{
essl_handle_t handle = NULL;
test_sdio_param_t test_param = {
.host_flags = SDMMC_HOST_FLAG_4BIT | SDMMC_HOST_FLAG_ALLOC_ALIGNED_BUF,
.max_freq_khz = SDMMC_FREQ_HIGHSPEED,
};
//essl init and sdmmc init
s_master_init(&test_param, &handle, NULL);
s_send_finish_test(handle);
s_master_deinit();
}
TEST_CASE("SDIO_SDMMC: test to host (Performance)", "[sdio_speed]")
{
test_to_host(false);

View File

@@ -1,13 +1,30 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import os.path
from typing import List
from typing import Tuple
import pytest
from pytest_embedded_idf import IdfDut
def parameter_expand(existing_parameters: List[List[str]], value_list: List[str]) -> List[List[str]]:
ret = []
for param in existing_parameters:
ret.extend([param + [value] for value in value_list])
return ret
esp32_32_param = [[f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}', 'esp32|esp32']]
esp32_c6_param = [[f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}', 'esp32|esp32c6']]
esp32_param_default = [pytest.param(*param) for param in parameter_expand(esp32_32_param, ['default|default'])]
c6_param_default = [pytest.param(*param) for param in parameter_expand(esp32_c6_param, ['default|default'])]
c6_param_retention = [pytest.param(*param) for param in parameter_expand(esp32_c6_param, ['default|sleep_retention'])]
# Normal tests
def test_sdio_flow(dut:Tuple[IdfDut, IdfDut]) -> None:
dut[1].expect('Press ENTER to see the list of tests')
@@ -24,11 +41,7 @@ def test_sdio_flow(dut:Tuple[IdfDut, IdfDut]) -> None:
@pytest.mark.esp32c6
@pytest.mark.sdio_multidev_32_c6
@pytest.mark.parametrize('count', [2,], indirect=True)
@pytest.mark.parametrize('app_path, target', [
pytest.param(
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
'esp32|esp32c6'),
], indirect=True)
@pytest.mark.parametrize('app_path, target, config', c6_param_default, indirect=True)
def test_sdio_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
test_sdio_flow(dut)
@@ -36,11 +49,7 @@ def test_sdio_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
@pytest.mark.esp32
@pytest.mark.sdio_master_slave
@pytest.mark.parametrize('count', [2,], indirect=True)
@pytest.mark.parametrize('app_path, target', [
pytest.param(
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
'esp32|esp32'),
], indirect=True)
@pytest.mark.parametrize('app_path, target, config', esp32_param_default, indirect=True)
def test_sdio_esp32_esp32(dut:Tuple[IdfDut, IdfDut]) -> None:
test_sdio_flow(dut)
@@ -68,11 +77,7 @@ def test_sdio_speed_frhost_flow(dut:Tuple[IdfDut, IdfDut], expected_4b_speed:int
@pytest.mark.esp32c6
@pytest.mark.sdio_multidev_32_c6
@pytest.mark.parametrize('count', [2,], indirect=True)
@pytest.mark.parametrize('app_path, target', [
pytest.param(
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
'esp32|esp32c6'),
], indirect=True)
@pytest.mark.parametrize('app_path, target, config', c6_param_default, indirect=True)
def test_sdio_speed_frhost_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
test_sdio_speed_frhost_flow(dut, 10000, 4000)
@@ -80,11 +85,7 @@ def test_sdio_speed_frhost_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
@pytest.mark.esp32
@pytest.mark.sdio_master_slave
@pytest.mark.parametrize('count', [2,], indirect=True)
@pytest.mark.parametrize('app_path, target', [
pytest.param(
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
'esp32|esp32'),
], indirect=True)
@pytest.mark.parametrize('app_path, target, config', esp32_param_default, indirect=True)
def test_sdio_speed_frhost_esp32_esp32(dut:Tuple[IdfDut, IdfDut]) -> None:
test_sdio_speed_frhost_flow(dut, 12200, 4000)
@@ -112,11 +113,7 @@ def test_sdio_speed_tohost_flow(dut:Tuple[IdfDut, IdfDut], expected_4b_speed:int
@pytest.mark.esp32c6
@pytest.mark.sdio_multidev_32_c6
@pytest.mark.parametrize('count', [2,], indirect=True)
@pytest.mark.parametrize('app_path, target', [
pytest.param(
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
'esp32|esp32c6'),
], indirect=True)
@pytest.mark.parametrize('app_path, target, config', c6_param_default, indirect=True)
def test_sdio_speed_tohost_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
test_sdio_speed_tohost_flow(dut, 9000, 4000)
@@ -124,10 +121,27 @@ def test_sdio_speed_tohost_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
@pytest.mark.esp32
@pytest.mark.sdio_master_slave
@pytest.mark.parametrize('count', [2,], indirect=True)
@pytest.mark.parametrize('app_path, target', [
pytest.param(
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
'esp32|esp32'),
], indirect=True)
@pytest.mark.parametrize('app_path, target, config', esp32_param_default, indirect=True)
def test_sdio_speed_tohost_esp32_esp32(dut:Tuple[IdfDut, IdfDut]) -> None:
test_sdio_speed_tohost_flow(dut, 12200, 4000)
# Retention tests
def test_sdio_retention(dut:Tuple[IdfDut, IdfDut]) -> None:
dut[1].expect('Press ENTER to see the list of tests')
dut[1].write('[sdio_retention]')
dut[1].expect('test_sdio: slave ready')
dut[0].expect('Press ENTER to see the list of tests')
dut[0].write('[sdio_retention]')
dut[1].expect_unity_test_output()
dut[0].expect_unity_test_output()
@pytest.mark.esp32c6
@pytest.mark.sdio_multidev_32_c6
@pytest.mark.parametrize('count', [2,], indirect=True)
@pytest.mark.parametrize('app_path, target, config', c6_param_retention, indirect=True)
def test_sdio_retention_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
test_sdio_retention(dut)

View File

@@ -2,5 +2,5 @@ set(srcs "test_app_main.c"
"test_sdio_slave.c")
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES test_driver_utils driver
PRIV_REQUIRES test_driver_utils driver esp_hw_support
WHOLE_ARCHIVE)

View File

@@ -305,6 +305,31 @@ TEST_CASE("SDIO_Slave: test to host", "[sdio]")
test_to_host();
}
#if SOC_PAU_SUPPORTED
#include "esp_private/sleep_sys_periph.h"
#include "esp_private/sleep_retention.h"
TEST_CASE("SDIO_Slave: test sleep retention", "[sdio_retention]")
{
TEST_ASSERT_EQUAL_INT32(true, peripheral_domain_pd_allowed());
sleep_retention_dump_modules(stdout);
s_slave_init(SDIO_SLAVE_SEND_STREAM);
TEST_ESP_OK(sdio_slave_start());
ESP_LOGI(TAG, "slave ready");
TEST_ASSERT_EQUAL_INT32(false, peripheral_domain_pd_allowed());
sleep_retention_dump_modules(stdout);
wait_for_finish(&s_test_slv_ctx);
sdio_slave_stop();
sdio_slave_deinit();
TEST_ASSERT_EQUAL_INT32(true, peripheral_domain_pd_allowed());
}
#endif
TEST_CASE("SDIO_Slave: test to host (Performance)", "[sdio_speed]")
{
test_to_host();

View File

@@ -0,0 +1,4 @@
CONFIG_PM_ENABLE=y
CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y

View File

@@ -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
*

View File

@@ -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 ||

View File

@@ -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

View File

@@ -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)

View File

@@ -0,0 +1,2 @@
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 |
| ----------------- | -------- | -------- | --------- | -------- | -------- |

View File

@@ -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)

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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()

View File

@@ -0,0 +1,2 @@
CONFIG_SPIRAM=y
CONFIG_SPIRAM_XIP_FROM_PSRAM=y

View File

@@ -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

View File

@@ -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),
@@ -112,6 +115,7 @@ typedef enum periph_retention_module_bitmap {
| SLEEP_RETENTION_MODULE_BM_PARLIO0 \
| SLEEP_RETENTION_MODULE_BM_GPSPI2 \
| SLEEP_RETENTION_MODULE_BM_LEDC \
| SLEEP_RETENTION_MODULE_BM_NULL \
)
#ifdef __cplusplus
}

View File

@@ -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),
@@ -114,6 +117,7 @@ typedef enum periph_retention_module_bitmap {
| SLEEP_RETENTION_MODULE_BM_PARLIO0 \
| SLEEP_RETENTION_MODULE_BM_GPSPI2 \
| SLEEP_RETENTION_MODULE_BM_LEDC \
| SLEEP_RETENTION_MODULE_BM_NULL \
)
#ifdef __cplusplus

View File

@@ -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,
@@ -47,6 +48,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),
@@ -90,6 +93,7 @@ typedef enum periph_retention_module_bitmap {
| SLEEP_RETENTION_MODULE_BM_ETM0 \
| SLEEP_RETENTION_MODULE_BM_GPSPI2 \
| SLEEP_RETENTION_MODULE_BM_LEDC \
| SLEEP_RETENTION_MODULE_BM_NULL \
)
#ifdef __cplusplus

View File

@@ -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,
@@ -53,6 +54,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),
@@ -110,6 +113,7 @@ typedef enum periph_retention_module_bitmap {
| SLEEP_RETENTION_MODULE_BM_PARLIO0 \
| SLEEP_RETENTION_MODULE_BM_GPSPI2 \
| SLEEP_RETENTION_MODULE_BM_LEDC \
| SLEEP_RETENTION_MODULE_BM_NULL \
)
#ifdef __cplusplus

View File

@@ -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

View File

@@ -141,7 +141,7 @@ The following peripheral drivers are not aware of DFS yet. Applications need to
If :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP` is enabled, when the driver initializes the peripheral, the driver will register the working register context of the peripheral to the sleep retention link. Before entering sleep, the ``REG_DMA`` peripheral reads the configuration in the sleep retention link, and back up the register context to memory according to the configuration. ``REG_DMA`` also restores context from memory to peripheral registers on wakeup.
Currently ESP-IDF supports Light-sleep context retention for the following peripherals:
Currently ESP-IDF supports Light-sleep context retention for the following peripherals. Their context is automatically restored, or they provide some option for the user to enable this feature and goes into peripheral power down mode.
.. list::
@@ -162,7 +162,13 @@ The following peripheral drivers are not aware of DFS yet. Applications need to
:SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO
:SOC_SPI_SUPPORT_SLEEP_RETENTION: - All GPSPIs
The following peripherals are not yet supported:
Some peripherals haven't support Light-sleep context retention, or it cannot survive from the register lose. They will prevent the power-down of peripherals even when the feature is enabled.
.. list::
:SOC_SDIO_SLAVE_SUPPORTED: - SDIO Slave
The following peripherals (and those not listed in any group of this section) are not yet supported. If your application uses these peripherals, they may not work well after waking up from sleep.
.. list::
@@ -173,9 +179,6 @@ The following peripheral drivers are not aware of DFS yet. Applications need to
- USB-Serial-JTAG
- MCPWM
- SARADC
- SDIO
For peripherals that do not support Light-sleep context retention, if the Power management is enabled, the ``ESP_PM_NO_LIGHT_SLEEP`` lock should be held when the peripheral is working to avoid losing the working context of the peripheral when entering sleep.
.. note::

View File

@@ -141,7 +141,7 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
如果在 menuconfig 中启用了 :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP`,在初始化外设时,驱动会将外设工作的寄存器上下文注册到休眠备份链表中,在进入休眠前,``REG_DMA`` 外设会读取休眠备份链表中的配置,根据链表中的配置将外设的寄存器上下文备份至内存,``REG_DMA`` 也会在唤醒时将上下文从内存恢复到外设寄存中。
目前 IDF 支持以下外设的 Light-sleep 上下文备份:
目前 IDF 支持以下外设的 Light-sleep 上下文备份,它们的上下文会自动恢复,或者提供了相关的选项允许用户进入外设下电模式
.. list::
@@ -162,7 +162,13 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
:SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO
:SOC_SPI_SUPPORT_SLEEP_RETENTION: - All GPSPIs
以下外设尚未支持:
一些外设尚未支持睡眠上下文恢复,或者寄存器丢失后根本无法恢复。即使外设下电功能被启用,它们也会阻止外设下电的发生
.. list::
:SOC_SDIO_SLAVE_SUPPORTED: - SDIO Slave
以下外设(以及一些未在本章节任意一组中列出的外设)尚未支持外设下电功能。如果您的应用使用了这些外设,它们可能无法在从睡眠中醒来后仍然正常工作:
.. list::
@@ -173,9 +179,6 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
- USB-Serial-JTAG
- MCPWM
- SARADC
- SDIO
对于未支持 Light-sleep 上下文备份的外设,若启用了电源管理功能,应在外设工作时持有 ``ESP_PM_NO_LIGHT_SLEEP`` 锁以避免进入休眠导致外设工作上下文丢失。
.. note::