LED APIs

LED

The LED provides a convenient and thread-safe wrapper around the ESP-IDF LEDC perhipheral.

It allows for both instant and hardware-based timed changing (fading) of duty cycle (in floating point percent [0,100]).

API Reference

Header File

Classes

class Led : public espp::BaseComponent

Provides a wrapper around the LEDC peripheral in ESP-IDF which allows for thread-safe control over one or more channels of LEDs using a simpler API.

Linear LED Example

    fmt::print("Starting linear led example!\n");
    float num_seconds_to_run = 10.0f;
    int led_fade_time_ms = 1000;
    std::vector<espp::Led::ChannelConfig> led_channels{{
        .gpio = 2,
        .channel = LEDC_CHANNEL_5,
        .timer = LEDC_TIMER_2,
    }};
    espp::Led led(espp::Led::Config{
        .timer = LEDC_TIMER_2,
        .frequency_hz = 5000,
        .channels = led_channels,
        .duty_resolution = LEDC_TIMER_10_BIT,
    });
    auto led_channel = led_channels[0].channel;
    auto start = std::chrono::high_resolution_clock::now();
    auto now = std::chrono::high_resolution_clock::now();
    float elapsed = std::chrono::duration<float>(now - start).count();
    while (elapsed < num_seconds_to_run) {
      // if we can change the led, the previous fade is done
      if (led.can_change(led_channel)) {
        auto maybe_duty = led.get_duty(led_channel);
        if (maybe_duty.has_value()) {
          auto current_duty = maybe_duty.value();
          float new_duty = (current_duty < 50.0f) ? 100.0f : 0.0f;
          // start a new fade to the opposite duty cycle
          led.set_fade_with_time(led_channel, new_duty, led_fade_time_ms);
        }
      }
      // sleep for a little bit
      std::this_thread::sleep_for(100ms);
      // update our elapsed time
      now = std::chrono::high_resolution_clock::now();
      elapsed = std::chrono::duration<float>(now - start).count();
    }

Breathing LED Example

    fmt::print("Starting gaussian led example!\n");
    float breathing_period = 3.5f; // seconds
    float num_periods_to_run = 2.0f;
    std::vector<espp::Led::ChannelConfig> led_channels{{
        .gpio = 2,
        .channel = LEDC_CHANNEL_5,
        .timer = LEDC_TIMER_2,
    }};
    espp::Led led(espp::Led::Config{
        .timer = LEDC_TIMER_2,
        .frequency_hz = 5000,
        .channels = led_channels,
        .duty_resolution = LEDC_TIMER_10_BIT,
        .clock_config = LEDC_USE_RC_FAST_CLK,
    });
    espp::Gaussian gaussian({.gamma = 0.1f, .alpha = 1.0f, .beta = 0.5f});
    auto breathe = [&gaussian, &breathing_period]() -> float {
      static auto breathing_start = std::chrono::high_resolution_clock::now();
      auto now = std::chrono::high_resolution_clock::now();
      auto elapsed = std::chrono::duration<float>(now - breathing_start).count();
      float t = std::fmod(elapsed, breathing_period) / breathing_period;
      return gaussian(t);
    };
    auto led_callback = [&breathe, &led, &led_channels](auto &m, auto &cv) -> bool {
      led.set_duty(led_channels[0].channel, 100.0f * breathe());
      std::unique_lock<std::mutex> lk(m);
      cv.wait_for(lk, 10ms);
      return false;
    };
    auto led_task =
        espp::Task::make_unique({.callback = led_callback, .task_config = {.name = "breathe"}});
    led_task->start();
    float wait_time = num_periods_to_run * breathing_period;
    fmt::print("Sleeping for {:.1f}s...\n", wait_time);
    std::this_thread::sleep_for(wait_time * 1.0s);

Public Functions

inline explicit Led(const Config &config) noexcept

Initialize the LEDC subsystem according to the configuration.

Parameters

config – The configuration structure for the LEDC subsystem.

inline ~Led()

Stop the LEDC subsystem and free memory.

inline bool can_change(ledc_channel_t channel)

Can the LED settings can be changed for the channel? If this function returns true, then (threaded race conditions aside), the set_duty() and set_fade_with_time() functions should not block.

Parameters

channel – The channel to check

Returns

True if the channel settings can be changed, false otherwise

inline std::optional<float> get_duty(ledc_channel_t channel) const

Get the current duty cycle this channel has.

Parameters

channel – The channel in question

Returns

The duty percentage [0.0f, 100.0f] if the channel is managed, std::nullopt otherwise

inline void set_duty(ledc_channel_t channel, float duty_percent)

Set the duty cycle for this channel.

Note

This function will block until until a current fade process completes (if there is one).

Parameters
  • channel – The channel to set the duty cycle for.

  • duty_percent – The new duty percentage, [0.0, 100.0].

inline void set_fade_with_time(ledc_channel_t channel, float duty_percent, uint32_t fade_time_ms)

Set the duty cycle for this channel, fading from the current duty cycle to the new duty cycle over fade_time_ms milliseconds.

Note

This function will block until until a current fade process completes (if there is one).

Parameters
  • channel – The channel to fade.

  • duty_percent – The new duty percentage to fade to, [0.0, 100.0].

  • fade_time_ms – The number of milliseconds for which to fade.

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters

rate_limit – The rate limit to use for the logger

struct ChannelConfig

Represents one LED channel.

Public Members

size_t gpio

The GPIO pin the LED is connected to.

ledc_channel_t channel

The LEDC channel that you want associated with this LED.

ledc_timer_t timer

The LEDC timer that you want associated with this LED channel.

float duty{0}

The starting duty cycle (%) [0, 100] that you want the LED channel to have.

ledc_mode_t speed_mode{LEDC_LOW_SPEED_MODE}

The LEDC speed mode you want for this LED channel.

bool output_invert = {false}

Whether to invert the GPIO output for this LED channel.

struct Config

Configuration Struct for the LEDC subsystem including the different LED channels that should be associated.

Public Members

int isr_core_id = -1

The core to install the LEDC fade function (interrupt) on. If -1, then the LEDC interrupt is installed on the core that this constructor is called on. If 0 or 1, then the LEDC interrupt is installed on the specified core.

ledc_timer_t timer

The LEDC timer that you want associated with the LEDs.

size_t frequency_hz

The frequency that you want to run the PWM hardawre for the LEDs at.

Note

this is inversely related to the duty resolution configuration.

std::vector<ChannelConfig> channels

The LED channels that you want to control.

ledc_timer_bit_t duty_resolution{LEDC_TIMER_13_BIT}

The resolution of the duty cycle for these LEDs.

Note

this is inversely related to the frequency configuration.

ledc_clk_cfg_t clock_config{LEDC_AUTO_CLK}

The LEDC clock configuration you want for these LED channels.

ledc_mode_t speed_mode{LEDC_LOW_SPEED_MODE}

The LEDC speed mode you want for these LED channels.

Logger::Verbosity log_level = {Logger::Verbosity::WARN}

Log verbosity for the task.