Low-Power LEDC Development Guide

[中文]

Introduction

In low-power applications such as smart lighting, devices usually need to maintain a long Wi-Fi connection while minimizing power consumption as much as possible. ESP-IDF provides automatic Light Sleep, Modem Sleep, and Dynamic Frequency Scaling (DFS) power management mechanisms, which can adjust the CPU and APB frequency according to application needs, achieving low-power system operation.

After enabling Dynamic Frequency Scaling (DFS), the clock of some peripherals will change with the APB frequency. For example, when using PWM dimming (LEDC), dynamic frequency scaling may cause LED flickering, and it is necessary to ensure stable brightness in conjunction with power management strategies. At the same time, when Wi-Fi is disconnected, the continuous operation of the RF module will also increase power consumption, and it is necessary to reasonably configure the power optimization strategy in the disconnected state.

This document will take LEDC as an example to introduce how to ensure stable PWM dimming under the enabled Dynamic Frequency Scaling (DFS) and low-power mode, while managing the power consumption in the Wi-Fi disconnected state. Similar principles also apply to other peripherals that depend on APB or fixed clocks.

Maintaining a Long Wi-Fi Connection

For smart lighting products, it is usually necessary to maintain a long Wi-Fi connection. The following low-power configurations are recommended:

  1. Enable Automatic Light sleep

  2. Enable BLE Modem sleep

  3. Enable Wi-Fi Modem sleep

LEDC Clock Source Selection

After enabling Dynamic Frequency Scaling (DFS), the APB frequency may change multiple times within a single RTOS cycle, and some peripheral communications that depend on the APB clock may be affected. For specific instructions, see Dynamic Frequency Scaling and Peripheral Drivers.

For example, for dimming operations, when using an I2C external dimming chip, communication is not affected by dynamic frequency scaling; when using LEDC, if the clock source is APB, flickering may occur.

To ensure stable dimming, it is necessary to choose a suitable clock source according to the usage scenario. LEDC supports two clock sources: APB and RTC 8M. Both have their own characteristics in terms of clock accuracy, sensitivity to dynamic frequency scaling, and temperature stability. When choosing, you need to balance accuracy and stability.

APB Clock Source

RTC 8M Clock Source

Clock Frequency

80 MHz

8 MHz

Clock Accuracy

±10 ppm

Low

Impact of Dynamic Frequency Scaling

Need to use PM Lock to ensure normal operation of LEDC

Not affected

Temperature Stability

High

Low (±2%)

Clock Jitter

Stable

Relatively stable

Using APB as the Clock Source

Usually, LEDC uses APB as the default clock source. After enabling Dynamic Frequency Scaling (DFS), the APB frequency will be dynamically adjusted, but LEDC itself will not automatically adapt to the changes in APB. This will cause the PWM output to flicker when the light is on, affecting the stability of dimming.

