feat(parlio): support sleep retention

This commit is contained in:
Chen Jichang 2024-09-30 12:54:33 +08:00
parent e9fc43f5da
commit b6645acafe
31 changed files with 469 additions and 40 deletions

View File

@ -41,6 +41,9 @@ typedef struct {
i.e. high level of valid gpio to enable the clock output, low to disable */
uint32_t io_loop_back: 1; /*!< For debug/test, the signal output from the GPIO will be fed to the input path as well */
uint32_t io_no_init: 1 __attribute__((deprecated)); /*!< Deprecated. Driver won't change the GPIO configuration in inilization. */
uint32_t allow_pd: 1; /*!< Set to allow power down. When this flag set, the driver will backup/restore the PARLIO registers before/after entering/exist sleep mode.
By this approach, the system can power off PARLIO's power domain.
This can save power, but at the expense of more RAM being consumed. */
} flags; /*!< RX driver flags */
} parlio_rx_unit_config_t;

View File

@ -40,6 +40,9 @@ typedef struct {
the output clock will be controlled by the MSB bit of the data bus,
i.e. by data_gpio_nums[PARLIO_TX_UNIT_MAX_DATA_WIDTH-1]. High level to enable the clock output, low to disable */
uint32_t io_loop_back: 1; /*!< For debug/test, the signal output from the GPIO will be fed to the input path as well */
uint32_t allow_pd: 1; /*!< Set to allow power down. When this flag set, the driver will backup/restore the PARLIO registers before/after entering/exist sleep mode.
By this approach, the system can power off PARLIO's power domain.
This can save power, but at the expense of more RAM being consumed. */
} flags; /*!< Extra configuration flags */
} parlio_tx_unit_config_t;

View File

@ -18,6 +18,7 @@
#include "soc/parlio_periph.h"
#include "hal/parlio_ll.h"
#include "esp_private/esp_clk.h"
#include "esp_private/sleep_retention.h"
#include "parlio_private.h"
static const char *TAG = "parlio";
@ -46,6 +47,23 @@ parlio_group_t *parlio_acquire_group_handle(int group_id)
parlio_ll_enable_bus_clock(group_id, true);
parlio_ll_reset_register(group_id);
}
#if PARLIO_USE_RETENTION_LINK
sleep_retention_module_t module_id = parlio_reg_retention_info[group_id].retention_module;
sleep_retention_module_init_param_t init_param = {
.cbs = {
.create = {
.handle = parlio_create_sleep_retention_link_cb,
.arg = group,
},
},
.depends = SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM
};
// we only do retention init here. Allocate retention module in the unit initialization
if (sleep_retention_module_init(module_id, &init_param) != ESP_OK) {
// even though the sleep retention module init failed, PARLIO driver should still work, so just warning here
ESP_LOGW(TAG, "init sleep retention failed %d, power domain may be turned off during sleep", group_id);
}
#endif // PARLIO_USE_RETENTION_LINK
// hal layer initialize
parlio_hal_init(&group->hal);
group->dma_align = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
@ -87,6 +105,16 @@ void parlio_release_group_handle(parlio_group_t *group)
_lock_release(&s_platform.mutex);
if (do_deinitialize) {
#if PARLIO_USE_RETENTION_LINK
const periph_retention_module_t module_id = parlio_reg_retention_info[group_id].retention_module;
if (sleep_retention_get_created_modules() & BIT(module_id)) {
assert(sleep_retention_get_inited_modules() & BIT(module_id));
sleep_retention_module_free(module_id);
}
if (sleep_retention_get_inited_modules() & BIT(module_id)) {
sleep_retention_module_deinit(module_id);
}
#endif // PARLIO_USE_RETENTION_LINK
free(group);
ESP_LOGD(TAG, "del group(%d)", group_id);
}
@ -147,3 +175,32 @@ void parlio_unregister_unit_from_group(parlio_unit_base_handle_t unit)
/* the parlio unit has a reference of the group, release it now */
parlio_release_group_handle(group);
}
#if PARLIO_USE_RETENTION_LINK
esp_err_t parlio_create_sleep_retention_link_cb(void *arg)
{
parlio_group_t *group = (parlio_group_t *)arg;
int group_id = group->group_id;
sleep_retention_module_t module_id = parlio_reg_retention_info[group_id].retention_module;
esp_err_t err = sleep_retention_entries_create(parlio_reg_retention_info[group_id].regdma_entry_array,
parlio_reg_retention_info[group_id].array_size,
REGDMA_LINK_PRI_PARLIO, module_id);
ESP_RETURN_ON_ERROR(err, TAG, "create retention link failed");
return ESP_OK;
}
void parlio_create_retention_module(parlio_group_t *group)
{
int group_id = group->group_id;
sleep_retention_module_t module_id = parlio_reg_retention_info[group_id].retention_module;
_lock_acquire(&s_platform.mutex);
if ((sleep_retention_get_inited_modules() & BIT(module_id)) && !(sleep_retention_get_created_modules() & BIT(module_id))) {
if (sleep_retention_module_allocate(module_id) != ESP_OK) {
// even though the sleep retention module create failed, PARLIO driver should still work, so just warning here
ESP_LOGW(TAG, "create retention module failed, power domain can't turn off");
}
}
_lock_release(&s_platform.mutex);
}
#endif // PARLIO_USE_RETENTION_LINK

View File

@ -24,6 +24,7 @@
#include "esp_private/periph_ctrl.h"
#include "esp_private/esp_gpio_reserve.h"
#include "esp_private/gpio.h"
#include "esp_private/sleep_retention.h"
#if CONFIG_PARLIO_ISR_IRAM_SAFE
#define PARLIO_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
@ -44,6 +45,9 @@
#define PARLIO_INTR_ALLOC_FLAG (ESP_INTR_FLAG_LOWMED | PARLIO_INTR_ALLOC_FLAG_SHARED)
#endif
// Use retention link only when the target supports sleep retention is enabled
#define PARLIO_USE_RETENTION_LINK (SOC_PARLIO_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)
#if defined(SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS) // Parlio uses GDMA
#if defined(SOC_GDMA_BUS_AHB) && (SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS == SOC_GDMA_BUS_AHB)
typedef dma_descriptor_align4_t parlio_dma_desc_t;
@ -149,6 +153,11 @@ esp_err_t parlio_register_unit_to_group(parlio_unit_base_handle_t unit);
*/
void parlio_unregister_unit_from_group(parlio_unit_base_handle_t unit);
#if PARLIO_USE_RETENTION_LINK
esp_err_t parlio_create_sleep_retention_link_cb(void *arg);
void parlio_create_retention_module(parlio_group_t *group);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -620,6 +620,10 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un
esp_err_t ret = ESP_OK;
parlio_rx_unit_handle_t unit = NULL;
#if !SOC_PARLIO_SUPPORT_SLEEP_RETENTION
ESP_RETURN_ON_FALSE(config->flags.allow_pd == 0, ESP_ERR_NOT_SUPPORTED, TAG, "register back up is not supported");
#endif // SOC_PARLIO_SUPPORT_SLEEP_RETENTION
/* Allocate unit memory */
unit = heap_caps_calloc(1, sizeof(parlio_rx_unit_t), PARLIO_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(unit, ESP_ERR_NO_MEM, err, TAG, "no memory for rx unit");
@ -676,6 +680,12 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un
}
#endif // SOC_PARLIO_RX_CLK_SUPPORT_GATING
#if PARLIO_USE_RETENTION_LINK
if (config->flags.allow_pd != 0) {
parlio_create_retention_module(group);
}
#endif // PARLIO_USE_RETENTION_LINK
/* return RX unit handle */
*ret_unit = unit;

View File

@ -270,7 +270,7 @@ static esp_err_t parlio_select_periph_clock(parlio_tx_unit_t *tx_unit, const par
#endif
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true);
PARLIO_CLOCK_SRC_ATOMIC() {
// turn on the tx module clock to sync the register configuration to the module
// turn on the tx module clock to sync the clock divider configuration because of the CDC (Cross Domain Crossing)
parlio_ll_tx_enable_clock(hal->regs, true);
parlio_ll_tx_set_clock_source(hal->regs, clk_src);
// set clock division
@ -309,6 +309,10 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
ESP_RETURN_ON_FALSE(config->flags.clk_gate_en == 0, ESP_ERR_NOT_SUPPORTED, TAG, "clock gating is not supported");
#endif // SOC_PARLIO_TX_CLK_SUPPORT_GATING
#if !SOC_PARLIO_SUPPORT_SLEEP_RETENTION
ESP_RETURN_ON_FALSE(config->flags.allow_pd == 0, ESP_ERR_NOT_SUPPORTED, TAG, "register back up is not supported");
#endif // SOC_PARLIO_SUPPORT_SLEEP_RETENTION
// malloc unit memory
uint32_t mem_caps = PARLIO_MEM_ALLOC_CAPS;
unit = heap_caps_calloc(1, sizeof(parlio_tx_unit_t) + sizeof(parlio_tx_trans_desc_t) * config->trans_queue_depth, mem_caps);
@ -381,6 +385,12 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
// GPIO Matrix/MUX configuration
ESP_GOTO_ON_ERROR(parlio_tx_unit_configure_gpio(unit, config), err, TAG, "configure gpio failed");
#if PARLIO_USE_RETENTION_LINK
if (config->flags.allow_pd != 0) {
parlio_create_retention_module(group);
}
#endif // PARLIO_USE_RETENTION_LINK
portMUX_INITIALIZE(&unit->spinlock);
atomic_init(&unit->fsm, PARLIO_TX_FSM_INIT);
// return TX unit handle
@ -468,13 +478,11 @@ static void IRAM_ATTR parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio
while (parlio_ll_tx_is_ready(hal->regs) == false);
// turn on the core clock after we start the TX unit
parlio_ll_tx_start(hal->regs, true);
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_tx_enable_clock(hal->regs, true);
}
}
esp_err_t parlio_tx_unit_enable(parlio_tx_unit_handle_t tx_unit)
{
parlio_hal_context_t *hal = &tx_unit->base.group->hal;
ESP_RETURN_ON_FALSE(tx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
parlio_tx_fsm_t expected_fsm = PARLIO_TX_FSM_INIT;
if (atomic_compare_exchange_strong(&tx_unit->fsm, &expected_fsm, PARLIO_TX_FSM_ENABLE_WAIT)) {
@ -489,6 +497,11 @@ esp_err_t parlio_tx_unit_enable(parlio_tx_unit_handle_t tx_unit)
ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_STATE, TAG, "unit not in init state");
}
// enable clock output
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_tx_enable_clock(hal->regs, true);
}
// check if we need to start one pending transaction
parlio_tx_trans_desc_t *t = NULL;
expected_fsm = PARLIO_TX_FSM_ENABLE;
@ -531,6 +544,10 @@ esp_err_t parlio_tx_unit_disable(parlio_tx_unit_handle_t tx_unit)
// stop the TX engine
parlio_hal_context_t *hal = &tx_unit->base.group->hal;
// disable clock output
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_tx_enable_clock(hal->regs, false);
}
gdma_stop(tx_unit->dma_chan);
parlio_ll_tx_start(hal->regs, false);
parlio_ll_enable_interrupt(hal->regs, PARLIO_LL_EVENT_TX_EOF, false);
@ -621,9 +638,6 @@ static void IRAM_ATTR parlio_tx_default_isr(void *args)
if (status & PARLIO_LL_EVENT_TX_EOF) {
parlio_ll_clear_interrupt_status(hal->regs, PARLIO_LL_EVENT_TX_EOF);
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_tx_enable_clock(hal->regs, false);
}
parlio_ll_tx_start(hal->regs, false);
parlio_tx_trans_desc_t *trans_desc = NULL;

