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.
- 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
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"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 ]__|
pulse_width + dead_time ≤ slot
If violated, creation fails.
- Resolution is auto-selected based on:
- frequency
- number of channels
- Guarantees ≥5% granularity per slot
- Maximum resolution: 13 bits
| Chip | Status |
|---|---|
| ESP32 | ✅ Tested |
| ESP32-S2 | |
| ESP32-S3 | |
| ESP32-C3 |
The component uses soc/soc_caps.h and targets the LEDC low-speed mode,
making it portable across ESP-IDF supported chips.
esp_err_t interleavedPWMCreate(
interleaved_pwm_config_t *config,
interleaved_pwm_handle_t **out_handle);PWM_START(handle);
PWM_STOP(handle);
PWM_DESTROY(&handle);
PWM_SET_WIDTH(handle, channel, width);#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);- 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
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. |
- Navigate to the example directory:
cd examples/simple
idf.py build flash monitor
# License
MIT License
