Step 22 of 56
LEDC and sigma-delta: the simple outputs
Eight PWM channels for dimming and clean square waves, and eight 1-bit density-modulated outputs that become analog with one resistor and one capacitor.
LEDC: PWM without the motor-control machinery
Eight low-speed channels fed by four timers. A channel picks a timer — which sets its frequency and duty resolution — and drives a GPIO with a duty cycle you change at run time. This is the "dim an LED, generate a clean PWM" block; for dead-time, fault inputs and capture, see MCPWM.
type Channel_Index is range 0 .. 7;
subtype Resolution is Positive range 1 .. 14; -- duty-cycle bits
subtype Duty_Percent is Float range 0.0 .. 100.0;
procedure Claim (C : in out Channel; Index : Channel_Index);
procedure Configure (C : ...; Freq : ...; Bits : Resolution; Pin : ...);
procedure Set_Duty (C : Channel; Percent : Duty_Percent);
procedure Stop (C : Channel);
Two constraints are worth knowing before you pick numbers.
Resolution and frequency trade against each
other: freq_max = 80 MHz / 2**Bits. Fourteen bits of
duty resolution caps you under 5 kHz; a 100 kHz carrier leaves about
nine bits. Choose Bits for the dimming smoothness you actually need,
not the maximum.
A channel uses timer Index mod 4.
Channels 0 and 4 share a timer, as do 1 and 5, and so on — so two channels
four apart cannot run at different frequencies. Spread channels across
0 .. 3 when you need independent rates.
Set_Duty takes effect at the next period, so it is safe to call
while running — no glitch, no partial-update flicker. The handle is limited
and controlled as everywhere else here, and finalization stops the output
as well as releasing the channel, so a leaked handle cannot keep driving a
pad.
Sigma-delta: analog for the price of an RC filter
Eight channels in the GPIO sigma-delta unit. Each emits a high-frequency pulse stream whose average density is set by a signed 8-bit value; pass it through an external RC low-pass and you have a cheap analog output — LED dimming, a bias voltage, simple audio.
type Channel_Index is range 0 .. 7;
subtype Density_Percent is Float range 0.0 .. 100.0;
procedure Configure (C : ...; Pin : ...; Carrier_Hz : ...); -- starts at 0 %
procedure Set_Density (C : Channel; Percent : Density_Percent); -- one register write
The distinction from LEDC matters when choosing between them. LEDC varies the width of a pulse at a fixed frequency, so its output has energy at the PWM frequency and its harmonics. Sigma-delta varies the density of fixed-width pulses, pushing quantisation noise up in frequency where a simple filter removes it — which is why it makes a better analog voltage and why the same technique appears inside I2S's PDM mode.
Set_Density is a single register write, so it is cheap enough to
call from a sample loop.