Skip to content

embedblocks/interleaved-pwm

Repository files navigation

interleaved_pwm

ESP-IDF Espressif Component Registry License

ESP-IDF component for multi-phase interleaved PWM generation using the LEDC peripheral. Instead of switching all channels simultaneously, this component distributes switching events across the PWM period, reducing input ripple and improving power integrity.


Features

  • Multi-channel phase-interleaved PWM
  • Automatic even phase distribution
  • Configurable dead time enforcement
  • Runtime per-channel pulse width control
  • Automatic LEDC timer resolution selection
  • Cross-chip support using soc_caps
  • Validation of timing constraints at creation

Installation

Using ESP-IDF Component Manager (Recommended)

idf.py add-dependency "embedblocks/interleaved_pwm^0..1.17"

Or in your project's idf_component.yml:

dependencies:
  embedblocks/interleaved_pwm: "^0..1.17"

How it works

The PWM period is divided into equal slots, one per channel:

slot = period / total_channels

Each channel is phase-shifted into its own slot.

Time →   0        5000      10000     15000     20000  (µs)
         |---------|---------|---------|---------|
CH0      [  ON  ]__|
CH1               [  ON  ]__|
CH2                         [  ON  ]__|
CH3                                   [  ON  ]__|

Dead Time Constraint

pulse_width + dead_time ≤ slot

If violated, creation fails.


Frequency and Resolution

  • Resolution is auto-selected based on:
    • frequency
    • number of channels
  • Guarantees ≥5% granularity per slot
  • Maximum resolution: 13 bits

Chip Support

Chip Status
ESP32 ✅ Tested
ESP32-S2 ⚠️ Expected to work
ESP32-S3 ⚠️ Expected to work
ESP32-C3 ⚠️ Expected to work

The component uses soc/soc_caps.h and targets the LEDC low-speed mode, making it portable across ESP-IDF supported chips.

However, only ESP32 has been fully validated so far.

API

Create

esp_err_t interleavedPWMCreate(
    interleaved_pwm_config_t *config,
    interleaved_pwm_handle_t **out_handle);

Control

PWM_START(handle);
PWM_STOP(handle);
PWM_DESTROY(&handle);
PWM_SET_WIDTH(handle, channel, width);

Usage Example

#include "interleaved_pwm.h"

static uint8_t gpio_list[4] = {5, 18, 22, 23};
static uint32_t widths[4]   = {2000, 2000, 2000, 2000};

interleaved_pwm_handle_t *pwm = NULL;
interleaved_pwm_config_t config = {
    .gpio_no      = gpio_list,
    .pulse_widths = widths,
    .total_gpio   = 4,
    .dead_time    = 1000,
    .frequency    = 50
};

ESP_ERROR_CHECK(interleavedPWMCreate(&config, &pwm));
PWM_START(pwm);
PWM_SET_WIDTH(pwm, 0, 3000);
PWM_STOP(pwm);
PWM_DESTROY(&pwm);

Limitations

Start Problem

  • All channels may not be correct on 1-2 cycle after start because of LEDC limitation
  • Single instance per application in the current release
  • Timer 0 is always used — not configurable
  • 13-bit resolution cap (sufficient for all supported chips)
  • No dynamic channel reallocation after creation

Examples

The component includes two examples demonstrating typical usage patterns.

Example Description
simple Minimal setup of a multi-channel interleaved PWM instance. Shows basic creation, start, and steady-state operation.
ramp Demonstrates runtime pulse width updates using a ramp pattern across channels. Useful for observing dynamic behaviour and transient response.

Running an example

  1. Navigate to the example directory:
cd examples/simple
idf.py build flash monitor


# License
MIT License

About

This is an implementation of PWM line interface using the LEDC PWM peripheral of esp32. An object of desired PWM phase, duty cycle, phase and dead time can be created. Multiple such objects can be used by a manager to create phase shifted PWM waves lines of same frequency, with dead time

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors