mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 17:19:09 -04:00
feat(mcpwm): support sleep retention
This commit is contained in:
parent
c8fa2a1f42
commit
2e44cb9387
@ -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
|
||||
*/
|
||||
@ -22,6 +22,11 @@ typedef struct {
|
||||
int group_id; /*!< Specify from which group to allocate the capture timer */
|
||||
mcpwm_capture_clock_source_t clk_src; /*!< MCPWM capture timer clock source */
|
||||
uint32_t resolution_hz; /*!< Resolution of capture timer */
|
||||
struct {
|
||||
uint32_t allow_pd: 1; /*!< Set to allow power down. When this flag set, the driver will backup/restore the MCPWM registers before/after entering/exist sleep mode.
|
||||
By this approach, the system can power off MCPWM's power domain.
|
||||
This can save power, but at the expense of more RAM being consumed.*/
|
||||
} flags; /*!< Extra configuration flags for timer */
|
||||
} mcpwm_capture_timer_config_t;
|
||||
|
||||
/**
|
||||
|
@ -40,6 +40,9 @@ typedef struct {
|
||||
struct {
|
||||
uint32_t update_period_on_empty: 1; /*!< Whether to update period when timer counts to zero */
|
||||
uint32_t update_period_on_sync: 1; /*!< Whether to update period on sync event */
|
||||
uint32_t allow_pd: 1; /*!< Set to allow power down. When this flag set, the driver will backup/restore the MCPWM registers before/after entering/exist sleep mode.
|
||||
By this approach, the system can power off MCPWM's power domain.
|
||||
This can save power, but at the expense of more RAM being consumed. */
|
||||
} flags; /*!< Extra configuration flags for timer */
|
||||
} mcpwm_timer_config_t;
|
||||
|
||||
|
@ -94,6 +94,10 @@ esp_err_t mcpwm_new_capture_timer(const mcpwm_capture_timer_config_t *config, mc
|
||||
ESP_GOTO_ON_FALSE(config->group_id < SOC_MCPWM_GROUPS && config->group_id >= 0, ESP_ERR_INVALID_ARG,
|
||||
err, TAG, "invalid group ID:%d", config->group_id);
|
||||
|
||||
#if !SOC_MCPWM_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_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
cap_timer = heap_caps_calloc(1, sizeof(mcpwm_cap_timer_t), MCPWM_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(cap_timer, ESP_ERR_NO_MEM, err, TAG, "no mem for capture timer");
|
||||
|
||||
@ -139,6 +143,13 @@ esp_err_t mcpwm_new_capture_timer(const mcpwm_capture_timer_config_t *config, mc
|
||||
cap_timer->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
cap_timer->fsm = MCPWM_CAP_TIMER_FSM_INIT;
|
||||
*ret_cap_timer = cap_timer;
|
||||
|
||||
#if MCPWM_USE_RETENTION_LINK
|
||||
if (config->flags.allow_pd != 0) {
|
||||
mcpwm_create_retention_module(group);
|
||||
}
|
||||
#endif // MCPWM_USE_RETENTION_LINK
|
||||
|
||||
ESP_LOGD(TAG, "new capture timer at %p, in group (%d), resolution %"PRIu32, cap_timer, group_id, cap_timer->resolution_hz);
|
||||
return ESP_OK;
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/mcpwm_ll.h"
|
||||
#include "mcpwm_private.h"
|
||||
#include "esp_private/rtc_clk.h"
|
||||
|
||||
#if SOC_PERIPH_CLK_CTRL_SHARED
|
||||
#define MCPWM_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
|
||||
@ -34,6 +35,10 @@
|
||||
#define MCPWM_RCC_ATOMIC()
|
||||
#endif
|
||||
|
||||
#if MCPWM_USE_RETENTION_LINK
|
||||
static esp_err_t mcpwm_create_sleep_retention_link_cb(void *arg);
|
||||
#endif
|
||||
|
||||
static const char *TAG = "mcpwm";
|
||||
|
||||
typedef struct {
|
||||
@ -59,6 +64,23 @@ mcpwm_group_t *mcpwm_acquire_group_handle(int group_id)
|
||||
group->group_id = group_id;
|
||||
group->intr_priority = -1;
|
||||
group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
#if MCPWM_USE_RETENTION_LINK
|
||||
sleep_retention_module_t module = mcpwm_reg_retention_info[group_id].retention_module;
|
||||
sleep_retention_module_init_param_t init_param = {
|
||||
.cbs = {
|
||||
.create = {
|
||||
.handle = mcpwm_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, &init_param) != ESP_OK) {
|
||||
// even though the sleep retention module init failed, MCPWM 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 // MCPWM_USE_RETENTION_LINK
|
||||
// enable APB to access MCPWM registers
|
||||
MCPWM_RCC_ATOMIC() {
|
||||
mcpwm_ll_enable_bus_clock(group_id, true);
|
||||
@ -116,6 +138,15 @@ void mcpwm_release_group_handle(mcpwm_group_t *group)
|
||||
if (group->pm_lock) {
|
||||
esp_pm_lock_delete(group->pm_lock);
|
||||
}
|
||||
#if MCPWM_USE_RETENTION_LINK
|
||||
const periph_retention_module_t module_id = mcpwm_reg_retention_info[group_id].retention_module;
|
||||
if (sleep_retention_get_created_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 // MCPWM_USE_RETENTION_LINK
|
||||
free(group);
|
||||
}
|
||||
_lock_release(&s_platform.mutex);
|
||||
@ -257,3 +288,29 @@ esp_err_t mcpwm_set_prescale(mcpwm_group_t *group, uint32_t expect_module_resolu
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if MCPWM_USE_RETENTION_LINK
|
||||
static esp_err_t mcpwm_create_sleep_retention_link_cb(void *arg)
|
||||
{
|
||||
mcpwm_group_t *group = (mcpwm_group_t *)arg;
|
||||
int group_id = group->group_id;
|
||||
sleep_retention_module_t module_id = mcpwm_reg_retention_info[group_id].retention_module;
|
||||
esp_err_t err = sleep_retention_entries_create(mcpwm_reg_retention_info[group_id].regdma_entry_array,
|
||||
mcpwm_reg_retention_info[group_id].array_size,
|
||||
REGDMA_LINK_PRI_MCPWM, module_id);
|
||||
return err;
|
||||
}
|
||||
void mcpwm_create_retention_module(mcpwm_group_t *group)
|
||||
{
|
||||
int group_id = group->group_id;
|
||||
sleep_retention_module_t module_id = mcpwm_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, MCPWM 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 // MCPWM_USE_RETENTION_LINK
|
||||
|
@ -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
|
||||
*/
|
||||
@ -17,6 +17,7 @@
|
||||
#include "hal/mcpwm_hal.h"
|
||||
#include "hal/mcpwm_types.h"
|
||||
#include "driver/mcpwm_types.h"
|
||||
#include "esp_private/sleep_retention.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -34,6 +35,9 @@ extern "C" {
|
||||
#define MCPWM_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED)
|
||||
#endif
|
||||
|
||||
// Use retention link only when the target supports sleep retention is enabled
|
||||
#define MCPWM_USE_RETENTION_LINK (SOC_MCPWM_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)
|
||||
|
||||
#define MCPWM_ALLOW_INTR_PRIORITY_MASK ESP_INTR_FLAG_LOWMED
|
||||
|
||||
#define MCPWM_GROUP_CLOCK_DEFAULT_PRESCALE 2
|
||||
@ -259,6 +263,10 @@ int mcpwm_get_intr_priority_flag(mcpwm_group_t *group);
|
||||
esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, soc_module_clk_t clk_src);
|
||||
esp_err_t mcpwm_set_prescale(mcpwm_group_t *group, uint32_t expect_module_resolution_hz, uint32_t module_prescale_max, uint32_t *ret_module_prescale);
|
||||
|
||||
#if MCPWM_USE_RETENTION_LINK
|
||||
void mcpwm_create_retention_module(mcpwm_group_t *group);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -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
|
||||
*/
|
||||
@ -102,6 +102,10 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle
|
||||
}
|
||||
ESP_GOTO_ON_FALSE(peak_ticks > 0 && peak_ticks < MCPWM_LL_MAX_COUNT_VALUE, ESP_ERR_INVALID_ARG, err, TAG, "invalid period ticks");
|
||||
|
||||
#if !SOC_MCPWM_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_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
timer = heap_caps_calloc(1, sizeof(mcpwm_timer_t), MCPWM_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(timer, ESP_ERR_NO_MEM, err, TAG, "no mem for timer");
|
||||
|
||||
@ -143,6 +147,13 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle
|
||||
timer->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
timer->fsm = MCPWM_TIMER_FSM_INIT;
|
||||
*ret_timer = timer;
|
||||
|
||||
#if MCPWM_USE_RETENTION_LINK
|
||||
if (config->flags.allow_pd != 0) {
|
||||
mcpwm_create_retention_module(group);
|
||||
}
|
||||
#endif // MCPWM_USE_RETENTION_LINK
|
||||
|
||||
ESP_LOGD(TAG, "new timer(%d,%d) at %p, resolution:%"PRIu32"Hz, peak:%"PRIu32", count_mod:%c",
|
||||
group_id, timer_id, timer, timer->resolution_hz, timer->peak_ticks, "SUDB"[timer->count_mode]);
|
||||
return ESP_OK;
|
||||
|
@ -17,6 +17,11 @@ if(CONFIG_SOC_ETM_SUPPORTED AND CONFIG_SOC_MCPWM_SUPPORT_ETM)
|
||||
list(APPEND srcs "test_mcpwm_etm.c")
|
||||
endif()
|
||||
|
||||
# TODO: IDF-9928 support ESP32P4
|
||||
if(CONFIG_SOC_LIGHT_SLEEP_SUPPORTED AND CONFIG_PM_ENABLE AND NOT CONFIG_IDF_TARGET_ESP32P4)
|
||||
list(APPEND srcs "test_mcpwm_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}
|
||||
|
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include "unity.h"
|
||||
#include "unity_test_utils.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_clk_tree.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/mcpwm_prelude.h"
|
||||
#include "esp_private/sleep_cpu.h"
|
||||
#include "esp_private/esp_sleep_internal.h"
|
||||
#include "esp_private/sleep_retention.h"
|
||||
#include "esp_private/esp_pmu.h"
|
||||
#include "test_mcpwm_utils.h"
|
||||
|
||||
/**
|
||||
* @brief Test the MCPWM timer can still work after light sleep
|
||||
*
|
||||
* @param allow_pd Whether to allow power down the peripheral in light sleep
|
||||
*/
|
||||
static void test_mcpwm_timer_sleep_retention(bool allow_pd)
|
||||
{
|
||||
const int generator_gpio = TEST_PWMA_GPIO;
|
||||
printf("init a gpio to read generator output\r\n");
|
||||
gpio_config_t gpio_conf = {
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pin_bit_mask = BIT(generator_gpio),
|
||||
};
|
||||
TEST_ESP_OK(gpio_config(&gpio_conf));
|
||||
|
||||
printf("create timer and operator\r\n");
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.group_id = 0,
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 1000000,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
.period_ticks = 1000,
|
||||
.flags.allow_pd = allow_pd,
|
||||
};
|
||||
mcpwm_timer_handle_t timer = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
|
||||
|
||||
mcpwm_operator_config_t oper_config = {
|
||||
.group_id = 0,
|
||||
};
|
||||
mcpwm_oper_handle_t oper = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_operator(&oper_config, &oper));
|
||||
|
||||
printf("connect timer and operator\r\n");
|
||||
TEST_ESP_OK(mcpwm_operator_connect_timer(oper, timer));
|
||||
|
||||
printf("create generator\r\n");
|
||||
mcpwm_generator_config_t gen_config = {
|
||||
.gen_gpio_num = generator_gpio,
|
||||
.flags.io_loop_back = true,
|
||||
};
|
||||
mcpwm_gen_handle_t gen = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_generator(oper, &gen_config, &gen));
|
||||
|
||||
printf("set generator to output high on timer full\r\n");
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gen,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_KEEP),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
|
||||
// go to sleep
|
||||
esp_sleep_context_t sleep_ctx;
|
||||
esp_sleep_set_sleep_context(&sleep_ctx);
|
||||
printf("go to light sleep for 1 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(1 * 1000 * 1000));
|
||||
TEST_ESP_OK(esp_light_sleep_start());
|
||||
|
||||
printf("Waked up! Let's see if MCPWM 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_MCPWM_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("enable timer\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timer));
|
||||
printf("start timer\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
printf("stop timer on full\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_FULL));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
TEST_ASSERT_EQUAL(1, gpio_get_level(generator_gpio));
|
||||
|
||||
printf("delete timer, operator, generator\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timer));
|
||||
TEST_ESP_OK(mcpwm_del_generator(gen));
|
||||
TEST_ESP_OK(mcpwm_del_operator(oper));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timer));
|
||||
TEST_ESP_OK(gpio_reset_pin(generator_gpio));
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_timer_sleep_retention", "[mcpwm]")
|
||||
{
|
||||
test_mcpwm_timer_sleep_retention(false);
|
||||
#if SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
test_mcpwm_timer_sleep_retention(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_MCPWM_CALLBACK_ATTR
|
||||
static bool test_capture_callback(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_data_t *edata, void *user_data)
|
||||
{
|
||||
uint32_t *cap_value = (uint32_t *)user_data;
|
||||
if (edata->cap_edge == MCPWM_CAP_EDGE_NEG) {
|
||||
cap_value[1] = edata->cap_value;
|
||||
} else {
|
||||
cap_value[0] = edata->cap_value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test the MCPWM capture timer can still work after light sleep
|
||||
*
|
||||
* @param allow_pd Whether to allow power down the peripheral in light sleep
|
||||
*/
|
||||
static void test_mcpwm_capture_timer_sleep_retention(bool allow_pd)
|
||||
{
|
||||
const int cap_gpio = TEST_CAP_GPIO;
|
||||
printf("init a gpio to simulate the external capture signal\r\n");
|
||||
gpio_config_t gpio_conf = {
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pin_bit_mask = BIT(cap_gpio),
|
||||
};
|
||||
TEST_ESP_OK(gpio_config(&gpio_conf));
|
||||
// reset the gpio
|
||||
TEST_ESP_OK(gpio_set_level(cap_gpio, 0));
|
||||
// install mcpwm capture timer
|
||||
mcpwm_cap_timer_handle_t cap_timer = NULL;
|
||||
uint32_t clk_src_freq_hz;
|
||||
esp_clk_tree_src_get_freq_hz(MCPWM_CAPTURE_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz);
|
||||
mcpwm_capture_timer_config_t cap_timer_config = {
|
||||
.clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT,
|
||||
.group_id = 0,
|
||||
.resolution_hz = clk_src_freq_hz / 2,
|
||||
.flags.allow_pd = allow_pd,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_capture_timer(&cap_timer_config, &cap_timer));
|
||||
// install mcpwm capture channel
|
||||
mcpwm_cap_channel_handle_t cap_channel;
|
||||
mcpwm_capture_channel_config_t cap_chan_config = {
|
||||
.gpio_num = cap_gpio,
|
||||
.prescale = 1,
|
||||
.flags.pos_edge = true,
|
||||
.flags.neg_edge = true,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_capture_channel(cap_timer, &cap_chan_config, &cap_channel));
|
||||
|
||||
// install callback for capture channel
|
||||
mcpwm_capture_event_callbacks_t cbs = {
|
||||
.on_cap = test_capture_callback,
|
||||
};
|
||||
uint32_t cap_value[2] = {0};
|
||||
TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(cap_channel, &cbs, cap_value));
|
||||
|
||||
// go to sleep
|
||||
esp_sleep_context_t sleep_ctx;
|
||||
esp_sleep_set_sleep_context(&sleep_ctx);
|
||||
printf("go to light sleep for 1 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(1 * 1000 * 1000));
|
||||
TEST_ESP_OK(esp_light_sleep_start());
|
||||
|
||||
printf("Waked up! Let's see if MCPWM 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_MCPWM_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("enable capture\r\n");
|
||||
TEST_ESP_OK(mcpwm_capture_channel_enable(cap_channel));
|
||||
TEST_ESP_OK(mcpwm_capture_timer_enable(cap_timer));
|
||||
|
||||
printf("simulate GPIO capture signal\r\n");
|
||||
TEST_ESP_OK(mcpwm_capture_timer_start(cap_timer));
|
||||
TEST_ESP_OK(gpio_set_level(cap_gpio, 1));
|
||||
esp_rom_delay_us(10 * 1000);
|
||||
TEST_ESP_OK(gpio_set_level(cap_gpio, 0));
|
||||
|
||||
uint32_t clk_src_res;
|
||||
TEST_ESP_OK(mcpwm_capture_timer_get_resolution(cap_timer, &clk_src_res));
|
||||
clk_src_res /= 1000; // convert to kHz
|
||||
uint32_t capture_value = (cap_value[1] - cap_value[0]) * 1000 / clk_src_res;
|
||||
TEST_ASSERT_UINT_WITHIN(1000, 10000, capture_value);
|
||||
|
||||
printf("delete timer, operator, generator\r\n");
|
||||
TEST_ESP_OK(mcpwm_capture_channel_disable(cap_channel));
|
||||
TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel));
|
||||
TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer));
|
||||
TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
|
||||
TEST_ESP_OK(gpio_reset_pin(cap_gpio));
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_capture_timer_sleep_retention", "[mcpwm]")
|
||||
{
|
||||
test_mcpwm_capture_timer_sleep_retention(false);
|
||||
#if SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
test_mcpwm_capture_timer_sleep_retention(true);
|
||||
#endif
|
||||
}
|
@ -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
|
||||
|
@ -1,2 +1,5 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT_INIT=n
|
||||
|
||||
# primitives for checking sleep internal state
|
||||
CONFIG_ESP_SLEEP_DEBUG=y
|
||||
|
@ -887,6 +887,10 @@ config SOC_MCPWM_CAPTURE_CLK_FROM_GROUP
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_PARLIO_GROUPS
|
||||
int
|
||||
default 1
|
||||
|
@ -44,6 +44,7 @@ typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_GPSPI2 = 20,
|
||||
SLEEP_RETENTION_MODULE_LEDC = 21,
|
||||
SLEEP_RETENTION_MODULE_PCNT0 = 22,
|
||||
SLEEP_RETENTION_MODULE_MCPWM0 = 23,
|
||||
|
||||
/* modem module, which includes WiFi, BLE and 802.15.4 */
|
||||
SLEEP_RETENTION_MODULE_WIFI_MAC = 26,
|
||||
@ -91,6 +92,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
SLEEP_RETENTION_MODULE_BM_GPSPI2 = BIT(SLEEP_RETENTION_MODULE_GPSPI2),
|
||||
SLEEP_RETENTION_MODULE_BM_LEDC = BIT(SLEEP_RETENTION_MODULE_LEDC),
|
||||
SLEEP_RETENTION_MODULE_BM_PCNT0 = BIT(SLEEP_RETENTION_MODULE_PCNT0),
|
||||
SLEEP_RETENTION_MODULE_BM_MCPWM0 = BIT(SLEEP_RETENTION_MODULE_MCPWM0),
|
||||
|
||||
SLEEP_RETENTION_MODULE_BM_GDMA_CH0 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH0),
|
||||
SLEEP_RETENTION_MODULE_BM_GDMA_CH1 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH1),
|
||||
@ -118,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_MCPWM0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_NULL \
|
||||
)
|
||||
#ifdef __cplusplus
|
||||
|
@ -358,6 +358,7 @@
|
||||
#define SOC_MCPWM_SUPPORT_ETM 1 ///< Support ETM (Event Task Matrix)
|
||||
#define SOC_MCPWM_SUPPORT_EVENT_COMPARATOR 1 ///< Support event comparator (based on ETM)
|
||||
#define SOC_MCPWM_CAPTURE_CLK_FROM_GROUP 1 ///< Capture timer shares clock with other PWM timers
|
||||
#define SOC_MCPWM_SUPPORT_SLEEP_RETENTION 1 ///< Support back up registers before sleep
|
||||
|
||||
/*------------------------ USB SERIAL JTAG CAPS ------------------------------*/
|
||||
// #define SOC_USB_SERIAL_JTAG_SUPPORT_LIGHT_SLEEP (1) /*!< Support to maintain minimum usb communication during light sleep */ // TODO: IDF-6395
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/mcpwm_periph.h"
|
||||
#include "soc/mcpwm_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
const mcpwm_signal_conn_t mcpwm_periph_signals = {
|
||||
@ -81,3 +82,46 @@ const mcpwm_signal_conn_t mcpwm_periph_signals = {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* MCPWM Registers to be saved during sleep retention
|
||||
* - Clk Configuration registers, e.g.: MCPWM_CLK_CFG_REG
|
||||
* - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG, MCPWM_TIMER0_CFG1_REG
|
||||
* - Operator Configuration registers, e.g.: MCPWM_OPERATOR_TIMERSEL_REG
|
||||
* |- Generator Configuration registers, e.g.: MCPWM_GEN0_STMP_CFG_REG, MCPWM_GEN0_TSTMP_A_REG, MCPWM_GEN0_TSTMP_B_REG, MCPWM_GEN0_CFG0_REG, MCPWM_GEN0_FORCE_REG, MCPWM_GEN0_A_REG, MCPWM_GEN0_B_REG
|
||||
* |- Dead Time Configuration registers, e.g.: MCPWM_DT0_CFG_REG, MCPWM_DT0_FED_CFG_REG, MCPWM_DT0_RED_CFG_REG
|
||||
* |- Carrier Configuration registers, e.g.: MCPWM_CARRIER0_CFG_REG
|
||||
* └- Fault Handle Configuration registers, e.g.: MCPWM_FAULT_DETECT_REG, MCPWM_FH0_CFG0_REG, MCPWM_FH0_CFG1_REG
|
||||
* - Capture Timer Configuration registers, e.g.: MCPWM_CAP_TIMER_CFG_REG, MCPWM_CAP_TIMER_PHASE_REG, MCPWM_CAP_CH0_CFG_REG, MCPWM_CAP_CH1_CFG_REG, MCPWM_CAP_CH2_CFG_REG
|
||||
* - Interrupt enable registers, e.g.: MCPWM_INT_ENA_REG
|
||||
* - ETM Configurations, e.g.: MCPWM_EVT_EN_REG, MCPWM_EVT_EN2_REG, MCPWM_TASK_EN_REG, MCPWM_OP0_TSTMP_E1_REG, MCPWM_OP0_TSTMP_E2_REG, MCPWM_OP1_TSTMP_E1_REG, MCPWM_OP1_TSTMP_E2_REG, MCPWM_OP2_TSTMP_E1_REG, MCPWM_OP2_TSTMP_E2_REG
|
||||
* - Misc Configurations, e.g.: MCPWM_UPDATE_CFG_REG
|
||||
*/
|
||||
#define MCPWM_RETENTION_REGS_CNT 68
|
||||
#define MCPWM_RETENTION_REGS_BASE (DR_REG_MCPWM_BASE + 0x0)
|
||||
static const uint32_t mcpwm_regs_map[4] = {0xefffeeef, 0x7efffbff, 0x1ff18, 0x0};
|
||||
static const regdma_entries_config_t mcpwm_regs_retention[] = {
|
||||
// backup stage: save configuration registers
|
||||
// restore stage: restore the configuration registers
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_MCPWM_LINK(0x00),
|
||||
MCPWM_RETENTION_REGS_BASE, MCPWM_RETENTION_REGS_BASE,
|
||||
MCPWM_RETENTION_REGS_CNT, 0, 0,
|
||||
mcpwm_regs_map[0], mcpwm_regs_map[1],
|
||||
mcpwm_regs_map[2], mcpwm_regs_map[3]),
|
||||
.owner = ENTRY(0) | ENTRY(2) },
|
||||
// restore stage: trigger a forced update of all active registers
|
||||
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x01),
|
||||
MCPWM_UPDATE_CFG_REG(0), MCPWM_GLOBAL_FORCE_UP, MCPWM_GLOBAL_FORCE_UP_M, 1, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2) },
|
||||
[2] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x02),
|
||||
MCPWM_UPDATE_CFG_REG(0), 0, MCPWM_GLOBAL_FORCE_UP_M, 1, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2) },
|
||||
};
|
||||
|
||||
const mcpwm_reg_retention_info_t mcpwm_reg_retention_info[SOC_MCPWM_GROUPS] = {
|
||||
[0] = {
|
||||
.regdma_entry_array = mcpwm_regs_retention,
|
||||
.array_size = ARRAY_SIZE(mcpwm_regs_retention),
|
||||
.retention_module = SLEEP_RETENTION_MODULE_MCPWM0
|
||||
},
|
||||
};
|
||||
|
@ -895,6 +895,10 @@ config SOC_MCPWM_CAPTURE_CLK_FROM_GROUP
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_PARLIO_GROUPS
|
||||
int
|
||||
default 1
|
||||
|
@ -46,6 +46,7 @@ typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_GPSPI2 = 22,
|
||||
SLEEP_RETENTION_MODULE_LEDC = 23,
|
||||
SLEEP_RETENTION_MODULE_PCNT0 = 24,
|
||||
SLEEP_RETENTION_MODULE_MCPWM0 = 25,
|
||||
|
||||
/* Modem module, which includes WiFi, BLE and 802.15.4 */
|
||||
SLEEP_RETENTION_MODULE_WIFI_MAC = 26,
|
||||
@ -89,6 +90,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
SLEEP_RETENTION_MODULE_BM_GPSPI2 = BIT(SLEEP_RETENTION_MODULE_GPSPI2),
|
||||
SLEEP_RETENTION_MODULE_BM_LEDC = BIT(SLEEP_RETENTION_MODULE_LEDC),
|
||||
SLEEP_RETENTION_MODULE_BM_PCNT0 = BIT(SLEEP_RETENTION_MODULE_PCNT0),
|
||||
SLEEP_RETENTION_MODULE_BM_MCPWM0 = BIT(SLEEP_RETENTION_MODULE_MCPWM0),
|
||||
/* 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),
|
||||
@ -120,6 +122,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_MCPWM0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_NULL \
|
||||
)
|
||||
|
||||
|
@ -341,6 +341,7 @@
|
||||
#define SOC_MCPWM_SWSYNC_CAN_PROPAGATE (1) ///< Software sync event can be routed to its output
|
||||
#define SOC_MCPWM_SUPPORT_ETM (1) ///< Support ETM (Event Task Matrix)
|
||||
#define SOC_MCPWM_CAPTURE_CLK_FROM_GROUP (1) ///< Capture timer shares clock with other PWM timers
|
||||
#define SOC_MCPWM_SUPPORT_SLEEP_RETENTION (1) ///< Support back up registers before sleep
|
||||
|
||||
/*------------------------ USB SERIAL JTAG CAPS ------------------------------*/
|
||||
// #define SOC_USB_SERIAL_JTAG_SUPPORT_LIGHT_SLEEP (1) /*!< Support to maintain minimum usb communication during light sleep */ // TODO: IDF-6395
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/mcpwm_periph.h"
|
||||
#include "soc/mcpwm_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
const mcpwm_signal_conn_t mcpwm_periph_signals = {
|
||||
@ -81,3 +82,46 @@ const mcpwm_signal_conn_t mcpwm_periph_signals = {
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* MCPWM Registers to be saved during sleep retention
|
||||
* - Clk Configuration registers, e.g.: MCPWM_CLK_CFG_REG
|
||||
* - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG, MCPWM_TIMER0_CFG1_REG
|
||||
* - Operator Configuration registers, e.g.: MCPWM_OPERATOR_TIMERSEL_REG
|
||||
* |- Generator Configuration registers, e.g.: MCPWM_GEN0_STMP_CFG_REG, MCPWM_GEN0_TSTMP_A_REG, MCPWM_GEN0_TSTMP_B_REG, MCPWM_GEN0_CFG0_REG, MCPWM_GEN0_FORCE_REG, MCPWM_GEN0_A_REG, MCPWM_GEN0_B_REG
|
||||
* |- Dead Time Configuration registers, e.g.: MCPWM_DT0_CFG_REG, MCPWM_DT0_FED_CFG_REG, MCPWM_DT0_RED_CFG_REG
|
||||
* |- Carrier Configuration registers, e.g.: MCPWM_CARRIER0_CFG_REG
|
||||
* └- Fault Handle Configuration registers, e.g.: MCPWM_FAULT_DETECT_REG, MCPWM_FH0_CFG0_REG, MCPWM_FH0_CFG1_REG
|
||||
* - Capture Timer Configuration registers, e.g.: MCPWM_CAP_TIMER_CFG_REG, MCPWM_CAP_TIMER_PHASE_REG, MCPWM_CAP_CH0_CFG_REG, MCPWM_CAP_CH1_CFG_REG, MCPWM_CAP_CH2_CFG_REG
|
||||
* - Interrupt enable registers, e.g.: MCPWM_INT_ENA_REG
|
||||
* - ETM Configurations, e.g.: MCPWM_EVT_EN_REG, MCPWM_TASK_EN_REG
|
||||
* - Misc Configurations, e.g.: MCPWM_UPDATE_CFG_REG
|
||||
*/
|
||||
#define MCPWM_RETENTION_REGS_CNT 61
|
||||
#define MCPWM_RETENTION_REGS_BASE (DR_REG_MCPWM_BASE + 0x0)
|
||||
static const uint32_t mcpwm_regs_map[4] = {0xefffeeef, 0x7efffbff, 0x318, 0x0};
|
||||
static const regdma_entries_config_t mcpwm_regs_retention[] = {
|
||||
// backup stage: save configuration registers
|
||||
// restore stage: restore the configuration registers
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_MCPWM_LINK(0x00),
|
||||
MCPWM_RETENTION_REGS_BASE, MCPWM_RETENTION_REGS_BASE,
|
||||
MCPWM_RETENTION_REGS_CNT, 0, 0,
|
||||
mcpwm_regs_map[0], mcpwm_regs_map[1],
|
||||
mcpwm_regs_map[2], mcpwm_regs_map[3]),
|
||||
.owner = ENTRY(0) | ENTRY(2) },
|
||||
// restore stage: trigger a forced update of all active registers
|
||||
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x01),
|
||||
MCPWM_UPDATE_CFG_REG(0), MCPWM_GLOBAL_FORCE_UP, MCPWM_GLOBAL_FORCE_UP_M, 1, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2) },
|
||||
[2] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x02),
|
||||
MCPWM_UPDATE_CFG_REG(0), 0, MCPWM_GLOBAL_FORCE_UP_M, 1, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2) },
|
||||
};
|
||||
|
||||
const mcpwm_reg_retention_info_t mcpwm_reg_retention_info[SOC_MCPWM_GROUPS] = {
|
||||
[0] = {
|
||||
.regdma_entry_array = mcpwm_regs_retention,
|
||||
.array_size = ARRAY_SIZE(mcpwm_regs_retention),
|
||||
.retention_module = SLEEP_RETENTION_MODULE_MCPWM0
|
||||
},
|
||||
};
|
||||
|
@ -879,6 +879,10 @@ config SOC_MCPWM_CAPTURE_CLK_FROM_GROUP
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_PARLIO_GROUPS
|
||||
int
|
||||
default 1
|
||||
|
@ -46,6 +46,7 @@ typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_GPSPI2 = 22,
|
||||
SLEEP_RETENTION_MODULE_LEDC = 23,
|
||||
SLEEP_RETENTION_MODULE_PCNT0 = 24,
|
||||
SLEEP_RETENTION_MODULE_MCPWM0 = 25,
|
||||
|
||||
/* Modem module, which includes BLE and 802.15.4 */
|
||||
SLEEP_RETENTION_MODULE_BLE_MAC = 28,
|
||||
@ -87,6 +88,7 @@ typedef enum periph_retention_module_bitmap {
|
||||
SLEEP_RETENTION_MODULE_BM_GPSPI2 = BIT(SLEEP_RETENTION_MODULE_GPSPI2),
|
||||
SLEEP_RETENTION_MODULE_BM_LEDC = BIT(SLEEP_RETENTION_MODULE_LEDC),
|
||||
SLEEP_RETENTION_MODULE_BM_PCNT0 = BIT(SLEEP_RETENTION_MODULE_PCNT0),
|
||||
SLEEP_RETENTION_MODULE_BM_MCPWM0 = BIT(SLEEP_RETENTION_MODULE_MCPWM0),
|
||||
/* 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),
|
||||
@ -116,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_MCPWM0 \
|
||||
| SLEEP_RETENTION_MODULE_BM_NULL \
|
||||
)
|
||||
|
||||
|
@ -335,6 +335,7 @@
|
||||
#define SOC_MCPWM_SWSYNC_CAN_PROPAGATE (1) ///< Software sync event can be routed to its output
|
||||
#define SOC_MCPWM_SUPPORT_ETM (1) ///< Support ETM (Event Task Matrix)
|
||||
#define SOC_MCPWM_CAPTURE_CLK_FROM_GROUP (1) ///< Capture timer shares clock with other PWM timers
|
||||
#define SOC_MCPWM_SUPPORT_SLEEP_RETENTION (1) ///< Support back up registers before sleep
|
||||
|
||||
/*------------------------ USB SERIAL JTAG CAPS ------------------------------*/
|
||||
// #define SOC_USB_SERIAL_JTAG_SUPPORT_LIGHT_SLEEP (1) /*!< Support to maintain minimum usb communication during light sleep */ // TODO: IDF-6395
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/mcpwm_periph.h"
|
||||
#include "soc/mcpwm_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
const mcpwm_signal_conn_t mcpwm_periph_signals = {
|
||||
@ -81,3 +82,46 @@ const mcpwm_signal_conn_t mcpwm_periph_signals = {
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* MCPWM Registers to be saved during sleep retention
|
||||
* - Clk Configuration registers, e.g.: MCPWM_CLK_CFG_REG
|
||||
* - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG, MCPWM_TIMER0_CFG1_REG
|
||||
* - Operator Configuration registers, e.g.: MCPWM_OPERATOR_TIMERSEL_REG
|
||||
* |- Generator Configuration registers, e.g.: MCPWM_GEN0_STMP_CFG_REG, MCPWM_GEN0_TSTMP_A_REG, MCPWM_GEN0_TSTMP_B_REG, MCPWM_GEN0_CFG0_REG, MCPWM_GEN0_FORCE_REG, MCPWM_GEN0_A_REG, MCPWM_GEN0_B_REG
|
||||
* |- Dead Time Configuration registers, e.g.: MCPWM_DT0_CFG_REG, MCPWM_DT0_FED_CFG_REG, MCPWM_DT0_RED_CFG_REG
|
||||
* |- Carrier Configuration registers, e.g.: MCPWM_CARRIER0_CFG_REG
|
||||
* └- Fault Handle Configuration registers, e.g.: MCPWM_FAULT_DETECT_REG, MCPWM_FH0_CFG0_REG, MCPWM_FH0_CFG1_REG
|
||||
* - Capture Timer Configuration registers, e.g.: MCPWM_CAP_TIMER_CFG_REG, MCPWM_CAP_TIMER_PHASE_REG, MCPWM_CAP_CH0_CFG_REG, MCPWM_CAP_CH1_CFG_REG, MCPWM_CAP_CH2_CFG_REG
|
||||
* - Interrupt enable registers, e.g.: MCPWM_INT_ENA_REG
|
||||
* - ETM Configurations, e.g.: MCPWM_EVT_EN_REG, MCPWM_TASK_EN_REG
|
||||
* - Misc Configurations, e.g.: MCPWM_UPDATE_CFG_REG
|
||||
*/
|
||||
#define MCPWM_RETENTION_REGS_CNT 61
|
||||
#define MCPWM_RETENTION_REGS_BASE (DR_REG_MCPWM_BASE + 0x0)
|
||||
static const uint32_t mcpwm_regs_map[4] = {0xefffeeef, 0x7efffbff, 0x318, 0x0};
|
||||
static const regdma_entries_config_t mcpwm_regs_retention[] = {
|
||||
// backup stage: save configuration registers
|
||||
// restore stage: restore the configuration registers
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_MCPWM_LINK(0x00),
|
||||
MCPWM_RETENTION_REGS_BASE, MCPWM_RETENTION_REGS_BASE,
|
||||
MCPWM_RETENTION_REGS_CNT, 0, 0,
|
||||
mcpwm_regs_map[0], mcpwm_regs_map[1],
|
||||
mcpwm_regs_map[2], mcpwm_regs_map[3]),
|
||||
.owner = ENTRY(0) | ENTRY(2) },
|
||||
// restore stage: trigger a forced update of all active registers
|
||||
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x01),
|
||||
MCPWM_UPDATE_CFG_REG, MCPWM_GLOBAL_FORCE_UP, MCPWM_GLOBAL_FORCE_UP_M, 1, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2) },
|
||||
[2] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x02),
|
||||
MCPWM_UPDATE_CFG_REG, 0, MCPWM_GLOBAL_FORCE_UP_M, 1, 0),
|
||||
.owner = ENTRY(0) | ENTRY(2) },
|
||||
};
|
||||
|
||||
const mcpwm_reg_retention_info_t mcpwm_reg_retention_info[SOC_MCPWM_GROUPS] = {
|
||||
[0] = {
|
||||
.regdma_entry_array = mcpwm_regs_retention,
|
||||
.array_size = ARRAY_SIZE(mcpwm_regs_retention),
|
||||
.retention_module = SLEEP_RETENTION_MODULE_MCPWM0
|
||||
},
|
||||
};
|
||||
|
@ -454,6 +454,7 @@
|
||||
#define SOC_MCPWM_SUPPORT_ETM (1) ///< Support ETM (Event Task Matrix)
|
||||
#define SOC_MCPWM_SUPPORT_EVENT_COMPARATOR (1) ///< Support event comparator (based on ETM)
|
||||
#define SOC_MCPWM_CAPTURE_CLK_FROM_GROUP (1) ///< Capture timer shares clock with other PWM timers
|
||||
// #define SOC_MCPWM_SUPPORT_SLEEP_RETENTION (1) // TODO: IDF-9928 Waiting for expansion of module ID ///< Support back up registers before sleep
|
||||
|
||||
/*-------------------------- USB CAPS ----------------------------------------*/
|
||||
// USB Serial JTAG Caps
|
||||
|
@ -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
|
||||
*/
|
||||
@ -150,3 +150,58 @@ const mcpwm_signal_conn_t mcpwm_periph_signals = {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
/**
|
||||
* MCPWM Registers to be saved during sleep retention
|
||||
* - Clk Configuration registers, e.g.: MCPWM_CLK_CFG_REG
|
||||
* - Timer Configuration registers, e.g.: MCPWM_TIMER_SYNCI_CFG_REG, MCPWM_TIMER0_CFG0_REG, MCPWM_TIMER0_CFG1_REG, MCPWM_TIMER0_CFG1_REG
|
||||
* - Operator Configuration registers, e.g.: MCPWM_OPERATOR_TIMERSEL_REG
|
||||
* |- Generator Configuration registers, e.g.: MCPWM_GEN0_STMP_CFG_REG, MCPWM_GEN0_TSTMP_A_REG, MCPWM_GEN0_TSTMP_B_REG, MCPWM_GEN0_CFG0_REG, MCPWM_GEN0_FORCE_REG, MCPWM_GEN0_A_REG, MCPWM_GEN0_B_REG
|
||||
* |- Dead Time Configuration registers, e.g.: MCPWM_DT0_CFG_REG, MCPWM_DT0_FED_CFG_REG, MCPWM_DT0_RED_CFG_REG
|
||||
* |- Carrier Configuration registers, e.g.: MCPWM_CARRIER0_CFG_REG
|
||||
* └- Fault Handle Configuration registers, e.g.: MCPWM_FAULT_DETECT_REG, MCPWM_FH0_CFG0_REG, MCPWM_FH0_CFG1_REG
|
||||
* - Capture Timer Configuration registers, e.g.: MCPWM_CAP_TIMER_CFG_REG, MCPWM_CAP_TIMER_PHASE_REG, MCPWM_CAP_CH0_CFG_REG, MCPWM_CAP_CH1_CFG_REG, MCPWM_CAP_CH2_CFG_REG
|
||||
* - Interrupt enable registers, e.g.: MCPWM_INT_ENA_REG
|
||||
* - ETM Configurations, e.g.: MCPWM_EVT_EN_REG, MCPWM_TASK_EN_REG
|
||||
* - Misc Configurations, e.g.: MCPWM_UPDATE_CFG_REG
|
||||
*/
|
||||
#define MCPWM_RETENTION_REGS_CNT 68
|
||||
#define MCPWM_RETENTION_REGS_BASE(i) REG_MCPWM_BASE(i)
|
||||
static const uint32_t mcpwm_regs_map[4] = {0xefffeeef, 0x7efffbff, 0x1ff18, 0x0};
|
||||
#define MCPWM_SLEEP_RETENTION_ENTRIES(mcpwm_port) { \
|
||||
/* backup stage: save configuration registers \
|
||||
restore stage: restore the configuration registers */ \
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \
|
||||
REGDMA_MCPWM_LINK(0x00), \
|
||||
MCPWM_RETENTION_REGS_BASE(mcpwm_port), \
|
||||
MCPWM_RETENTION_REGS_BASE(mcpwm_port), \
|
||||
MCPWM_RETENTION_REGS_CNT, 0, 0, \
|
||||
mcpwm_regs_map[0], mcpwm_regs_map[1], \
|
||||
mcpwm_regs_map[2], mcpwm_regs_map[3]), \
|
||||
.owner = ENTRY(0)}, \
|
||||
/* restore stage: trigger a forced update of all active registers*/ \
|
||||
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x01), \
|
||||
MCPWM_UPDATE_CFG_REG(mcpwm_port), MCPWM_GLOBAL_FORCE_UP, MCPWM_GLOBAL_FORCE_UP_M, 1, 0), \
|
||||
.owner = ENTRY(0) }, \
|
||||
[2] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_MCPWM_LINK(0x02), \
|
||||
MCPWM_UPDATE_CFG_REG(mcpwm_port), 0, MCPWM_GLOBAL_FORCE_UP_M, 1, 0), \
|
||||
.owner = ENTRY(0) }, \
|
||||
};
|
||||
|
||||
static const regdma_entries_config_t mcpwm0_regs_retention[] = MCPWM_SLEEP_RETENTION_ENTRIES(0);
|
||||
static const regdma_entries_config_t mcpwm1_regs_retention[] = MCPWM_SLEEP_RETENTION_ENTRIES(1);
|
||||
|
||||
const mcpwm_reg_retention_info_t mcpwm_reg_retention_info[SOC_MCPWM_GROUPS] = {
|
||||
[0] = {
|
||||
.regdma_entry_array = mcpwm0_regs_retention,
|
||||
.array_size = ARRAY_SIZE(mcpwm0_regs_retention),
|
||||
.retention_module = SLEEP_RETENTION_MODULE_MCPWM0
|
||||
},
|
||||
[1] = {
|
||||
.regdma_entry_array = mcpwm1_regs_retention,
|
||||
.array_size = ARRAY_SIZE(mcpwm1_regs_retention),
|
||||
.retention_module = SLEEP_RETENTION_MODULE_MCPWM1
|
||||
},
|
||||
};
|
||||
#endif //SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -9,6 +9,10 @@
|
||||
#include <stdint.h>
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "soc/regdma.h"
|
||||
#if SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
#include "soc/retention_periph_defs.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -37,6 +41,17 @@ typedef struct {
|
||||
} mcpwm_signal_conn_t;
|
||||
|
||||
extern const mcpwm_signal_conn_t mcpwm_periph_signals;
|
||||
|
||||
#if SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
typedef struct {
|
||||
const regdma_entries_config_t *regdma_entry_array;
|
||||
uint32_t array_size;
|
||||
const periph_retention_module_t retention_module;
|
||||
} mcpwm_reg_retention_info_t;
|
||||
|
||||
extern const mcpwm_reg_retention_info_t mcpwm_reg_retention_info[SOC_MCPWM_GROUPS];
|
||||
#endif // SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
#endif // SOC_MCPWM_SUPPORTED
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -61,6 +61,7 @@ extern "C" {
|
||||
#define REGDMA_GPSPI_LINK(_pri) ((0x23 << 8) | _pri)
|
||||
#define REGDMA_LEDC_LINK(_pri) ((0x24 << 8) | _pri)
|
||||
#define REGDMA_PCNT_LINK(_pri) ((0x25 << 8) | _pri)
|
||||
#define REGDMA_MCPWM_LINK(_pri) ((0x26 << 8) | _pri)
|
||||
#define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri)
|
||||
|
||||
#define REGDMA_LINK_PRI_SYS_CLK REGDMA_LINK_PRI_0
|
||||
@ -86,6 +87,7 @@ extern "C" {
|
||||
#define REGDMA_LINK_PRI_TWAI REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
#define REGDMA_LINK_PRI_GPSPI REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
#define REGDMA_LINK_PRI_LEDC REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
#define REGDMA_LINK_PRI_MCPWM REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
|
||||
typedef enum {
|
||||
REGDMA_LINK_PRI_0 = 0,
|
||||
|
@ -976,6 +976,11 @@ However, the driver can prevent the system from going into Light-sleep by acquir
|
||||
|
||||
Likewise, whenever the driver creates an MCPWM capture timer instance, the driver guarantees that the power management lock is acquired when enabling the timer by :cpp:func:`mcpwm_capture_timer_enable`. And releases the lock in :cpp:func:`mcpwm_capture_timer_disable`.
|
||||
|
||||
.. only:: SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
{IDF_TARGET_NAME} supports to retain the MCPWM register context before entering **Light-sleep** and restore them after woke up. Which means you don't have to re-init the MCPWM driver after the **Light-sleep**.
|
||||
|
||||
This feature can be enabled by setting the flag :cpp:member:`mcpwm_timer_config_t::allow_pd` or :cpp:member:`mcpwm_capture_timer_config_t::allow_pd`. It will allow the system to power down the MCPWM in Light-sleep, meanwhile save the MCPWM register context. It can help to save more power consumption with some extra cost of the memory.
|
||||
|
||||
.. _mcpwm-iram-safe:
|
||||
|
||||
|
@ -156,6 +156,7 @@ The following peripheral drivers are not aware of DFS yet. Applications need to
|
||||
:SOC_LEDC_SUPPORT_SLEEP_RETENTION: - LEDC
|
||||
:SOC_I2C_SUPPORT_SLEEP_RETENTION: - I2C
|
||||
:SOC_I2S_SUPPORT_SLEEP_RETENTION: - I2S
|
||||
:SOC_MCPWM_SUPPORT_SLEEP_RETENTION: - MCPWM
|
||||
:SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs
|
||||
:SOC_TEMPERATURE_SENSOR_SUPPORT_SLEEP_RETENTION: - Temperature Sensor
|
||||
:SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs
|
||||
@ -177,7 +178,6 @@ The following peripheral drivers are not aware of DFS yet. Applications need to
|
||||
- Crypto: AES/ECC/HMAC/RSA/SHA/DS/XTA_AES/ECDSA
|
||||
- PCNT
|
||||
- USB-Serial-JTAG
|
||||
- MCPWM
|
||||
- SARADC
|
||||
|
||||
.. note::
|
||||
|
@ -976,6 +976,11 @@ MCPWM 捕获通道支持在信号上检测到有效边沿时发送通知。须
|
||||
|
||||
同理,每当驱动创建 MCPWM 捕获定时器实例时,都会在通过 :cpp:func:`mcpwm_capture_timer_enable` 启用定时器时获取电源管理锁,并在调用 :cpp:func:`mcpwm_capture_timer_disable` 时释放锁。
|
||||
|
||||
.. only:: SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
{IDF_TARGET_NAME} 支持在进入 **Light-sleep** 之前保留 MCPWM 寄存器中的内容,并在唤醒后恢复。也就是说程序不需要在 **Light-sleep** 唤醒后重新配置 MCPWM。
|
||||
|
||||
该特性可以通过置位配置中的 :cpp:member:`mcpwm_timer_config_t::allow_pd` 或 :cpp:member:`mcpwm_capture_timer_config_t::allow_pd` 标志位启用。启用后驱动允许系统在 Light-sleep 时对 MCPWM 掉电,同时保存 MCPWM 的寄存器内容。它可以帮助降低 Light-sleep 时的功耗,但需要花费一些额外的存储来保存寄存器的配置。
|
||||
|
||||
.. _mcpwm-iram-safe:
|
||||
|
||||
|
@ -156,6 +156,7 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
|
||||
:SOC_I2C_SUPPORT_SLEEP_RETENTION: - I2C
|
||||
:SOC_I2S_SUPPORT_SLEEP_RETENTION: - I2S
|
||||
:SOC_ETM_SUPPORT_SLEEP_RETENTION: - ETM
|
||||
:SOC_MCPWM_SUPPORT_SLEEP_RETENTION: - MCPWM
|
||||
:SOC_UART_SUPPORT_SLEEP_RETENTION: - All UARTs
|
||||
:SOC_TEMPERATURE_SENSOR_SUPPORT_SLEEP_RETENTION: - Temperature Sensor
|
||||
:SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs
|
||||
@ -177,7 +178,6 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
|
||||
- Crypto: AES/ECC/HMAC/RSA/SHA/DS/XTA_AES/ECDSA
|
||||
- PCNT
|
||||
- USB-Serial-JTAG
|
||||
- MCPWM
|
||||
- SARADC
|
||||
|
||||
.. note::
|
||||
|
Loading…
x
Reference in New Issue
Block a user