From b2dbcd7804779455086f9e4e354e5879b58b61d6 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Tue, 31 Dec 2024 21:28:20 +0800 Subject: [PATCH] fix(ledc): left-off gamma ram registers should be cleared Hardware reads in (range_number+1) fade parameter registers, which could cause output waveform error. --- components/esp_driver_ledc/src/ledc.c | 9 ++++++++- components/hal/include/hal/ledc_hal.h | 11 ++++++++++- components/hal/ledc_hal_iram.c | 11 +++++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/components/esp_driver_ledc/src/ledc.c b/components/esp_driver_ledc/src/ledc.c index 3216c154be..31878261e7 100644 --- a/components/esp_driver_ledc/src/ledc.c +++ b/components/esp_driver_ledc/src/ledc.c @@ -279,6 +279,8 @@ static IRAM_ATTR esp_err_t ledc_duty_config(ledc_mode_t speed_mode, ledc_channel ledc_hal_set_fade_param(&(p_ledc_obj[speed_mode]->ledc_hal), channel, 0, duty_direction, duty_cycle, duty_scale, duty_num); #if SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED ledc_hal_set_range_number(&(p_ledc_obj[speed_mode]->ledc_hal), channel, 1); + // Clear left-off LEDC gamma ram registers, random data in ram could cause output waveform error + ledc_hal_clear_left_off_fade_param(&(p_ledc_obj[speed_mode]->ledc_hal), channel, 1); #endif return ESP_OK; } @@ -417,6 +419,10 @@ static bool ledc_speed_mode_ctx_create(ledc_mode_t speed_mode) ledc_ll_enable_bus_clock(true); ledc_ll_enable_reset_reg(false); } + // Enable core clock gating at early stage, some LEDC registers and gamma RAM rely on the LEDC core clock existence + LEDC_FUNC_CLOCK_ATOMIC() { + ledc_ll_enable_clock(LEDC_LL_GET_HW(), true); + } ledc_hal_init(&(ledc_new_mode_obj->ledc_hal), speed_mode); ledc_new_mode_obj->glb_clk = LEDC_SLOW_CLK_UNINIT; #if SOC_LEDC_HAS_TIMER_SPECIFIC_MUX @@ -693,7 +699,6 @@ static esp_err_t ledc_set_timer_div(ledc_mode_t speed_mode, ledc_timer_t timer_n p_ledc_obj[speed_mode]->glb_clk = glb_clk; esp_clk_tree_enable_src((soc_module_clk_t)glb_clk, true); LEDC_FUNC_CLOCK_ATOMIC() { - ledc_ll_enable_clock(p_ledc_obj[speed_mode]->ledc_hal.dev, true); ledc_hal_set_slow_clk_sel(&(p_ledc_obj[speed_mode]->ledc_hal), glb_clk); } } @@ -1630,6 +1635,8 @@ static esp_err_t _ledc_set_multi_fade(ledc_mode_t speed_mode, ledc_channel_t cha ledc_hal_set_fade_param(&(p_ledc_obj[speed_mode]->ledc_hal), channel, i, fade_param.dir, fade_param.cycle_num, fade_param.scale, fade_param.step_num); } ledc_hal_set_range_number(&(p_ledc_obj[speed_mode]->ledc_hal), channel, list_len); + // Clear left-off LEDC gamma ram registers, random data in ram could cause output waveform error + ledc_hal_clear_left_off_fade_param(&(p_ledc_obj[speed_mode]->ledc_hal), channel, list_len); portEXIT_CRITICAL(&ledc_spinlock); // Calculate target duty, and take account for overflow uint32_t target_duty = start_duty; diff --git a/components/hal/include/hal/ledc_hal.h b/components/hal/include/hal/ledc_hal.h index b914cb5778..fe9275ee9b 100644 --- a/components/hal/include/hal/ledc_hal.h +++ b/components/hal/include/hal/ledc_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -365,6 +365,15 @@ void ledc_hal_get_range_number(ledc_hal_context_t *hal, ledc_channel_t channel_n * @return None */ void ledc_hal_get_fade_param(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t range, uint32_t *dir, uint32_t *cycle, uint32_t *scale, uint32_t *step); + +/** + * @brief Clear left-off range fade parameters in LEDC gamma ram + * + * @param hal Context of the HAL layer + * @param channel_num LEDC channel index, select from ledc_channel_t + * @param start_range Start of the range to clear + */ +void ledc_hal_clear_left_off_fade_param(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t start_range); #endif //SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED /** diff --git a/components/hal/ledc_hal_iram.c b/components/hal/ledc_hal_iram.c index 4cff5cfcd7..be3e876567 100644 --- a/components/hal/ledc_hal_iram.c +++ b/components/hal/ledc_hal_iram.c @@ -1,11 +1,11 @@ /* - * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ // The HAL layer for LEDC (common part, in iram) -// make these functions in a seperate file to make sure all LL functions are in the IRAM. +// make these functions in a separate file to make sure all LL functions are in the IRAM. #include "hal/ledc_hal.h" #include "hal/assert.h" @@ -58,6 +58,13 @@ void ledc_hal_get_range_number(ledc_hal_context_t *hal, ledc_channel_t channel_n { ledc_ll_get_range_number(hal->dev, hal->speed_mode, channel_num, range_num); } + +void ledc_hal_clear_left_off_fade_param(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t start_range) +{ + for (int i = start_range; i < SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX; i++) { + ledc_ll_set_fade_param_range(hal->dev, hal->speed_mode, channel_num, i, 0, 0, 0, 0); + } +} #endif //SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED void ledc_hal_get_fade_end_intr_status(ledc_hal_context_t *hal, uint32_t *intr_status)