View File

@ -7,6 +7,10 @@ if(CONFIG_PARLIO_ISR_IRAM_SAFE)
list(REMOVE_ITEM srcs "test_parlio_rx.c")
endif()
if(CONFIG_SOC_LIGHT_SLEEP_SUPPORTED AND CONFIG_PM_ENABLE)
list(APPEND srcs "test_parlio_sleep.c")
endif()
# 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}

View File

@ -56,14 +56,14 @@ extern "C" {
#elif CONFIG_IDF_TARGET_ESP32P4
#define TEST_CLK_GPIO 33
#define TEST_VALID_GPIO 36
#define TEST_DATA0_GPIO 20
#define TEST_DATA1_GPIO 21
#define TEST_DATA2_GPIO 22
#define TEST_DATA3_GPIO 23
#define TEST_DATA4_GPIO 45
#define TEST_DATA5_GPIO 46
#define TEST_DATA6_GPIO 47
#define TEST_DATA7_GPIO 48
#define TEST_DATA0_GPIO 0
#define TEST_DATA1_GPIO 1
#define TEST_DATA2_GPIO 2
#define TEST_DATA3_GPIO 3
#define TEST_DATA4_GPIO 4
#define TEST_DATA5_GPIO 5
#define TEST_DATA6_GPIO 6
#define TEST_DATA7_GPIO 7
#else
#error "Unsupported target"
#endif

View File

@ -0,0 +1,168 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "unity.h"
#include "driver/parlio_tx.h"
#include "driver/parlio_rx.h"
#include "driver/gpio.h"
#include "soc/soc_caps.h"
#include "soc/parl_io_struct.h"
#include "esp_private/sleep_cpu.h"
#include "esp_private/esp_sleep_internal.h"
#include "esp_private/esp_pmu.h"
#include "esp_attr.h"
#include "test_board.h"
TEST_PARLIO_CALLBACK_ATTR
static bool test_parlio_rx_done_callback(parlio_rx_unit_handle_t rx_unit, const parlio_rx_event_data_t *edata, void *user_ctx)
{
BaseType_t high_task_wakeup = pdFALSE;
TaskHandle_t task = (TaskHandle_t)user_ctx;
vTaskNotifyGiveFromISR(task, &high_task_wakeup);
return high_task_wakeup == pdTRUE;
}
#define TEST_PAYLOAD_SIZE 64
static void test_parlio_sleep_retention(bool allow_pd)
{
printf("install parlio tx unit\r\n");
parlio_tx_unit_handle_t tx_unit = NULL;
parlio_tx_unit_config_t tx_config = {
.clk_src = PARLIO_CLK_SRC_DEFAULT,
.data_width = 4,
.clk_in_gpio_num = -1, // use internal clock source
.valid_gpio_num = TEST_VALID_GPIO,
.clk_out_gpio_num = TEST_CLK_GPIO,
.data_gpio_nums = {
TEST_DATA0_GPIO,
TEST_DATA1_GPIO,
TEST_DATA2_GPIO,
TEST_DATA3_GPIO,
},
.output_clk_freq_hz = 1 * 1000 * 1000,
.trans_queue_depth = 8,
.max_transfer_size = 128,
.bit_pack_order = PARLIO_BIT_PACK_ORDER_MSB,
.sample_edge = PARLIO_SAMPLE_EDGE_POS,
.flags.allow_pd = allow_pd,
};
TEST_ESP_OK(parlio_new_tx_unit(&tx_config, &tx_unit));
printf("send packets and check event is fired\r\n");
parlio_transmit_config_t transmit_config = {
.idle_value = 0x00,
};
uint8_t tx_payload[TEST_PAYLOAD_SIZE] = {0};
for (int i = 0; i < TEST_PAYLOAD_SIZE; i++) {
tx_payload[i] = i;
}
printf("install parlio rx unit\r\n");
parlio_rx_unit_handle_t rx_unit = NULL;
parlio_rx_delimiter_handle_t deli = NULL;
parlio_rx_unit_config_t rx_config = {
.trans_queue_depth = 10,
.max_recv_size = 1024,
.data_width = 4,
.clk_src = PARLIO_CLK_SRC_DEFAULT,
.ext_clk_freq_hz = 0,
.clk_in_gpio_num = -1,
.exp_clk_freq_hz = 1 * 1000 * 1000,
.clk_out_gpio_num = -1,
.valid_gpio_num = TEST_VALID_GPIO,
.data_gpio_nums = {
TEST_DATA0_GPIO,
TEST_DATA1_GPIO,
TEST_DATA2_GPIO,
TEST_DATA3_GPIO,
},
.flags = {
.clk_gate_en = false,
.allow_pd = allow_pd,
}
};
rx_config.flags.free_clk = 1;
TEST_ESP_OK(parlio_new_rx_unit(&rx_config, &rx_unit));
parlio_rx_level_delimiter_config_t lvl_deli_cfg = {
.valid_sig_line_id = PARLIO_RX_UNIT_MAX_DATA_WIDTH - 1,
.sample_edge = PARLIO_SAMPLE_EDGE_POS,
.bit_pack_order = PARLIO_BIT_PACK_ORDER_MSB,
.eof_data_len = TEST_PAYLOAD_SIZE,
.timeout_ticks = 0,
.flags = {
.active_low_en = 0,
},
};
TEST_ESP_OK(parlio_new_rx_level_delimiter(&lvl_deli_cfg, &deli));
printf("register receive_done event callback\r\n");
parlio_rx_event_callbacks_t rx_cbs = {
.on_receive_done = test_parlio_rx_done_callback,
};
TEST_ESP_OK(parlio_rx_unit_register_event_callbacks(rx_unit, &rx_cbs, xTaskGetCurrentTaskHandle()));
parlio_receive_config_t recv_config = {
.delimiter = deli,
.flags.partial_rx_en = false,
};
__attribute__((aligned(TEST_PAYLOAD_SIZE))) uint8_t rx_payload[TEST_PAYLOAD_SIZE] = {0};
// go to sleep
esp_sleep_context_t sleep_ctx;
esp_sleep_set_sleep_context(&sleep_ctx);
printf("go to light sleep for 2 seconds\r\n");
#if ESP_SLEEP_POWER_DOWN_CPU
TEST_ESP_OK(sleep_cpu_configure(true));
#endif
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(2 * 1000 * 1000));
TEST_ESP_OK(esp_light_sleep_start());
printf("Waked up! Let's see if PARLIO driver can still work...\r\n");
#if ESP_SLEEP_POWER_DOWN_CPU
TEST_ESP_OK(sleep_cpu_configure(false));
#endif
printf("check if the sleep happened as expected\r\n");
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
#if SOC_PARLIO_SUPPORT_SLEEP_RETENTION
// check if the power domain also is powered down
TEST_ASSERT_EQUAL(allow_pd ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP);
#endif
esp_sleep_set_sleep_context(NULL);
printf("Testing tx and rx after sleep...\n");
TEST_ESP_OK(parlio_tx_unit_enable(tx_unit));
TEST_ESP_OK(parlio_rx_unit_enable(rx_unit, 1));
TEST_ESP_OK(parlio_rx_unit_receive(rx_unit, rx_payload, TEST_PAYLOAD_SIZE, &recv_config));
TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, tx_payload, TEST_PAYLOAD_SIZE * sizeof(uint8_t) * 8, &transmit_config));
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(1000)));
for (int i = 0; i < TEST_PAYLOAD_SIZE; i++) {
printf("%.2d ", (rx_payload[i]));
TEST_ASSERT_EQUAL(tx_payload[i], rx_payload[i]);
if ((i + 1) % 16 == 0) {
printf("\n");
}
}
TEST_ESP_OK(parlio_tx_unit_disable(tx_unit));
TEST_ESP_OK(parlio_del_tx_unit(tx_unit));
TEST_ESP_OK(parlio_rx_unit_disable(rx_unit));
TEST_ESP_OK(parlio_del_rx_delimiter(deli));
TEST_ESP_OK(parlio_del_rx_unit(rx_unit));
}
TEST_CASE("parlio light sleep", "[parlio]")
{
test_parlio_sleep_retention(false);
#if SOC_PARLIO_SUPPORT_SLEEP_RETENTION
test_parlio_sleep_retention(true);
#endif
}

