Skip to content

Commit e6230e4

Browse files
committed
Merge branch 'feat/support_tg_retention_v5.3' into 'release/v5.3'
change(esp_hw_support): do TG WDT/Timer retention by needs (v5.3) See merge request espressif/esp-idf!31486
2 parents 9ddf014 + 2ab144d commit e6230e4

File tree

48 files changed

+973
-249
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+973
-249
lines changed

components/driver/i2c/i2c.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ static void i2c_hw_enable(i2c_port_t i2c_num)
280280
static esp_err_t i2c_sleep_retention_init(void *arg)
281281
{
282282
i2c_port_t i2c_num = *(i2c_port_t *)arg;
283-
esp_err_t ret = sleep_retention_entries_create(i2c_regs_retention[i2c_num].link_list, i2c_regs_retention[i2c_num].link_num, REGDMA_LINK_PRI_7, I2C_SLEEP_RETENTION_MODULE(i2c_num));
283+
esp_err_t ret = sleep_retention_entries_create(i2c_regs_retention[i2c_num].link_list, i2c_regs_retention[i2c_num].link_num, REGDMA_LINK_PRI_I2C, I2C_SLEEP_RETENTION_MODULE(i2c_num));
284284
ESP_RETURN_ON_ERROR(ret, I2C_TAG, "failed to allocate mem for sleep retention");
285285
return ret;
286286
}

components/esp_driver_gptimer/include/driver/gptimer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ typedef struct {
2828
if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */
2929
struct {
3030
uint32_t intr_shared: 1; /*!< Set true, the timer interrupt number can be shared with other peripherals */
31+
uint32_t backup_before_sleep: 1; /*!< If set, the driver will backup/restore the GPTimer registers before/after entering/exist sleep mode.
32+
By this approach, the system can power off GPTimer's power domain.
33+
This can save power, but at the expense of more RAM being consumed */
3134
} flags; /*!< GPTimer config flags*/
3235
} gptimer_config_t;
3336

components/esp_driver_gptimer/src/gptimer.c

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -30,6 +30,10 @@
3030
#include "esp_clk_tree.h"
3131
#include "gptimer_priv.h"
3232

33+
#if GPTIMER_USE_RETENTION_LINK
34+
#include "esp_private/sleep_retention.h"
35+
#endif
36+
3337
static const char *TAG = "gptimer";
3438

3539
#if SOC_PERIPH_CLK_CTRL_SHARED
@@ -52,6 +56,37 @@ static void gptimer_release_group_handle(gptimer_group_t *group);
5256
static esp_err_t gptimer_select_periph_clock(gptimer_t *timer, gptimer_clock_source_t src_clk, uint32_t resolution_hz);
5357
static void gptimer_default_isr(void *args);
5458

