From da67bbb0a48781da10cedc7e5bdab8efabb21681 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/driver/ledc/ledc.c | 4 ++++ components/hal/include/hal/ledc_hal.h | 11 ++++++++++- components/hal/ledc_hal_iram.c | 15 +++++++++++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/components/driver/ledc/ledc.c b/components/driver/ledc/ledc.c index 81b63cb30c..a85c4dad18 100644 --- a/components/driver/ledc/ledc.c +++ b/components/driver/ledc/ledc.c @@ -212,6 +212,8 @@ int duty_val, ledc_duty_direction_t duty_direction, uint32_t duty_num, uint32_t #if SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED ledc_hal_set_duty_range_wr_addr(&(p_ledc_obj[speed_mode]->ledc_hal), channel, 0); 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; } @@ -1274,6 +1276,8 @@ static esp_err_t _ledc_set_multi_fade(ledc_mode_t speed_mode, ledc_channel_t cha ledc_hal_set_duty_range_wr_addr(&(p_ledc_obj[speed_mode]->ledc_hal), channel, i); } 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 4f8731b1ad..91610ee7eb 100644 --- a/components/hal/include/hal/ledc_hal.h +++ b/components/hal/include/hal/ledc_hal.h @@ -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 */ @@ -386,6 +386,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 ede00c26a5..0ea5f8617d 100644 --- a/components/hal/ledc_hal_iram.c +++ b/components/hal/ledc_hal_iram.c @@ -1,11 +1,11 @@ /* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2025 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 "esp_attr.h" #include "hal/ledc_hal.h" @@ -70,6 +70,17 @@ 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_duty_direction(hal->dev, hal->speed_mode, channel_num, 0); + ledc_ll_set_duty_cycle(hal->dev, hal->speed_mode, channel_num, 0); + ledc_ll_set_duty_scale(hal->dev, hal->speed_mode, channel_num, 0); + ledc_ll_set_duty_num(hal->dev, hal->speed_mode, channel_num, 0); + ledc_ll_set_duty_range_wr_addr(hal->dev, hal->speed_mode, channel_num, i); + } +} #endif //SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED void ledc_hal_get_fade_end_intr_status(ledc_hal_context_t *hal, uint32_t *intr_status)