View File

@ -1,5 +1,6 @@
CONFIG_PM_ENABLE=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

View File

@ -3,3 +3,6 @@
#
CONFIG_ESP_TASK_WDT_INIT=n
CONFIG_FREERTOS_HZ=1000
# primitives for checking sleep internal state
CONFIG_ESP_SLEEP_DEBUG=y

View File

@ -915,6 +915,10 @@ config SOC_PARLIO_TX_SIZE_BY_DMA
bool
default y
config SOC_PARLIO_SUPPORT_SLEEP_RETENTION
bool
default y
config SOC_MPI_MEM_BLOCKS_NUM
int
default 4

View File

@ -39,6 +39,7 @@ typedef enum periph_retention_module {
SLEEP_RETENTION_MODULE_I2S0 = 16,
SLEEP_RETENTION_MODULE_ETM0 = 17,
SLEEP_RETENTION_MODULE_TEMP_SENSOR = 18,
SLEEP_RETENTION_MODULE_PARLIO0 = 19,
/* modem module, which includes WiFi, BLE and 802.15.4 */
SLEEP_RETENTION_MODULE_WIFI_MAC = 26,
@ -80,6 +81,7 @@ typedef enum periph_retention_module_bitmap {
SLEEP_RETENTION_MODULE_BM_I2S0 = BIT(SLEEP_RETENTION_MODULE_I2S0),
SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0),
SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR = BIT(SLEEP_RETENTION_MODULE_TEMP_SENSOR),
SLEEP_RETENTION_MODULE_BM_PARLIO0 = BIT(SLEEP_RETENTION_MODULE_PARLIO0),
SLEEP_RETENTION_MODULE_BM_GDMA_CH0 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH0),
SLEEP_RETENTION_MODULE_BM_GDMA_CH1 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH1),
@ -103,6 +105,7 @@ typedef enum periph_retention_module_bitmap {
| SLEEP_RETENTION_MODULE_BM_I2S0 \
| SLEEP_RETENTION_MODULE_BM_ETM0 \
| SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR \
| SLEEP_RETENTION_MODULE_BM_PARLIO0 \
)
#ifdef __cplusplus
}