59+
#if GPTIMER_USE_RETENTION_LINK
60+
static esp_err_t sleep_tg_timer_retention_link_cb(void *arg)
61+
{
62+
uint32_t group_id = *(uint32_t *)arg;
63+
esp_err_t err = sleep_retention_entries_create(tg_timer_regs_retention[group_id].link_list,
64+
tg_timer_regs_retention[group_id].link_num,
65+
REGDMA_LINK_PRI_6,
66+
(group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_TIMER : SLEEP_RETENTION_MODULE_TG1_TIMER);
67+
if (err == ESP_OK) {
68+
ESP_LOGD(TAG, "Timer group %ld retention initialization", group_id);
69+
}
70+
ESP_RETURN_ON_ERROR(err, TAG, "Failed to create sleep retention linked list for timer group %ld", group_id);
71+
return err;
72+
}
73+
74+
static void gptimer_create_retention_module(gptimer_group_t *group)
75+
{
76+
_lock_acquire(&s_platform.mutex);
77+
int group_id = group->group_id;
78+
if ((group->sleep_retention_initialized == true) && (group->retention_link_created == false)) {
79+
esp_err_t err = sleep_retention_module_allocate((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_TIMER : SLEEP_RETENTION_MODULE_TG1_TIMER);
80+
if (err != ESP_OK) {
81+
ESP_LOGW(TAG, "Failed to allocate sleep retention linked list for timer group %d retention, power domain can't turn off", group_id);
82+
} else {
83+
group->retention_link_created = true;
84+
}
85+
}
86+
_lock_release(&s_platform.mutex);
87+
}
88+
#endif
89+
5590
static esp_err_t gptimer_register_to_group(gptimer_t *timer)
5691
{
5792
gptimer_group_t *group = NULL;
@@ -129,6 +164,12 @@ esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *re
129164
int group_id = group->group_id;
130165
int timer_id = timer->timer_id;
131166

167+
#if GPTIMER_USE_RETENTION_LINK
168+
if (config->flags.backup_before_sleep != 0) {
169+
gptimer_create_retention_module(group);
170+
}
171+
#endif // GPTIMER_USE_RETENTION_LINK
172+
132173
// initialize HAL layer
133174
timer_hal_init(&timer->hal, group_id, timer_id);
134175
// select clock source, set clock resolution
@@ -404,7 +445,6 @@ static gptimer_group_t *gptimer_acquire_group_handle(int group_id)
404445
// someone acquired the group handle means we have a new object that refer to this group
405446
s_platform.group_ref_counts[group_id]++;
406447
}
407-
_lock_release(&s_platform.mutex);
408448

409449
if (new_group) {
410450
// !!! HARDWARE SHARED RESOURCE !!!
@@ -417,7 +457,28 @@ static gptimer_group_t *gptimer_acquire_group_handle(int group_id)
417457
}
418458
}
419459
ESP_LOGD(TAG, "new group (%d) @%p", group_id, group);
460+
#if GPTIMER_USE_RETENTION_LINK
461+
if (group->sleep_retention_initialized != true) {
462+
sleep_retention_module_init_param_t init_param = {
463+
.cbs = {
464+
.create = {
465+
.handle = sleep_tg_timer_retention_link_cb,
466+
.arg = &group_id
467+
},
468+
},
469+
.depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM)
470+
};
471+
esp_err_t err = sleep_retention_module_init((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_TIMER : SLEEP_RETENTION_MODULE_TG1_TIMER, &init_param);
472+
473+
if (err == ESP_OK) {
474+
group->sleep_retention_initialized = true;
475+
} else {
476+
ESP_LOGW(TAG, "Failed to allocate sleep retention linked list for timer group %d retention", group_id);
477+
}
478+
}
479+
#endif // GPTIMER_USE_RETENTION_LINK
420480
}
481+
_lock_release(&s_platform.mutex);
421482

422483
return group;
423484
}
@@ -434,7 +495,6 @@ static void gptimer_release_group_handle(gptimer_group_t *group)
434495
do_deinitialize = true;
435496
s_platform.groups[group_id] = NULL;
436497
}
437-
_lock_release(&s_platform.mutex);
438498

439499
if (do_deinitialize) {
440500
// disable bus clock for the timer group
@@ -443,9 +503,18 @@ static void gptimer_release_group_handle(gptimer_group_t *group)
443503
timer_ll_enable_bus_clock(group_id, false);
444504
}
445505
}
506+
#if GPTIMER_USE_RETENTION_LINK
507+
if (group->retention_link_created) {
508+
sleep_retention_module_free((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_TIMER : SLEEP_RETENTION_MODULE_TG1_TIMER);
509+
}
510+
if (group->sleep_retention_initialized) {
511+
sleep_retention_module_deinit((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_TIMER : SLEEP_RETENTION_MODULE_TG1_TIMER);
512+
}
513+
#endif
446514
free(group);
447515
ESP_LOGD(TAG, "del group (%d)", group_id);
448516
}
517+
_lock_release(&s_platform.mutex);
449518
}
450519

451520
static esp_err_t gptimer_select_periph_clock(gptimer_t *timer, gptimer_clock_source_t src_clk, uint32_t resolution_hz)

