From 03299962f67f1cb8f562749329f4b8fbf439b08d Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 20 Sep 2023 12:47:21 +0800 Subject: [PATCH] fix(ledc): fix ledc driver 100% duty cycle configuration Update ledc duty cycle value range in doxygen. Fix duty configuration error at 100% duty cycle for ESP32. Improve LEDC API doxygen. Closes https://github.com/espressif/esp-idf/pull/11516 Closes https://github.com/espressif/esp-idf/issues/12593 Closes https://github.com/espressif/esp-idf/issues/12083 --- components/driver/ledc/include/driver/ledc.h | 117 ++++++++++++------ components/driver/ledc/ledc.c | 17 ++- docs/en/api-reference/peripherals/ledc.rst | 8 +- docs/zh_CN/api-reference/peripherals/ledc.rst | 8 +- .../peripherals/ledc/ledc_basic/README.md | 8 +- .../ledc_basic/main/ledc_basic_example_main.c | 8 +- 6 files changed, 113 insertions(+), 53 deletions(-) diff --git a/components/driver/ledc/include/driver/ledc.h b/components/driver/ledc/include/driver/ledc.h index c0e2f14530f..08f7cbb2bde 100644 --- a/components/driver/ledc/include/driver/ledc.h +++ b/components/driver/ledc/include/driver/ledc.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -38,12 +38,12 @@ extern "C" { */ typedef struct { int gpio_num; /*!< the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16 */ - ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode */ + ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode (only exists on esp32) or low-speed mode */ ledc_channel_t channel; /*!< LEDC channel (0 - LEDC_CHANNEL_MAX-1) */ ledc_intr_type_t intr_type; /*!< configure interrupt, Fade interrupt enable or Fade interrupt disable */ ledc_timer_t timer_sel; /*!< Select the timer source of channel (0 - LEDC_TIMER_MAX-1) */ uint32_t duty; /*!< LEDC channel duty, the range of duty setting is [0, (2**duty_resolution)] */ - int hpoint; /*!< LEDC channel hpoint value, the max value is 0xfffff */ + int hpoint; /*!< LEDC channel hpoint value, the range is [0, (2**duty_resolution)-1] */ struct { unsigned int output_invert: 1;/*!< Enable (1) or disable (0) gpio output invert */ } flags; /*!< LEDC flags */ @@ -54,7 +54,7 @@ typedef struct { * @brief Configuration parameters of LEDC Timer timer for ledc_timer_config function */ typedef struct { - ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode */ + ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode (only exists on esp32) or low-speed mode */ ledc_timer_bit_t duty_resolution; /*!< LEDC channel duty resolution */ ledc_timer_t timer_num; /*!< The timer source of channel (0 - LEDC_TIMER_MAX-1) */ uint32_t freq_hz; /*!< LEDC timer frequency (Hz) */ @@ -83,7 +83,7 @@ typedef struct { ledc_cb_event_t event; /**< Event name */ uint32_t speed_mode; /**< Speed mode of the LEDC channel group */ uint32_t channel; /**< LEDC channel (0 - LEDC_CHANNEL_MAX-1) */ - uint32_t duty; /**< LEDC current duty of the channel, the range of duty is [0, (2**duty_resolution) - 1] */ + uint32_t duty; /**< LEDC current duty of the channel, the range of duty is [0, (2**duty_resolution)] */ } ledc_cb_param_t; /** @@ -129,6 +129,7 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t *timer_conf); /** * @brief LEDC update channel parameters + * * @note Call this function to activate the LEDC updated parameters. * After ledc_set_duty, we need to call this function to update the settings. * And the new LEDC parameters don't take effect until the next PWM cycle. @@ -141,7 +142,6 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t *timer_conf); * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error - * */ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel); @@ -204,15 +204,17 @@ uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num); /** * @brief LEDC set duty and hpoint value * Only after calling ledc_update_duty will the duty update. + * * @note ledc_set_duty, ledc_set_duty_with_hpoint and ledc_update_duty are not thread-safe, do not call these functions to * control one LEDC channel in different tasks at the same time. * A thread-safe version of API is ledc_set_duty_and_update * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. + * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t - * @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution) - 1] - * @param hpoint Set the LEDC hpoint value(max: 0xfffff) + * @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)] + * @param hpoint Set the LEDC hpoint value, the range is [0, (2**duty_resolution)-1] * * @return * - ESP_OK Success @@ -225,6 +227,7 @@ esp_err_t ledc_set_duty_with_hpoint(ledc_mode_t speed_mode, ledc_channel_t chann * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t + * * @return * - LEDC_ERR_VAL if parameter error * - Others Current hpoint value of LEDC channel @@ -235,14 +238,16 @@ int ledc_get_hpoint(ledc_mode_t speed_mode, ledc_channel_t channel); * @brief LEDC set duty * This function do not change the hpoint value of this channel. if needed, please call ledc_set_duty_with_hpoint. * only after calling ledc_update_duty will the duty update. + * * @note ledc_set_duty, ledc_set_duty_with_hpoint and ledc_update_duty are not thread-safe, do not call these functions to * control one LEDC channel in different tasks at the same time. * A thread-safe version of API is ledc_set_duty_and_update. * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. + * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t - * @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution) - 1] + * @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)] * * @return * - ESP_OK Success @@ -268,11 +273,13 @@ uint32_t ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel); /** * @brief LEDC set gradient * Set LEDC gradient, After the function calls the ledc_update_duty function, the function can take effect. + * * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. + * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t - * @param duty Set the start of the gradient duty, the range of duty setting is [0, (2**duty_resolution) - 1] + * @param duty Set the start of the gradient duty, the range of duty setting is [0, (2**duty_resolution)] * @param fade_direction Set the direction of the gradient * @param step_num Set the number of the gradient * @param duty_cycle_num Set how many LEDC tick each time the gradient lasts @@ -298,7 +305,8 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t * * @return * - ESP_OK Success - * - ESP_ERR_INVALID_ARG Function pointer error. + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Failed to find available interrupt source */ esp_err_t ledc_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, ledc_isr_handle_t *handle); @@ -308,7 +316,7 @@ esp_err_t ledc_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param timer_sel Timer index (0-3), there are 4 timers in LEDC module * @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source - * @param duty_resolution Resolution of duty setting in number of bits. The range of duty values is [0, (2**duty_resolution)] + * @param duty_resolution Resolution of duty setting in number of bits. The range is [1, SOC_LEDC_TIMER_BIT_WIDTH] * @param clk_src Select LEDC source clock. * * @return @@ -338,7 +346,6 @@ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, ledc_timer_t timer_sel); * @return * - ESP_ERR_INVALID_ARG Parameter error * - ESP_OK Success - * */ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, ledc_timer_t timer_sel); @@ -369,6 +376,7 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel /** * @brief Set LEDC fade function. + * * @note Call ledc_fade_func_install() once before calling this function. * Call ledc_fade_start() after this to start fading. * @note ledc_set_fade_with_step, ledc_set_fade_with_time and ledc_fade_start are not thread-safe, do not call these functions to @@ -376,22 +384,24 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel * A thread-safe version of API is ledc_set_fade_step_and_start * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. - * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. , + * + * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t - * @param target_duty Target duty of fading [0, (2**duty_resolution) - 1] + * @param target_duty Target duty of fading [0, (2**duty_resolution)] * @param scale Controls the increase or decrease step scale. * @param cycle_num increase or decrease the duty every cycle_num cycles * * @return - * - ESP_ERR_INVALID_ARG Parameter error * - ESP_OK Success - * - ESP_ERR_INVALID_STATE Fade function not installed. + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, uint32_t scale, uint32_t cycle_num); /** * @brief Set LEDC fade function, with a limited time. + * * @note Call ledc_fade_func_install() once before calling this function. * Call ledc_fade_start() after this to start fading. * @note ledc_set_fade_with_step, ledc_set_fade_with_time and ledc_fade_start are not thread-safe, do not call these functions to @@ -399,43 +409,48 @@ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel * A thread-safe version of API is ledc_set_fade_step_and_start * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. - * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. , + * + * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t - * @param target_duty Target duty of fading [0, (2**duty_resolution) - 1] + * @param target_duty Target duty of fading [0, (2**duty_resolution)] * @param max_fade_time_ms The maximum time of the fading ( ms ). * * @return - * - ESP_ERR_INVALID_ARG Parameter error * - ESP_OK Success - * - ESP_ERR_INVALID_STATE Fade function not installed. + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, int max_fade_time_ms); /** * @brief Install LEDC fade function. This function will occupy interrupt of LEDC module. + * * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. * * @return * - ESP_OK Success - * - ESP_ERR_INVALID_STATE Fade function already installed. + * - ESP_ERR_INVALID_ARG Intr flag error + * - ESP_ERR_NOT_FOUND Failed to find available interrupt source + * - ESP_ERR_INVALID_STATE Fade function already installed */ esp_err_t ledc_fade_func_install(int intr_alloc_flags); /** * @brief Uninstall LEDC fade function. - * */ void ledc_fade_func_uninstall(void); /** * @brief Start LEDC fading. + * * @note Call ledc_fade_func_install() once before calling this function. * Call this API right after ledc_set_fade_with_time or ledc_set_fade_with_step before to start fading. * @note Starting fade operation with this API is not thread-safe, use with care. * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. + * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel number * @param fade_mode Whether to block until fading done. See ledc_types.h ledc_fade_mode_t for more info. @@ -443,7 +458,7 @@ void ledc_fade_func_uninstall(void); * * @return * - ESP_OK Success - * - ESP_ERR_INVALID_STATE Fade function not installed. + * - ESP_ERR_INVALID_STATE Channel not initialized or fade function not installed. * - ESP_ERR_INVALID_ARG Parameter error. */ esp_err_t ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_fade_mode_t fade_mode); @@ -451,6 +466,7 @@ esp_err_t ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_f #if SOC_LEDC_SUPPORT_FADE_STOP /** * @brief Stop LEDC fading. The duty of the channel is garanteed to be fixed at most one PWM cycle after the function returns. + * * @note This API can be called if a new fixed duty or a new fade want to be set while the last fade operation is still running in progress. * @note Call this API will abort the fading operation only if it was started by calling ledc_fade_start with LEDC_FADE_NO_WAIT mode. * @note If a fade was started with LEDC_FADE_WAIT_DONE mode, calling this API afterwards HAS no use in stopping the fade. Fade will continue until it reachs the target duty. @@ -459,73 +475,89 @@ esp_err_t ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_f * * @return * - ESP_OK Success - * - ESP_ERR_INVALID_STATE Fade function not installed. - * - ESP_ERR_INVALID_ARG Parameter error. + * - ESP_ERR_INVALID_STATE Channel not initialized + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_FAIL Fade function init error */ esp_err_t ledc_fade_stop(ledc_mode_t speed_mode, ledc_channel_t channel); #endif //SOC_LEDC_SUPPORT_FADE_STOP /** * @brief A thread-safe API to set duty for LEDC channel and return when duty updated. + * * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t - * @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution) - 1] - * @param hpoint Set the LEDC hpoint value(max: 0xfffff) + * @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)] + * @param hpoint Set the LEDC hpoint value, the range is [0, (2**duty_resolution)-1] * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_STATE Channel not initialized + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_duty_and_update(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty, uint32_t hpoint); /** * @brief A thread-safe API to set and start LEDC fade function, with a limited time. + * * @note Call ledc_fade_func_install() once, before calling this function. * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. + * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t - * @param target_duty Target duty of fading [0, (2**duty_resolution) - 1] + * @param target_duty Target duty of fading [0, (2**duty_resolution)] * @param max_fade_time_ms The maximum time of the fading ( ms ). * @param fade_mode choose blocking or non-blocking mode + * * @return - * - ESP_ERR_INVALID_ARG Parameter error * - ESP_OK Success - * - ESP_ERR_INVALID_STATE Fade function not installed. + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_fade_time_and_start(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, uint32_t max_fade_time_ms, ledc_fade_mode_t fade_mode); /** * @brief A thread-safe API to set and start LEDC fade function. + * * @note Call ledc_fade_func_install() once before calling this function. * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. + * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t - * @param target_duty Target duty of fading [0, (2**duty_resolution) - 1] + * @param target_duty Target duty of fading [0, (2**duty_resolution)] * @param scale Controls the increase or decrease step scale. * @param cycle_num increase or decrease the duty every cycle_num cycles * @param fade_mode choose blocking or non-blocking mode + * * @return - * - ESP_ERR_INVALID_ARG Parameter error * - ESP_OK Success - * - ESP_ERR_INVALID_STATE Fade function not installed. + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_fade_step_and_start(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, uint32_t scale, uint32_t cycle_num, ledc_fade_mode_t fade_mode); /** * @brief LEDC callback registration function + * * @note The callback is called from an ISR, it must never attempt to block, and any FreeRTOS API called must be ISR capable. + * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param cbs Group of LEDC callback functions * @param user_arg user registered data for the callback function + * * @return - * - ESP_ERR_INVALID_ARG Parameter error * - ESP_OK Success - * - ESP_ERR_INVALID_STATE Fade function not installed. + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_cb_register(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_cbs_t *cbs, void *user_arg); @@ -596,10 +628,11 @@ typedef struct { * @param start_duty Set the start of the gradient duty, the range of duty setting is [0, (2**duty_resolution)] * @param fade_params_list Pointer to the array of fade parameters for a multi-fade * @param list_len Length of the fade_params_list, i.e. number of fade ranges for a multi-fade (1 - SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX) + * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error - * - ESP_ERR_INVALID_STATE Fade function not installed + * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_multi_fade(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t start_duty, const ledc_fade_param_config_t *fade_params_list, uint32_t list_len); @@ -619,10 +652,11 @@ esp_err_t ledc_set_multi_fade(ledc_mode_t speed_mode, ledc_channel_t channel, ui * @param fade_params_list Pointer to the array of fade parameters for a multi-fade * @param list_len Length of the fade_params_list, i.e. number of fade ranges for a multi-fade (1 - SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX) * @param fade_mode Choose blocking or non-blocking mode + * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error - * - ESP_ERR_INVALID_STATE Fade function not installed + * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_multi_fade_and_start(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t start_duty, const ledc_fade_param_config_t *fade_params_list, uint32_t list_len, ledc_fade_mode_t fade_mode); @@ -646,11 +680,11 @@ esp_err_t ledc_set_multi_fade_and_start(ledc_mode_t speed_mode, ledc_channel_t c * @param[in] fade_params_list_size The size of the fade_params_list user allocated (1 - SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX) * @param[out] fade_params_list Pointer to the array of ledc_fade_param_config_t structure * @param[out] hw_fade_range_num Number of fade ranges for this multi-fade + * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error - * - ESP_ERR_INVALID_STATE LEDC not initialized - * - ESP_ERR_NO_MEM Out of memory + * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Required number of hardware ranges exceeds the size of the ledc_fade_param_config_t array user allocated */ esp_err_t ledc_fill_multi_fade_param_list(ledc_mode_t speed_mode, ledc_channel_t channel, @@ -673,10 +707,11 @@ esp_err_t ledc_fill_multi_fade_param_list(ledc_mode_t speed_mode, ledc_channel_t * @param[out] cycle Pointer to accept fade cycle value * @param[out] scale Pointer to accept fade scale value * @param[out] step Pointer to accept fade step value + * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error - * - ESP_ERR_INVALID_STATE LEDC not initialized + * - ESP_ERR_INVALID_STATE Channel not initialized */ esp_err_t ledc_read_fade_param(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t range, uint32_t *dir, uint32_t *cycle, uint32_t *scale, uint32_t *step); #endif // SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED diff --git a/components/driver/ledc/ledc.c b/components/driver/ledc/ledc.c index cd81b3c3b17..c41a0f3933d 100644 --- a/components/driver/ledc/ledc.c +++ b/components/driver/ledc/ledc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -600,8 +600,13 @@ esp_err_t ledc_channel_config(const ledc_channel_config_t *ledc_conf) } /*set channel parameters*/ - /* channel parameters decide how the waveform looks like in one period*/ - /* set channel duty and hpoint value, duty range is (0 ~ ((2 ** duty_resolution) - 1)), max hpoint value is 0xfffff*/ + /* channel parameters decide how the waveform looks like in one period */ + /* set channel duty and hpoint value, duty range is [0, (2**duty_res)], hpoint range is [0, (2**duty_res)-1] */ + /* Note: On ESP32, ESP32S2, ESP32S3, ESP32C3, ESP32C2, ESP32C6, ESP32H2, due to a hardware bug, + * 100% duty cycle (i.e. 2**duty_res) is not reachable when the binded timer selects the maximum duty + * resolution. For example, the max duty resolution on ESP32C3 is 14-bit width, then set duty to (2**14) + * will mess up the duty calculation in hardware. + */ ledc_set_duty_with_hpoint(speed_mode, ledc_channel, duty, hpoint); /*update duty settings*/ ledc_update_duty(speed_mode, ledc_channel); @@ -787,7 +792,7 @@ static inline void IRAM_ATTR ledc_calc_fade_end_channel(uint32_t *fade_end_statu *channel = i; } -void IRAM_ATTR ledc_fade_isr(void *arg) +static void IRAM_ATTR ledc_fade_isr(void *arg) { bool cb_yield = false; portBASE_TYPE HPTaskAwoken = pdFALSE; @@ -998,8 +1003,9 @@ static esp_err_t _ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t ESP_LOGD(LEDC_TAG, "cur duty: %"PRIu32"; target: %"PRIu32", step: %d, cycle: %d; scale: %d; dir: %d\n", duty_cur, target_duty, step_num, cycle_num, scale, dir); } else { + // Directly set duty to the target, does not care on the dir portENTER_CRITICAL(&ledc_spinlock); - ledc_duty_config(speed_mode, channel, LEDC_VAL_NO_CHANGE, target_duty, dir, 1, 1, 0); + ledc_duty_config(speed_mode, channel, LEDC_VAL_NO_CHANGE, target_duty, 1, 1, 1, 0); portEXIT_CRITICAL(&ledc_spinlock); ESP_LOGD(LEDC_TAG, "Set to target duty: %"PRIu32, target_duty); } @@ -1159,6 +1165,7 @@ esp_err_t ledc_fade_stop(ledc_mode_t speed_mode, ledc_channel_t channel) esp_err_t ledc_fade_func_install(int intr_alloc_flags) { + LEDC_CHECK(s_ledc_fade_isr_handle == NULL, "fade function already installed", ESP_ERR_INVALID_STATE); //OR intr_alloc_flags with ESP_INTR_FLAG_IRAM because the fade isr is in IRAM return ledc_isr_register(ledc_fade_isr, NULL, intr_alloc_flags | ESP_INTR_FLAG_IRAM, &s_ledc_fade_isr_handle); } diff --git a/docs/en/api-reference/peripherals/ledc.rst b/docs/en/api-reference/peripherals/ledc.rst index 2671ad2e8cd..cd199e0bd26 100644 --- a/docs/en/api-reference/peripherals/ledc.rst +++ b/docs/en/api-reference/peripherals/ledc.rst @@ -239,7 +239,13 @@ To set the duty cycle, use the dedicated function :cpp:func:`ledc_set_duty`. Aft Another way to set the duty cycle, as well as some other channel parameters, is by calling :cpp:func:`ledc_channel_config` covered in Section :ref:`ledc-api-configure-channel`. -The range of the duty cycle values passed to functions depends on selected ``duty_resolution`` and should be from ``0`` to ``(2 ** duty_resolution) - 1``. For example, if the selected duty resolution is 10, then the duty cycle values can range from 0 to 1023. This provides the resolution of ~0.1%. +The range of the duty cycle values passed to functions depends on selected ``duty_resolution`` and should be from ``0`` to ``(2 ** duty_resolution)``. For example, if the selected duty resolution is 10, then the duty cycle values can range from 0 to 1024. This provides the resolution of ~ 0.1%. + +.. only:: esp32 or esp32s2 or esp32s3 or esp32c3 or esp32c2 or esp32c6 or esp32h2 + + .. warning:: + + On {IDF_TARGET_NAME}, when channel's binded timer selects its maximum duty resolution, the duty cycle value cannot be set to ``(2 ** duty_resolution)``. Otherwise, the internal duty counter in the hardware will overflow and be messed up. Change PWM Duty Cycle using Hardware diff --git a/docs/zh_CN/api-reference/peripherals/ledc.rst b/docs/zh_CN/api-reference/peripherals/ledc.rst index ac03bc05ed1..ed692101b64 100644 --- a/docs/zh_CN/api-reference/peripherals/ledc.rst +++ b/docs/zh_CN/api-reference/peripherals/ledc.rst @@ -239,7 +239,13 @@ LED PWM 控制器可在无需 CPU 干预的情况下自动改变占空比,实 另外一种设置占空比和其他通道参数的方式是调用 :ref:`ledc-api-configure-channel` 一节提到的函数 :cpp:func:`ledc_channel_config`。 -传递给函数的占空比数值范围取决于选定的 ``duty_resolution``,应为 ``0`` 至 ``(2 ** duty_resolution) - 1``。例如,如选定的占空比分辨率为 10,则占空比的数值范围为 0 至 1023。此时分辨率为 ~0.1%。 +传递给函数的占空比数值范围取决于选定的 ``duty_resolution``,应为 ``0`` 至 ``(2 ** duty_resolution)``。例如,如选定的占空比分辨率为 10,则占空比的数值范围为 0 至 1024。此时分辨率为 ~ 0.1%。 + +.. only:: esp32 or esp32s2 or esp32s3 or esp32c3 or esp32c2 or esp32c6 or esp32h2 + + .. warning:: + + 在 {IDF_TARGET_NAME} 上,当通道绑定的定时器配置了其最大 PWM 占空比分辨率( ``MAX_DUTY_RES`` ),通道的占空比不能被设置到 ``(2 ** MAX_DUTY_RES)`` 。否则,硬件内部占空比计数器会溢出,并导致占空比计算错误。 使用硬件改变 PWM 占空比 diff --git a/examples/peripherals/ledc/ledc_basic/README.md b/examples/peripherals/ledc/ledc_basic/README.md index efab05a92b5..c030d1a5f8d 100644 --- a/examples/peripherals/ledc/ledc_basic/README.md +++ b/examples/peripherals/ledc/ledc_basic/README.md @@ -27,7 +27,7 @@ The example uses fixed PWM frequency of 5 kHz, duty cycle in 50%, and output GPI Depending on the selected `LEDC_FREQUENCY`, you will need to change the `LEDC_DUTY_RES`. -To dinamicaly set the duty and frequency, you can use the following functions: +To dynamically set the duty and frequency, you can use the following functions: To set the frequency to 2.5 kHZ i.e: @@ -35,10 +35,10 @@ To set the frequency to 2.5 kHZ i.e: ledc_set_freq(LEDC_MODE, LEDC_TIMER, 2500); ``` -Now the duty to 100% i.e: +Now set the duty to 100% i.e: ```c -ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 8191); +ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 8192); ledc_update_duty(LEDC_MODE, LEDC_CHANNEL); ``` @@ -46,7 +46,7 @@ To change the duty cycle you need to calculate the duty range according to the d If duty resolution is 13 bits: -Duty range: `0 to (2 ** 13) - 1 = 8191` where 0 is 0% and 8191 is 100%. +Duty range: `0 to (2 ** 13) = 8192` where 0 is 0% and 8192 is 100%. ### Build and Flash diff --git a/examples/peripherals/ledc/ledc_basic/main/ledc_basic_example_main.c b/examples/peripherals/ledc/ledc_basic/main/ledc_basic_example_main.c index f4f97b7200d..e6dca4f1b9c 100644 --- a/examples/peripherals/ledc/ledc_basic/main/ledc_basic_example_main.c +++ b/examples/peripherals/ledc/ledc_basic/main/ledc_basic_example_main.c @@ -15,9 +15,15 @@ #define LEDC_OUTPUT_IO (5) // Define the output GPIO #define LEDC_CHANNEL LEDC_CHANNEL_0 #define LEDC_DUTY_RES LEDC_TIMER_13_BIT // Set duty resolution to 13 bits -#define LEDC_DUTY (4095) // Set duty to 50%. ((2 ** 13) - 1) * 50% = 4095 +#define LEDC_DUTY (4096) // Set duty to 50%. (2 ** 13) * 50% = 4096 #define LEDC_FREQUENCY (5000) // Frequency in Hertz. Set frequency at 5 kHz +/* Warning: + * For ESP32, ESP32S2, ESP32S3, ESP32C3, ESP32C2, ESP32C6, ESP32H2 targets, + * when LEDC_DUTY_RES selects the maximum duty resolution (i.e. value equal to SOC_LEDC_TIMER_BIT_WIDTH), + * 100% duty cycle is not reachable (duty cannot be set to (2 ** SOC_LEDC_TIMER_BIT_WIDTH)). + */ + static void example_ledc_init(void) { // Prepare and then apply the LEDC PWM timer configuration