View File

@ -370,6 +370,7 @@
#define SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT 1 /*!< Support output RX clock to a GPIO */
#define SOC_PARLIO_TRANS_BIT_ALIGN 1 /*!< Support bit alignment in transaction */
#define SOC_PARLIO_TX_SIZE_BY_DMA 1 /*!< Transaction length is controlled by DMA instead of indicated by register */
#define SOC_PARLIO_SUPPORT_SLEEP_RETENTION 1 /*!< Support back up registers before sleep */
/*--------------------------- MPI CAPS ---------------------------------------*/
#define SOC_MPI_MEM_BLOCKS_NUM (4)

View File

@ -48,3 +48,31 @@ const parlio_signal_conn_t parlio_periph_signals = {
},
},
};
/**
* PARLIO Registers to be saved during sleep retention
* - Tx Configuration registers, e.g.: PARL_IO_TX_DATA_CFG_REG, PARL_IO_TX_GENRL_CFG_REG
* - Rx Configuration registers, e.g.: PARL_IO_RX_MODE_CFG_REG, PARL_IO_RX_DATA_CFG_REG, PARL_IO_RX_GENRL_CFG_REG
* - CLK Configuration registers, e.g.: PARL_IO_RX_CLK_CFG_REG, PARL_IO_TX_CLK_CFG_REG
* - Interrupt enable registers, e.g.: PARL_IO_INT_ENA_REG
*/
#define PARLIO_RETENTION_REGS_CNT 8
#define PARLIO_RETENTION_REGS_BASE (DR_REG_PARL_IO_BASE + 0x0)
static const uint32_t parlio_regs_map[4] = {0x60457, 0x0, 0x0, 0x0};
static const regdma_entries_config_t parlio_regs_retention[] = {
// backup stage: save configuration registers
// restore stage: restore the configuration registers
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_PARLIO_LINK(0x00), \
PARLIO_RETENTION_REGS_BASE, PARLIO_RETENTION_REGS_BASE, \
PARLIO_RETENTION_REGS_CNT, 0, 0, \
parlio_regs_map[0], parlio_regs_map[1], \
parlio_regs_map[2], parlio_regs_map[3]), \
.owner = ENTRY(0) | ENTRY(2) }, \
};
const parlio_reg_retention_info_t parlio_reg_retention_info[SOC_PARLIO_GROUPS] = {
[0] = {
.regdma_entry_array = parlio_regs_retention,
.array_size = ARRAY_SIZE(parlio_regs_retention),
.retention_module = SLEEP_RETENTION_MODULE_PARLIO0
},
};

View File

@ -907,6 +907,10 @@ config SOC_PARLIO_TX_RX_SHARE_INTERRUPT
bool
default y
config SOC_PARLIO_SUPPORT_SLEEP_RETENTION
bool
default y
config SOC_MPI_MEM_BLOCKS_NUM
int
default 4

View File

@ -41,6 +41,7 @@ typedef enum periph_retention_module {
SLEEP_RETENTION_MODULE_TEMP_SENSOR = 18,
SLEEP_RETENTION_MODULE_TWAI0 = 19,
SLEEP_RETENTION_MODULE_TWAI1 = 20,
SLEEP_RETENTION_MODULE_PARLIO0 = 21,
/* Modem module, which includes WiFi, BLE and 802.15.4 */
SLEEP_RETENTION_MODULE_WIFI_MAC = 26,
@ -78,6 +79,7 @@ typedef enum periph_retention_module_bitmap {
SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR = BIT(SLEEP_RETENTION_MODULE_TEMP_SENSOR),
SLEEP_RETENTION_MODULE_BM_TWAI0 = BIT(SLEEP_RETENTION_MODULE_TWAI0),
SLEEP_RETENTION_MODULE_BM_TWAI1 = BIT(SLEEP_RETENTION_MODULE_TWAI1),
SLEEP_RETENTION_MODULE_BM_PARLIO0 = BIT(SLEEP_RETENTION_MODULE_PARLIO0),
/* modem module, which includes WiFi, BLE and 802.15.4 */
SLEEP_RETENTION_MODULE_BM_WIFI_MAC = BIT(SLEEP_RETENTION_MODULE_WIFI_MAC),
SLEEP_RETENTION_MODULE_BM_WIFI_BB = BIT(SLEEP_RETENTION_MODULE_WIFI_BB),
@ -105,6 +107,7 @@ typedef enum periph_retention_module_bitmap {
| SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR \
| SLEEP_RETENTION_MODULE_BM_TWAI0 \
| SLEEP_RETENTION_MODULE_BM_TWAI1 \
| SLEEP_RETENTION_MODULE_BM_PARLIO0 \
)
#ifdef __cplusplus

View File

@ -349,6 +349,7 @@
#define SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the TX unit */
#define SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the RX unit */
#define SOC_PARLIO_TX_RX_SHARE_INTERRUPT 1 /*!< TX and RX unit share the same interrupt source number */
#define SOC_PARLIO_SUPPORT_SLEEP_RETENTION 1 /*!< Support back up registers before sleep */
/*--------------------------- MPI CAPS ---------------------------------------*/
#define SOC_MPI_MEM_BLOCKS_NUM (4)

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -64,3 +64,29 @@ const parlio_signal_conn_t parlio_periph_signals = {
},
},
};
/**
* PARLIO Registers to be saved during sleep retention
* - Configuration registers, e.g.: PARL_IO_RX_CFG0_REG, PARL_IO_RX_CFG1_REG, PARL_IO_TX_CFG0_REG, PARL_IO_TX_CFG1_REG, PARL_IO_CLK_REG
* - Interrupt enable registers, e.g.: PARL_IO_INT_ENA_REG
*/
#define PARLIO_RETENTION_REGS_CNT 6
#define PARLIO_RETENTION_REGS_BASE (DR_REG_PARL_IO_BASE + 0x0)
static const uint32_t parlio_regs_map[4] = {0x2f, 0x0, 0x100, 0x0};
static const regdma_entries_config_t parlio_regs_retention[] = {
// backup stage: save configuration registers
// restore stage: restore the configuration registers
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_PARLIO_LINK(0x00), \
PARLIO_RETENTION_REGS_BASE, PARLIO_RETENTION_REGS_BASE, \
PARLIO_RETENTION_REGS_CNT, 0, 0, \
parlio_regs_map[0], parlio_regs_map[1], \
parlio_regs_map[2], parlio_regs_map[3]), \
.owner = ENTRY(0) | ENTRY(2) }, \
};
const parlio_reg_retention_info_t parlio_reg_retention_info[SOC_PARLIO_GROUPS] = {
[0] = {
.regdma_entry_array = parlio_regs_retention,
.array_size = ARRAY_SIZE(parlio_regs_retention),
.retention_module = SLEEP_RETENTION_MODULE_PARLIO0
},
};