components/esp_driver_gptimer/src/gptimer_priv.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -39,12 +39,18 @@ extern "C" {
3939

4040
#define GPTIMER_PM_LOCK_NAME_LEN_MAX 16
4141

42+
#define GPTIMER_USE_RETENTION_LINK (SOC_TIMER_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)
43+
4244
typedef struct gptimer_t gptimer_t;
4345

4446
typedef struct gptimer_group_t {
4547
int group_id;
4648
portMUX_TYPE spinlock; // to protect per-group register level concurrent access
4749
gptimer_t *timers[SOC_TIMER_GROUP_TIMERS_PER_GROUP];
50+
#if GPTIMER_USE_RETENTION_LINK
51+
bool sleep_retention_initialized; // mark if the retention link is initialized
52+
bool retention_link_created; // mark if the retention link is created
53+
#endif
4854
} gptimer_group_t;
4955

5056
typedef enum {

components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer.c

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -13,6 +13,15 @@
1313
#include "soc/soc_caps.h"
1414
#include "esp_attr.h"
1515

16+
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION
17+
#include "esp_random.h"
18+
#include "esp_rom_uart.h"
19+
#include "esp_sleep.h"
20+
#include "esp_private/esp_sleep_internal.h"
21+
#include "esp_private/sleep_cpu.h"
22+
#include "esp_private/esp_pmu.h"
23+
#endif
24+
1625
#if CONFIG_GPTIMER_ISR_IRAM_SAFE
1726
#define TEST_ALARM_CALLBACK_ATTR IRAM_ATTR
1827
#else
@@ -596,3 +605,82 @@ TEST_CASE("gptimer_trig_alarm_with_old_count", "[gptimer]")
596605
TEST_ESP_OK(gptimer_disable(timer));
597606
TEST_ESP_OK(gptimer_del_timer(timer));
598607
}
608+
609+
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION
610+
static gptimer_handle_t timers[SOC_TIMER_GROUP_TOTAL_TIMERS];
611+
static uint32_t timer_resolution_hz[SOC_TIMER_GROUP_TOTAL_TIMERS];
612+
613+
static void test_gptimer_retention(gptimer_config_t *timer_config)
614+
{
615+
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
616+
TEST_ESP_OK(gptimer_new_timer(timer_config, &timers[i]));
617+
TEST_ESP_OK(gptimer_get_resolution(timers[i], &timer_resolution_hz[i]));
618+
619+
unsigned long long count_start_value = 0, count_end_value = 0;
620+
621+
// Let gptimer run for a while
622+
TEST_ESP_OK(gptimer_enable(timers[i]));
623+
TEST_ESP_OK(gptimer_start(timers[i]));
624+
vTaskDelay((esp_random() % 500) / portTICK_PERIOD_MS);
625+
TEST_ESP_OK(gptimer_stop(timers[i]));
626+
TEST_ESP_OK(gptimer_disable(timers[i]));
627+
TEST_ESP_OK(gptimer_get_raw_count(timers[i], &count_start_value));
628+
629+
esp_sleep_context_t sleep_ctx;
630+
esp_sleep_set_sleep_context(&sleep_ctx);
631+
TEST_ESP_OK(sleep_cpu_configure(true));
632+
esp_rom_output_tx_wait_idle(0);
633+
esp_sleep_enable_timer_wakeup(50 * 1000);
634+
esp_light_sleep_start();
635+
636+
if (timer_config->flags.backup_before_sleep) {
637+
TEST_ASSERT_EQUAL(PMU_SLEEP_PD_TOP, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP);
638+
} else {
639+
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP);
640+
}
641+
642+
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
643+
644+
TEST_ESP_OK(gptimer_enable(timers[i]));
645+
TEST_ESP_OK(gptimer_start(timers[i]));
646+
647+
uint32_t random_time_ms = 500 + esp_random() % 2000;
648+
vTaskDelay(random_time_ms / portTICK_PERIOD_MS);
649+
TEST_ESP_OK(gptimer_get_raw_count(timers[i], &count_end_value));
650+
651+
// Error tolerance is 2%
652+
TEST_ASSERT_UINT_WITHIN(random_time_ms / 50, random_time_ms, 1000 * (count_end_value - count_start_value) / (unsigned long long)timer_resolution_hz[i]);
653+
654+
TEST_ESP_OK(gptimer_stop(timers[i]));
655+
TEST_ESP_OK(gptimer_disable(timers[i]));
656+
TEST_ESP_OK(gptimer_del_timer(timers[i]));
657+
TEST_ESP_OK(sleep_cpu_configure(false));
658+
}
659+
}
660+
661+
TEST_CASE("gptimer context kept after peripheral powerdown lightsleep with backup_before_sleep enable", "[gptimer]")
662+
{
663+
printf("install gptimer driver\r\n");
664+
gptimer_config_t timer_config = {
665+
.resolution_hz = 10 * 1000, // 10KHz, 1 tick = 0.1ms
666+
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
667+
.direction = GPTIMER_COUNT_UP,
668+
.flags.backup_before_sleep = true
669+
};
670+
671+
test_gptimer_retention(&timer_config);
672+
}
673+
674+
TEST_CASE("gptimer context kept after peripheral powerdown lightsleep with backup_before_sleep disable", "[gptimer]")
675+
{
676+
printf("install gptimer driver\r\n");
677+
gptimer_config_t timer_config = {
678+
.resolution_hz = 10 * 1000, // 10KHz, 1 tick = 0.1ms
679+
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
680+
.direction = GPTIMER_COUNT_UP,
681+
.flags.backup_before_sleep = false
682+
};
683+
684+
test_gptimer_retention(&timer_config);
685+
}
686+
#endif

