From 31f9a69454c029c0af648b915992959527b802e8 Mon Sep 17 00:00:00 2001 From: songruojing Date: Fri, 6 Aug 2021 12:23:26 +0800 Subject: [PATCH] ledc: Update LEDC programming guide Add source clock in timer config Add fade end callback and ledc_fade_stop usage Explain ledc_fade_mode_t difference and limitation --- components/driver/test/test_ledc.c | 12 ++- docs/en/api-reference/peripherals/ledc.rst | 93 +++++++++++++++++-- docs/zh_CN/api-reference/peripherals/ledc.rst | 91 ++++++++++++++++-- 3 files changed, 179 insertions(+), 17 deletions(-) diff --git a/components/driver/test/test_ledc.c b/components/driver/test/test_ledc.c index 2134d27d6c..6eb74c78b0 100644 --- a/components/driver/test/test_ledc.c +++ b/components/driver/test/test_ledc.c @@ -445,7 +445,6 @@ TEST_CASE("LEDC fade stop test", "[ledc]") const ledc_mode_t test_speed_mode = TEST_SPEED_MODE; fade_setup(); - // Overwrite the last fade with new fade int64_t fade_start, fade_stop; int time_ms = 0; fade_start = esp_timer_get_time(); @@ -453,14 +452,19 @@ TEST_CASE("LEDC fade stop test", "[ledc]") TEST_ESP_OK(ledc_fade_start(test_speed_mode, LEDC_CHANNEL_0, LEDC_FADE_NO_WAIT)); // Add some delay before stopping the fade vTaskDelay(127 / portTICK_RATE_MS); - uint32_t duty_at_stop = ledc_get_duty(test_speed_mode, LEDC_CHANNEL_0); + // Get duty value right before stopping the fade + uint32_t duty_before_stop = ledc_get_duty(test_speed_mode, LEDC_CHANNEL_0); TEST_ESP_OK(ledc_fade_stop(test_speed_mode, LEDC_CHANNEL_0)); fade_stop = esp_timer_get_time(); time_ms = (fade_stop - fade_start) / 1000; TEST_ASSERT_TRUE(fabs(time_ms - 127) < 20); + // Get duty value after fade_stop returns (give at least one cycle for the duty set in fade_stop to take effective) + uint32_t duty_after_stop = ledc_get_duty(test_speed_mode, LEDC_CHANNEL_0); + TEST_ASSERT_INT32_WITHIN(4, duty_before_stop, duty_after_stop); // 4 is the scale for one step in the last fade vTaskDelay(300 / portTICK_RATE_MS); - TEST_ASSERT_EQUAL_INT32(duty_at_stop, ledc_get_duty(test_speed_mode, LEDC_CHANNEL_0)); - TEST_ASSERT_NOT_EQUAL(4000, duty_at_stop); + // Duty should not change any more after ledc_fade_stop returns + TEST_ASSERT_EQUAL_INT32(duty_after_stop, ledc_get_duty(test_speed_mode, LEDC_CHANNEL_0)); + TEST_ASSERT_NOT_EQUAL(4000, duty_after_stop); //deinitialize fade service ledc_fade_func_uninstall(); diff --git a/docs/en/api-reference/peripherals/ledc.rst b/docs/en/api-reference/peripherals/ledc.rst index 54d0fda5a4..b594e63329 100644 --- a/docs/en/api-reference/peripherals/ledc.rst +++ b/docs/en/api-reference/peripherals/ledc.rst @@ -1,6 +1,6 @@ LED Control (LEDC) ================== -{IDF_TARGET_LEDC_CHAN_NUM:default="8", esp32="16", esp32s2="8", esp32c3="6"} +{IDF_TARGET_LEDC_CHAN_NUM:default="8", esp32="16", esp32s2="8", esp32c3="6", esp32s3="8"} :link_to_translation:`zh_CN:[中文]` @@ -45,7 +45,7 @@ As an optional step, it is also possible to set up an interrupt on fade end. .. _ledc-api-configure-timer: -Timer Configuration +Timer Configuration ^^^^^^^^^^^^^^^^^^^ Setting the timer is done by calling the function :cpp:func:`ledc_timer_config` and passing the data structure :cpp:type:`ledc_timer_config_t` that contains the following configuration settings: @@ -57,9 +57,80 @@ Setting the timer is done by calling the function :cpp:func:`ledc_timer_config` - Timer number :cpp:type:`ledc_timer_t` - PWM signal frequency - Resolution of PWM duty + - Source clock :cpp:type:`ledc_clk_cfg_t` The frequency and the duty resolution are interdependent. The higher the PWM frequency, the lower the duty resolution which is available, and vice versa. This relationship might be important if you are planning to use this API for purposes other than changing the intensity of LEDs. For more details, see Section :ref:`ledc-api-supported-range-frequency-duty-resolution`. +The source clock can also limit the PWM frequency. The higher the source clock frequency, the higher the maximum PWM frequency can be configured. + +.. only:: esp32 + + .. list-table:: Characteristics of {IDF_TARGET_NAME} LEDC source clocks + :widths: 5 5 5 20 + :header-rows: 1 + + * - Clock name + - Clock freq + - Speed mode + - Clock capabilities + * - APB_CLK + - 80 MHz + - High / Low + - / + * - REF_TICK + - 1 MHz + - High / Low + - Dynamic Frequency Scaling compatible + * - RTC8M_CLK + - ~8 MHz + - Low + - Dynamic Frequency Scaling compatible, Light sleep compatible + +.. only:: esp32s2 + + .. list-table:: Characteristics of {IDF_TARGET_NAME} LEDC source clocks + :widths: 15 15 30 + :header-rows: 1 + + * - Clock name + - Clock freq + - Clock capabilities + * - APB_CLK + - 80 MHz + - / + * - REF_TICK + - 1 MHz + - Dynamic Frequency Scaling compatible + * - RTC8M_CLK + - ~8 MHz + - Dynamic Frequency Scaling compatible, Light sleep compatible + * - XTAL_CLK + - 40 MHz + - Dynamic Frequency Scaling compatible + +.. only:: esp32s3 or esp32c3 + + .. list-table:: Characteristics of {IDF_TARGET_NAME} LEDC source clocks + :widths: 15 15 30 + :header-rows: 1 + + * - Clock name + - Clock freq + - Clock capabilities + * - APB_CLK + - 80 MHz + - / + * - RTC20M_CLK + - ~20 MHz + - Dynamic Frequency Scaling compatible, Light sleep compatible + * - XTAL_CLK + - 40 MHz + - Dynamic Frequency Scaling compatible + + .. note:: + + For {IDF_TARGET_NAME}, all timers share one clock source. In other words, it is impossible to use different clock sources for different timers. + .. _ledc-api-configure-channel: @@ -82,7 +153,7 @@ Once the channel starts operating and generating the PWM signal with the constan The following two sections describe how to change the duty cycle using software and hardware fading. If required, the signal's frequency can also be changed; it is covered in Section :ref:`ledc-api-change-pwm-frequency`. -.. only:: esp32s2 or esp32c3 +.. only:: not esp32 .. note:: @@ -108,7 +179,15 @@ The LEDC hardware provides the means to gradually transition from one duty cycle * :cpp:func:`ledc_set_fade_with_step` * :cpp:func:`ledc_set_fade` -Finally start fading with :cpp:func:`ledc_fade_start`. +.. only:: esp32 + + Start fading with :cpp:func:`ledc_fade_start`. A fade can be operated in blocking or non-blocking mode, please check :cpp:enum:`ledc_fade_mode_t` for the difference between the two available fade modes. Note that with either fade mode, the next fade or fixed-duty update will not take effect until the last fade finishes. Due to hardware limitations, there is no way to stop a fade before it reaches its target duty. + +.. only:: not esp32 + + Start fading with :cpp:func:`ledc_fade_start`. A fade can be operated in blocking or non-blocking mode, please check :cpp:enum:`ledc_fade_mode_t` for the difference between the two available fade modes. Note that with either fade mode, the next fade or fixed-duty update will not take effect until the last fade finishes or is stopped. :cpp:func:`ledc_fade_stop` has to be called to stop a fade that is in progress. + +To get a notification about the completion of a fade operation, a fade end callback function can be registered for each channel by calling :cpp:func:`ledc_cb_register` after the fade service being installed. If not required anymore, fading and an associated interrupt can be disabled with :cpp:func:`ledc_fade_func_uninstall`. @@ -149,13 +228,13 @@ For registration of a handler to address this interrupt, call :cpp:func:`ledc_is .. only:: esp32 .. _ledc-api-high_low_speed_mode: - + LEDC High and Low Speed Mode ---------------------------- - High speed mode enables a glitch-free changeover of timer settings. This means that if the timer settings are modified, the changes will be applied automatically on the next overflow interrupt of the timer. In contrast, when updating the low-speed timer, the change of settings should be explicitly triggered by software. The LEDC driver handles it in the background, e.g., when :cpp:func:`ledc_timer_config` or :cpp:func:`ledc_timer_set` is called. + High speed mode enables a glitch-free changeover of timer settings. This means that if the timer settings are modified, the changes will be applied automatically on the next overflow interrupt of the timer. In contrast, when updating the low-speed timer, the change of settings should be explicitly triggered by software. The LEDC driver handles it in the background, e.g., when :cpp:func:`ledc_timer_config` or :cpp:func:`ledc_timer_set` is called. - For additional details regarding speed modes, see *{IDF_TARGET_NAME} Technical Reference Manual* > *LED PWM Controller (LEDC)* [`PDF <{IDF_TARGET_TRM_EN_URL}#ledpwm>`__]. Please note that the support for ``SLOW_CLOCK`` mentioned in this manual is not yet supported in the LEDC driver. + For additional details regarding speed modes, see *{IDF_TARGET_NAME} Technical Reference Manual* > *LED PWM Controller (LEDC)* [`PDF <{IDF_TARGET_TRM_EN_URL}#ledpwm>`__]. .. _ledc-api-supported-range-frequency-duty-resolution: diff --git a/docs/zh_CN/api-reference/peripherals/ledc.rst b/docs/zh_CN/api-reference/peripherals/ledc.rst index 2b5090f32e..a70e86d7d2 100644 --- a/docs/zh_CN/api-reference/peripherals/ledc.rst +++ b/docs/zh_CN/api-reference/peripherals/ledc.rst @@ -1,6 +1,6 @@ LED PWM 控制器 ============== -{IDF_TARGET_LEDC_CHAN_NUM:default="8", esp32="16", esp32s2="8", esp32c3="6"} +{IDF_TARGET_LEDC_CHAN_NUM:default="8", esp32="16", esp32s2="8", esp32c3="6", esp32s3="8"} :link_to_translation:`en:[English]` @@ -57,9 +57,80 @@ LED PWM 控制器可在无需 CPU 干预的情况下自动改变占空比,实 - 定时器索引 :cpp:type:`ledc_timer_t` - PWM 信号频率 - PWM 占空比分辨率 + - 时钟源 :cpp:type:`ledc_clk_cfg_t` 频率和占空比分辨率相互关联。PWM 频率越高,占空比分辨率越低,反之亦然。如果 API 不是用来改变 LED 亮度,而是用于其它目的,这种相互关系可能会很重要。更多信息详见 :ref:`ledc-api-supported-range-frequency-duty-resolution` 一节。 +时钟源同样可以限制PWM频率。选择的时钟源频率越高,可以配置的PWM频率上限就越高。 + +.. only:: esp32 + + .. list-table:: {IDF_TARGET_NAME} LEDC 时钟源特性 + :widths: 5 5 8 20 + :header-rows: 1 + + * - 时钟名称 + - 时钟频率 + - 速度模式 + - 时钟功能 + * - APB_CLK + - 80 MHz + - 高速 / 低速 + - / + * - REF_TICK + - 1 MHz + - 高速 / 低速 + - 支持动态调频(DFS)功能 + * - RTC8M_CLK + - ~8 MHz + - 低速 + - 支持动态调频(DFS)功能,支持Light-sleep模式 + +.. only:: esp32s2 + + .. list-table:: {IDF_TARGET_NAME} LEDC 时钟源特性 + :widths: 10 10 30 + :header-rows: 1 + + * - 时钟名称 + - 时钟频率 + - 时钟功能 + * - APB_CLK + - 80 MHz + - / + * - REF_TICK + - 1 MHz + - 支持动态调频(DFS)功能 + * - RTC8M_CLK + - ~8 MHz + - 支持动态调频(DFS)功能,支持Light-sleep模式 + * - XTAL_CLK + - 40 MHz + - 支持动态调频(DFS)功能 + +.. only:: esp32s3 or esp32c3 + + .. list-table:: {IDF_TARGET_NAME} LEDC 时钟源特性 + :widths: 10 10 30 + :header-rows: 1 + + * - 时钟名称 + - 时钟频率 + - 时钟功能 + * - APB_CLK + - 80 MHz + - / + * - RTC20M_CLK + - ~20 MHz + - 支持动态调频(DFS)功能,支持Light-sleep模式 + * - XTAL_CLK + - 40 MHz + - 支持动态调频(DFS)功能 + + .. note:: + + {IDF_TARGET_NAME}的所有定时器共用一个时钟源。因此{IDF_TARGET_NAME}不支持给不同的定时器配置不同的时钟源。 + .. _ledc-api-configure-channel: @@ -82,7 +153,7 @@ LED PWM 控制器可在无需 CPU 干预的情况下自动改变占空比,实 以下两节介绍了如何使用软件和硬件改变占空比。如有需要,PWM 信号的频率也可更改,详见 :ref:`ledc-api-change-pwm-frequency` 一节。 -.. only:: esp32s2 or esp32c3 +.. only:: not esp32 .. note:: @@ -108,7 +179,15 @@ LED PWM 控制器硬件可逐渐改变占空比的数值。要使用此功能, * :cpp:func:`ledc_set_fade_with_step` * :cpp:func:`ledc_set_fade` -最后用 :cpp:func:`ledc_fade_start` 开启渐变。 +.. only:: esp32 + + 最后需要调用 :cpp:func:`ledc_fade_start` 开启渐变。渐变可以在阻塞或非阻塞模式下运行,具体区别请查看 :cpp:enum:`ledc_fade_mode_t`。需要特别注意的是,不管在哪种模式下,下一次渐变或单次占空比配置的指令生效都必须等到前一次渐变结束。由于 {IDF_TARGET_NAME} 的硬件限制,在渐变达到原先预期的占空比前想要中止本次渐变是不被支持的。 + +.. only:: not esp32 + + 最后需要调用 :cpp:func:`ledc_fade_start` 开启渐变。渐变可以在阻塞或非阻塞模式下运行,具体区别请查看 :cpp:enum:`ledc_fade_mode_t`。需要特别注意的是,不管在哪种模式下,下一次渐变或是单次占空比配置的指令生效都必须等到前一次渐变完成或被中止。中止一个正在运行中的渐变需要调用函数 :cpp:func:`ledc_fade_stop`。 + +此外,在使能渐变后,每个通道都可以额外通过调用 :cpp:func:`ledc_cb_register` 注册一个回调函数用以获得渐变完成的事件通知。 如不需要渐变和渐变中断,可用函数 :cpp:func:`ledc_fade_func_uninstall` 关闭。 @@ -149,13 +228,13 @@ LED PWM 控制器 API 有多种方式即时改变 PWM 频率: .. only:: esp32 .. _ledc-api-high_low_speed_mode: - + LED PWM 控制器高速和低速模式 ---------------------------------- 高速模式的优点是可平稳地改变定时器设置。也就是说,高速模式下如定时器设置改变,此变更会自动应用于定时器的下一次溢出中断。而更新低速定时器时,设置变更应由软件显式触发。LED PWM 驱动的设置将在硬件层面被修改,比如在调用函数 :cpp:func:`ledc_timer_config` 或 :cpp:func:`ledc_timer_set` 时。 - 更多关于速度模式的详细信息请参阅 *{IDF_TARGET_NAME} 技术参考手册* > *LED PWM 控制器 (LEDC)* [`PDF <{IDF_TARGET_TRM_EN_URL}#ledpwm>`__]。注意,该手册中提到的支持 ``SLOW_CLOCK`` 暂不适用于 LED PWM 驱动。 + 更多关于速度模式的详细信息请参阅 *{IDF_TARGET_NAME} 技术参考手册* > *LED PWM 控制器 (LEDC)* [`PDF <{IDF_TARGET_TRM_EN_URL}#ledpwm>`__]。 .. _ledc-api-supported-range-frequency-duty-resolution: @@ -180,7 +259,7 @@ LED PWM 控制器 API 会在设定的频率和占空比分辨率超过 LED PWM 此时,占空比分辨率或频率必须降低。比如,将占空比分辨率设置为 2 会解决这一问题,让占空比设置为 25% 的倍数,即 25%、50% 或 75%。 -如设置的频率和占空比分辨率低于所支持的最低值,LED PWM 驱动器也会反映并报告,如: +如设置的频率和占空比分辨率低于所支持的最低值,LED PWM 驱动器也会反映并报告,如: ::