View File

@ -903,6 +903,10 @@ config SOC_PARLIO_TRANS_BIT_ALIGN
bool
default y
config SOC_PARLIO_SUPPORT_SLEEP_RETENTION
bool
default y
config SOC_MPI_MEM_BLOCKS_NUM
int
default 4

View File

@ -41,6 +41,7 @@ typedef enum periph_retention_module {
SLEEP_RETENTION_MODULE_ETM0 = 18,
SLEEP_RETENTION_MODULE_TEMP_SENSOR = 19,
SLEEP_RETENTION_MODULE_TWAI0 = 20,
SLEEP_RETENTION_MODULE_PARLIO0 = 21,
/* Modem module, which includes BLE and 802.15.4 */
SLEEP_RETENTION_MODULE_BLE_MAC = 28,
@ -76,6 +77,7 @@ typedef enum periph_retention_module_bitmap {
SLEEP_RETENTION_MODULE_BM_ETM0 = BIT(SLEEP_RETENTION_MODULE_ETM0),
SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR = BIT(SLEEP_RETENTION_MODULE_TEMP_SENSOR),
SLEEP_RETENTION_MODULE_BM_TWAI0 = BIT(SLEEP_RETENTION_MODULE_TWAI0),
SLEEP_RETENTION_MODULE_BM_PARLIO0 = BIT(SLEEP_RETENTION_MODULE_PARLIO0),
/* modem module, which includes BLE and 802.15.4 */
SLEEP_RETENTION_MODULE_BM_BLE_MAC = BIT(SLEEP_RETENTION_MODULE_BLE_MAC),
SLEEP_RETENTION_MODULE_BM_BT_BB = BIT(SLEEP_RETENTION_MODULE_BT_BB),
@ -101,6 +103,7 @@ typedef enum periph_retention_module_bitmap {
| SLEEP_RETENTION_MODULE_BM_ETM0 \
| SLEEP_RETENTION_MODULE_BM_TEMP_SENSOR \
| SLEEP_RETENTION_MODULE_BM_TWAI0 \
| SLEEP_RETENTION_MODULE_BM_PARLIO0 \
)
#ifdef __cplusplus

View File

@ -346,6 +346,7 @@
#define SOC_PARLIO_RX_CLK_SUPPORT_GATING 1 /*!< Support gating RX clock */
#define SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT 1 /*!< Support output RX clock to a GPIO */
#define SOC_PARLIO_TRANS_BIT_ALIGN 1 /*!< Support bit alignment in transaction */
#define SOC_PARLIO_SUPPORT_SLEEP_RETENTION 1 /*!< Support back up registers before sleep */
/*--------------------------- MPI CAPS ---------------------------------------*/
#define SOC_MPI_MEM_BLOCKS_NUM (4)

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -48,3 +48,31 @@ const parlio_signal_conn_t parlio_periph_signals = {
},
},
};
/**
* PARLIO Registers to be saved during sleep retention
* - Tx Configuration registers, e.g.: PARL_IO_TX_DATA_CFG_REG, PARL_IO_TX_GENRL_CFG_REG
* - Rx Configuration registers, e.g.: PARL_IO_RX_MODE_CFG_REG, PARL_IO_RX_DATA_CFG_REG, PARL_IO_RX_GENRL_CFG_REG
* - CLK Configuration registers, e.g.: PARL_IO_RX_CLK_CFG_REG, PARL_IO_TX_CLK_CFG_REG
* - Interrupt enable registers, e.g.: PARL_IO_INT_ENA_REG
*/
#define PARLIO_RETENTION_REGS_CNT 8
#define PARLIO_RETENTION_REGS_BASE (DR_REG_PARL_IO_BASE + 0x0)
static const uint32_t parlio_regs_map[4] = {0x60457, 0x0, 0x0, 0x0};
static const regdma_entries_config_t parlio_regs_retention[] = {
// backup stage: save configuration registers
// restore stage: restore the configuration registers
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_PARLIO_LINK(0x00), \
PARLIO_RETENTION_REGS_BASE, PARLIO_RETENTION_REGS_BASE, \
PARLIO_RETENTION_REGS_CNT, 0, 0, \
parlio_regs_map[0], parlio_regs_map[1], \
parlio_regs_map[2], parlio_regs_map[3]), \
.owner = ENTRY(0) | ENTRY(2) }, \
};
const parlio_reg_retention_info_t parlio_reg_retention_info[SOC_PARLIO_GROUPS] = {
[0] = {
.regdma_entry_array = parlio_regs_retention,
.array_size = ARRAY_SIZE(parlio_regs_retention),
.retention_module = SLEEP_RETENTION_MODULE_PARLIO0
},
};

