fix(ledc): fix undesired module reset when acquiring new speed mode on ESP32

Introduced in 885e32d4f0
This commit is contained in:
Song Ruo Jing
2026-04-09 22:31:04 +08:00
parent 9f50fb8543
commit e79d9f2567
+34 -23
View File
@@ -399,44 +399,55 @@ esp_err_t ledc_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags,
static bool ledc_speed_mode_ctx_create(ledc_mode_t speed_mode)
{
bool new_ctx = false;
bool group_acquired = false;
// Prevent p_ledc_obj malloc concurrently
_lock_acquire(&s_ledc_mutex[speed_mode]);
if (!p_ledc_obj[speed_mode]) {
for (int i = 0; i < LEDC_SPEED_MODE_MAX; i++) {
if (p_ledc_obj[i]) {
group_acquired = true;
break;
}
}
ledc_obj_t *ledc_new_mode_obj = (ledc_obj_t *) heap_caps_calloc(1, sizeof(ledc_obj_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (ledc_new_mode_obj) {
new_ctx = true;
PERIPH_RCC_ATOMIC() {
ledc_ll_enable_bus_clock(0, true);
ledc_ll_reset_register(0);
}
// Enable core clock gating at early stage, some LEDC registers and gamma RAM rely on the LEDC core clock existence
PERIPH_RCC_ATOMIC() {
ledc_ll_enable_clock(0, true);
}
ledc_hal_init(&(ledc_new_mode_obj->ledc_hal), 0);
// initialize some fields
ledc_new_mode_obj->glb_clk = LEDC_SLOW_CLK_UNINIT;
#if SOC_LEDC_HAS_TIMER_SPECIFIC_MUX
memset(ledc_new_mode_obj->timer_specific_clk, LEDC_TIMER_SPECIFIC_CLK_UNINIT, sizeof(ledc_clk_src_t) * LEDC_TIMER_MAX);
#endif
ledc_new_mode_obj->sleep_mode = LEDC_SLEEP_MODE_INVALID;
// if the entire LEDC group is not acquired, do module based initialization
if (!group_acquired) {
PERIPH_RCC_ATOMIC() {
ledc_ll_enable_bus_clock(0, true);
ledc_ll_reset_register(0);
}
// Enable core clock gating at early stage, some LEDC registers and gamma RAM rely on the LEDC core clock existence
PERIPH_RCC_ATOMIC() {
ledc_ll_enable_clock(0, true);
}
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP // for targets that is !SOC_LEDC_SUPPORT_SLEEP_RETENTION, retention module should still be inited to avoid TOP PD
// Initialize sleep retention module for LEDC
sleep_retention_module_t module = ledc_reg_retention_info[0].module_id;
sleep_retention_module_init_param_t init_param = {
.cbs = {
.create = {
.handle = ledc_create_sleep_retention_link_cb,
.arg = NULL,
// Initialize sleep retention module for LEDC
sleep_retention_module_t module = ledc_reg_retention_info[0].module_id;
sleep_retention_module_init_param_t init_param = {
.cbs = {
.create = {
.handle = ledc_create_sleep_retention_link_cb,
.arg = NULL,
},
},
},
.depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM)
};
if (sleep_retention_module_init(module, &init_param) != ESP_OK) {
ESP_LOGW(LEDC_TAG, "init sleep retention failed for ledc, power domain may be turned off during sleep");
}
.depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM)
};
if (sleep_retention_module_init(module, &init_param) != ESP_OK) {
ESP_LOGW(LEDC_TAG, "init sleep retention failed for ledc, power domain may be turned off during sleep");
}
#endif
}
ledc_hal_init(&(ledc_new_mode_obj->ledc_hal), 0);
p_ledc_obj[speed_mode] = ledc_new_mode_obj;
}
}