components/esp_driver_gptimer/test_apps/gptimer/sdkconfig.ci.release

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ CONFIG_PM_DFS_INIT_AUTO=y
44
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
55
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
66
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
7+
# For TASK WDT timer PD_TOP sleep retention test
8+
CONFIG_ESP_SLEEP_DEBUG=y
9+
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y

components/esp_driver_i2c/i2c_common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ static esp_err_t s_i2c_sleep_retention_init(void *arg)
5252
{
5353
i2c_bus_t *bus = (i2c_bus_t *)arg;
5454
i2c_port_num_t port_num = bus->port_num;
55-
esp_err_t ret = sleep_retention_entries_create(i2c_regs_retention[port_num].link_list, i2c_regs_retention[port_num].link_num, REGDMA_LINK_PRI_7, I2C_SLEEP_RETENTION_MODULE(port_num));
55+
esp_err_t ret = sleep_retention_entries_create(i2c_regs_retention[port_num].link_list, i2c_regs_retention[port_num].link_num, REGDMA_LINK_PRI_I2C, I2C_SLEEP_RETENTION_MODULE(port_num));
5656
ESP_RETURN_ON_ERROR(ret, TAG, "failed to allocate mem for sleep retention");
5757
return ret;
5858
}

components/esp_hw_support/include/esp_private/esp_regdma.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ extern "C" {
2222
#if SOC_PAU_SUPPORTED
2323
#include "hal/pau_types.h"
2424

25-
#define REGDMA_LINK_DBG 0 /* Enable REGDMA link info dump apis*/
26-
2725
/**
2826
* @brief Create a REGDMA continuous type linked list node without retention buffer and the retention buffer is passed in by the caller
2927
* @param backup Register address to be backed up by REGDMA

components/esp_hw_support/lowpower/cpu_retention/port/esp32c3/sleep_cpu.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "esp_check.h"
1515
#include "esp_sleep.h"
1616
#include "esp_log.h"
17-
#include "esp_crc.h"
1817
#include "freertos/FreeRTOS.h"
1918
#include "freertos/task.h"
2019
#include "esp_heap_caps.h"

components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#include "esp_check.h"
1515
#include "esp_sleep.h"
1616
#include "esp_log.h"
17-
#include "esp_crc.h"
17+
#include "esp_rom_crc.h"
1818
#include "freertos/FreeRTOS.h"
1919
#include "freertos/task.h"
2020
#include "esp_heap_caps.h"
@@ -391,12 +391,12 @@ static IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame_t *
391391
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
392392
static IRAM_ATTR void update_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr)
393393
{
394-
*(frame_crc_ptr) = esp_crc32_le(0, (void *)frame_ptr, frame_check_size);
394+
*(frame_crc_ptr) = esp_rom_crc32_le(0, (void *)frame_ptr, frame_check_size);
395395
}
396396

397397
static IRAM_ATTR void validate_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr)
398398
{
399-
if(*(frame_crc_ptr) != esp_crc32_le(0, (void *)(frame_ptr), frame_check_size)){
399+
if(*(frame_crc_ptr) != esp_rom_crc32_le(0, (void *)(frame_ptr), frame_check_size)){
400400
// resume uarts
401401
for (int i = 0; i < SOC_UART_NUM; ++i) {
402402
if (!uart_ll_is_enabled(i)) {

0 commit comments

Comments
 (0)