View File

@ -1287,6 +1287,10 @@ config SOC_PARLIO_TX_SIZE_BY_DMA
bool
default y
config SOC_PARLIO_SUPPORT_SLEEP_RETENTION
bool
default y
config SOC_MPI_MEM_BLOCKS_NUM
int
default 4

View File

@ -25,22 +25,21 @@ typedef enum periph_retention_module {
SLEEP_RETENTION_MODULE_TG1_WDT = 4,
SLEEP_RETENTION_MODULE_TG0_TIMER = 5,
SLEEP_RETENTION_MODULE_TG1_TIMER = 6,
/* MISC Peripherals */
SLEEP_RETENTION_MODULE_UART0 = 7,
SLEEP_RETENTION_MODULE_UART1 = 8,
SLEEP_RETENTION_MODULE_UART2 = 9,
SLEEP_RETENTION_MODULE_UART3 = 10,
SLEEP_RETENTION_MODULE_UART4 = 11,
SLEEP_RETENTION_MODULE_RMT0 = 12,
/* AHB_DMA by channel */
SLEEP_RETENTION_MODULE_AHB_DMA_CH0 = 13,
SLEEP_RETENTION_MODULE_AHB_DMA_CH1 = 14,
SLEEP_RETENTION_MODULE_AHB_DMA_CH2 = 15,
SLEEP_RETENTION_MODULE_AHB_DMA_CH0 = 7,
SLEEP_RETENTION_MODULE_AHB_DMA_CH1 = 8,
SLEEP_RETENTION_MODULE_AHB_DMA_CH2 = 9,
/* AXI_DMA by channel */
SLEEP_RETENTION_MODULE_AXI_DMA_CH0 = 16,
SLEEP_RETENTION_MODULE_AXI_DMA_CH1 = 17,
SLEEP_RETENTION_MODULE_AXI_DMA_CH2 = 18,
SLEEP_RETENTION_MODULE_AXI_DMA_CH0 = 10,
SLEEP_RETENTION_MODULE_AXI_DMA_CH1 = 11,
SLEEP_RETENTION_MODULE_AXI_DMA_CH2 = 12,
/* MISC Peripherals */
SLEEP_RETENTION_MODULE_UART0 = 13,
SLEEP_RETENTION_MODULE_UART1 = 14,
SLEEP_RETENTION_MODULE_UART2 = 15,
SLEEP_RETENTION_MODULE_UART3 = 16,
SLEEP_RETENTION_MODULE_UART4 = 17,
SLEEP_RETENTION_MODULE_RMT0 = 18,
SLEEP_RETENTION_MODULE_I2S0 = 19,
SLEEP_RETENTION_MODULE_I2S1 = 20,
SLEEP_RETENTION_MODULE_I2S2 = 21,
@ -50,6 +49,7 @@ typedef enum periph_retention_module {
SLEEP_RETENTION_MODULE_TWAI0 = 25,
SLEEP_RETENTION_MODULE_TWAI1 = 26,
SLEEP_RETENTION_MODULE_TWAI2 = 27,
SLEEP_RETENTION_MODULE_PARLIO0 = 28,
SLEEP_RETENTION_MODULE_MAX = 31
} periph_retention_module_t;
@ -89,6 +89,7 @@ typedef enum periph_retention_module_bitmap {
SLEEP_RETENTION_MODULE_BM_TWAI0 = BIT(SLEEP_RETENTION_MODULE_TWAI0),
SLEEP_RETENTION_MODULE_BM_TWAI1 = BIT(SLEEP_RETENTION_MODULE_TWAI1),
SLEEP_RETENTION_MODULE_BM_TWAI2 = BIT(SLEEP_RETENTION_MODULE_TWAI2),
SLEEP_RETENTION_MODULE_BM_PARLIO0 = BIT(SLEEP_RETENTION_MODULE_PARLIO0),
SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1
} periph_retention_module_bitmap_t;
@ -114,11 +115,12 @@ typedef enum periph_retention_module_bitmap {
| SLEEP_RETENTION_MODULE_BM_I2S1 \
| SLEEP_RETENTION_MODULE_BM_I2S2 \
| SLEEP_RETENTION_MODULE_BM_ETM0 \
| SLEEP_RETENTION_MODULE_BM_I2C0 \
| SLEEP_RETENTION_MODULE_BM_I2C1 \
| SLEEP_RETENTION_MODULE_BM_TWAI0 \
| SLEEP_RETENTION_MODULE_BM_TWAI1 \
| SLEEP_RETENTION_MODULE_BM_TWAI2 \
| SLEEP_RETENTION_MODULE_BM_I2C0 \
| SLEEP_RETENTION_MODULE_BM_I2C1 \
| SLEEP_RETENTION_MODULE_BM_TWAI0 \
| SLEEP_RETENTION_MODULE_BM_TWAI1 \
| SLEEP_RETENTION_MODULE_BM_TWAI2 \
| SLEEP_RETENTION_MODULE_BM_PARLIO0 \
)
#ifdef __cplusplus

View File

@ -465,6 +465,7 @@
#define SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT 1 /*!< Support output RX clock to a GPIO */
#define SOC_PARLIO_TRANS_BIT_ALIGN 1 /*!< Support bit alignment in transaction */
#define SOC_PARLIO_TX_SIZE_BY_DMA 1 /*!< Transaction length is controlled by DMA instead of indicated by register */
#define SOC_PARLIO_SUPPORT_SLEEP_RETENTION 1 /*!< Support back up registers before sleep */
/*--------------------------- MPI CAPS ---------------------------------------*/
#define SOC_MPI_MEM_BLOCKS_NUM (4)

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -64,3 +64,31 @@ const parlio_signal_conn_t parlio_periph_signals = {
},
},
};
/**
* PARLIO Registers to be saved during sleep retention
* - Tx Configuration registers, e.g.: PARL_IO_TX_DATA_CFG_REG, PARL_IO_TX_GENRL_CFG_REG
* - Rx Configuration registers, e.g.: PARL_IO_RX_MODE_CFG_REG, PARL_IO_RX_DATA_CFG_REG, PARL_IO_RX_GENRL_CFG_REG
* - CLK Configuration registers, e.g.: PARL_IO_RX_CLK_CFG_REG, PARL_IO_TX_CLK_CFG_REG
* - Interrupt enable registers, e.g.: PARL_IO_INT_ENA_REG
*/
#define PARLIO_RETENTION_REGS_CNT 8
#define PARLIO_RETENTION_REGS_BASE (DR_REG_PARL_IO_BASE + 0x0)
static const uint32_t parlio_regs_map[4] = {0x60457, 0x0, 0x0, 0x0};
static const regdma_entries_config_t parlio_regs_retention[] = {
// backup stage: save configuration registers
// restore stage: restore the configuration registers
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_PARLIO_LINK(0x00),
PARLIO_RETENTION_REGS_BASE, PARLIO_RETENTION_REGS_BASE,
PARLIO_RETENTION_REGS_CNT, 0, 0,
parlio_regs_map[0], parlio_regs_map[1],
parlio_regs_map[2], parlio_regs_map[3]),
.owner = ENTRY(0)},
};
const parlio_reg_retention_info_t parlio_reg_retention_info[SOC_PARLIO_GROUPS] = {
[0] = {
.regdma_entry_array = parlio_regs_retention,
.array_size = ARRAY_SIZE(parlio_regs_retention),
.retention_module = SLEEP_RETENTION_MODULE_PARLIO0
},
};

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -13,6 +13,10 @@
#include "soc/parl_io_reg.h"
#include "soc/parl_io_struct.h"
#endif
#include "soc/regdma.h"
#if SOC_PARLIO_SUPPORT_SLEEP_RETENTION
#include "soc/retention_periph_defs.h"
#endif
#ifdef __cplusplus
extern "C" {
@ -39,6 +43,16 @@ typedef struct {
extern const parlio_signal_conn_t parlio_periph_signals;
#if SOC_PARLIO_SUPPORT_SLEEP_RETENTION
typedef struct {
const periph_retention_module_t retention_module;
const regdma_entries_config_t *regdma_entry_array;
uint32_t array_size;
} parlio_reg_retention_info_t;
extern const parlio_reg_retention_info_t parlio_reg_retention_info[SOC_PARLIO_GROUPS];
#endif // SOC_PARLIO_SUPPORT_SLEEP_RETENTION
#endif
#ifdef __cplusplus

View File

@ -57,6 +57,7 @@ extern "C" {
#define REGDMA_ETM_LINK(_pri) ((0x1F << 8) | _pri)
#define REGDMA_TSENS_LINK(_pri) ((0x20 << 8) | _pri)
#define REGDMA_TWAI_LINK(_pri) ((0x21 << 8) | _pri)
#define REGDMA_PARLIO_LINK(_pri) ((0x22 << 8) | _pri)
#define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri)
#define REGDMA_LINK_PRI_SYS_CLK REGDMA_LINK_PRI_0
@ -75,6 +76,7 @@ extern "C" {
#define REGDMA_LINK_PRI_GPTIMER REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_I2C REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_I2S REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_PARLIO REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_UART REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_TEMPERATURE_SENSOR REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_TWAI REGDMA_LINK_PRI_GENERAL_PERIPH

View File

@ -158,6 +158,7 @@ The following peripheral drivers are not aware of DFS yet. Applications need to
:SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs
:SOC_TEMPERATURE_SENSOR_SUPPORT_SLEEP_RETENTION: - Temperature Sensor
:SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs
:SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO
The following peripherals are not yet supported:
@ -173,7 +174,6 @@ The following peripheral drivers are not aware of DFS yet. Applications need to
- MCPWM
- SARADC
- SDIO
- PARL_IO
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.

View File

@ -158,6 +158,7 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
:SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs
:SOC_TEMPERATURE_SENSOR_SUPPORT_SLEEP_RETENTION: - Temperature Sensor
:SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs
:SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO
以下外设尚未支持:
@ -173,7 +174,6 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
- MCPWM
- SARADC
- SDIO
- PARL_IO
对于未支持 Light-sleep 上下文备份的外设,若启用了电源管理功能,应在外设工作时持有 ``ESP_PM_NO_LIGHT_SLEEP`` 锁以避免进入休眠导致外设工作上下文丢失。