Therefore, in practical applications, it is necessary to use PM Lock in conjunction with the working state of LEDC to fix the LEDC frequency and avoid DFS changing its frequency causing flickering:

  • When turning on the light (LEDC output), acquire the PM Lock, prevent the APB clock from dynamically adjusting, and also prevent the CPU from entering Light Sleep mode;

  • When turning off the light (LEDC does not output), release the PM Lock, allow the APB clock to dynamically adjust, and also allow the CPU to enter Light Sleep mode to save power consumption.

 static esp_pm_lock_handle_t s_pm_apb_lock = NULL;
 static esp_pm_lock_handle_t s_pm_light_lock = NULL;
 static esp_pm_lock_handle_t s_pm_cpu_lock = NULL;
 ledc_timer_config_t ledc_timer = {
           .duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty
           .freq_hz = 5000, // frequency of PWM signal
           .speed_mode = LEDC_LS_MODE, // timer mode
           .timer_num = LEDC_LS_TIMER, // timer index
           .clk_cfg = LEDC_USE_APB_CLK, /*!< LEDC timer select APB clock as source clock*/
 };

 if (s_pm_apb_lock == NULL) {
           if (esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "l_apb", &s_pm_apb_lock) != ESP_OK) {
                   ESP_LOGE(TAG, "esp pm lock create failed");
           }
           if (esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "l_ls", &s_pm_light_lock) != ESP_OK) {
                   ESP_LOGE(TAG, "esp pm lock create failed");
           }
           if (esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "l_cpu", &s_pm_cpu_lock) != ESP_OK) {
                    ESP_LOGE(TAG, "esp pm lock create failed");
           }
 }

 while (1) {
           ESP_ERROR_CHECK(esp_pm_lock_acquire(s_pm_apb_lock));
           ESP_ERROR_CHECK(esp_pm_lock_acquire(s_pm_light_lock));
           ESP_ERROR_CHECK(esp_pm_lock_acquire(s_pm_cpu_lock));
           ESP_LOGI(TAG, "light turn on");
           for (ch = 0; ch < LEDC_CH_NUM; ch++) {
                   ledc_set_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel, LEDC_TEST_DUTY);
                   ledc_update_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel);
           }
           vTaskDelay(pdMS_TO_TICKS(5 * 1000));
                   ESP_LOGI(TAG, "light turn off");
  for (ch = 0; ch < LEDC_CH_NUM; ch++) {
                   ledc_set_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel, 0);
                   ledc_update_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel);
           }
           ESP_ERROR_CHECK(esp_pm_lock_release(s_pm_apb_lock));
           ESP_ERROR_CHECK(esp_pm_lock_release(s_pm_light_lock));
           ESP_ERROR_CHECK(esp_pm_lock_release(s_pm_cpu_lock));
           vTaskDelay(pdMS_TO_TICKS(5 * 1000));
}

Using RTC 8M as the clock source

When LEDC uses RTC 8M as the clock source, the RTC 8M clock will not be affected when dynamic frequency scaling (DFS) is enabled, and there will be no flickering when the light is on. Therefore, there is no need to use PM lock in actual applications.

ledc_timer_config_t ledc_timer = {
             .duty_resolution = LEDC_TIMER_10_BIT, // resolution of PWM duty
             .freq_hz = 5000, // frequency of PWM signal
             .speed_mode = LEDC_LS_MODE, // timer mode
             .timer_num = LEDC_LS_TIMER, // timer index
             .clk_cfg = LEDC_USE_RTC8M_CLK, /*!< LEDC timer select RTC8M_CLK as source clock*/
  };

  while (1) {
             ESP_LOGI(TAG, "light turn on");
             for (ch = 0; ch < LEDC_CH_NUM; ch++) {
                     ledc_set_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel, LEDC_TEST_DUTY);
                     ledc_update_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel);
             }
             vTaskDelay(pdMS_TO_TICKS(5 * 1000));
             ESP_LOGI(TAG, "light turn off");
             for (ch = 0; ch < LEDC_CH_NUM; ch++) {
                     ledc_set_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel, 0);
                     ledc_update_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel);
             }
             vTaskDelay(pdMS_TO_TICKS(5 * 1000));
  }

Power optimization under Wi-Fi disconnected status

Under normal circumstances, smart devices maintain a connection with the router. However, if the router fails or the signal is abnormal, the device will disconnect. At this time, the RF module may continue to work, leading to a significant increase in average power consumption.

To reduce power consumption while maintaining the ability to reconnect, ESP-IDF provides a power optimization solution for disconnected states. This solution periodically wakes up the RF module to allow the device to moderately sleep when not connected, saving energy and attempting to reestablish a connection.

The specific usage is as follows:

  1. Enable Disconnected Power Management

  2. After Wi-Fi initialization, call esp_wifi_set_connectionless_wake_interval(uint16_t interval); to set the wake interval

  3. After Wi-Fi initialization, call esp_now_set_wake_window(uint16_t window); API to set the wake work window

For example, setting the wake interval to 200ms and the wake work window to 110ms, the RF will work periodically to reduce power consumption when not connected to the router.