Chapters

33 DAC and PWM: Loads, Filters, and Code

electronics-controller-design
analog
digital
dac
pwm
actuators

33.1 Start With the Decision

A PWM waveform may look smooth until the load draws current. Simulate the RC filter and load before choosing code and frequency.

33.2 Route Overview

This is part 2 of 3. Review DAC and PWM: Output Foundations for the preceding evidence.

33.3 Learning Objectives

  • Calculate PWM ripple for an RC filter and load.
  • Implement DAC and PWM output on Arduino and ESP32.

33.4 Chapter Roadmap

  • PWM, DAC, and RC Simulator
  • Load Experience with PWM/DAC
  • Checkpoint: What the Load Sees
  • Arduino DAC/PWM Implementation
  • Arduino PWM Fade Code
  • ESP32 DAC Output Code
  • Try It: ESP32 DAC Output Simulation
  • PWM as Pseudo-DAC
  • Knowledge Check: PWM Duty Cycle
  • PWM Duty Cycle & DAC Output Calculator
  • PWM to Analog Conversion (RC Filter)
  • Checkpoint: PWM Filtering
  • PWM Low-Pass Filter Calculator
  • Hands-On Labs
  • ESP32 DAC Sweep Code
  • Arduino PWM Dimming Code
  • Common Pitfalls
  • DAC Resolution vs Accuracy
  • PWM Frequency Too Low
  • For Kids: Meet the Sensor Squad!
  • Matching Quiz: DAC and PWM Concepts
  • PWM to Analog Pipeline Quiz
  • Knowledge Check: DAC and PWM
  • ESP32 DAC: Digital to 2.59V
  • DAC vs PWM for LED Brightness
  • DAC/PWM Actuator Control
  • Checkpoint: Choosing DAC or PWM

33.5 PWM, DAC, and RC Simulator

The code examples below are useful when you have an Arduino, ESP32, Wokwi, or TinkerCAD open. Before writing code, use this simulator to see the core idea directly: PWM is a fast square wave, a load may average it, and an RC filter can turn it into a smoother voltage.

Load Experience with PWM/DAC

Change the duty cycle, frequency, supply voltage, and filter values. Watch the waveform and the load response change before you build anything.

What to try:

  • Set duty cycle to 25%, 50%, and 75%; notice how average voltage and LED brightness change.
  • Switch to PWM + RC filter, then increase capacitance; the output gets smoother but responds more slowly.
  • Lower PWM frequency below the filter cutoff; the ripple warning should appear.
  • Switch to True DAC and compare the stable blue voltage level with the PWM pulses.

Voltage VeraCheckpoint: What the Load Sees

You now know:

  • PWM duty cycle sets average voltage, but the raw pin is still switching between LOW and HIGH.
  • LEDs and motors can tolerate or naturally average PWM; audio and precision references usually need cleaner DAC behavior.
  • RC filtering trades ripple for response time, so a smoother voltage also settles more slowly.


33.6 Arduino DAC/PWM Implementation

With the behavior visible, implementation is easier to judge: Arduino starts from PWM, while ESP32 gives PWM plus two true DAC pins.

33.6.1 Arduino Uno (No True DAC)

Solution: Use PWM (Pulse Width Modulation) to simulate analog output

PWM Pins: 3, 5, 6, 9, 10, 11

Use this after you understand the simulator. It is not required for the no-hardware activity above.

// Fade LED using PWM (simulated DAC)
const int ledPin = 9;  // PWM-capable pin
int brightness = 0;

void setup() {
    pinMode(ledPin, OUTPUT);
}

void loop() {
    analogWrite(ledPin, brightness);  // 0-255
    brightness = (brightness + 5) % 256;
    delay(30);
}

PWM Characteristics:

Use the example as a sequence from setup to observable result: Resolution: 8-bit (0-255). Frequency: ~490 Hz (pins 3,9,10,11) or ~980 Hz (pins 5,6). Not true analog but works for LEDs, motors.

33.6.2 ESP32 (True DAC)

DAC Pins: GPIO25, GPIO26

This is useful for Wokwi or real ESP32 hardware. The simulator above shows the same voltage calculation without requiring hardware.

// True analog output on ESP32
void setup() {
    // No setup needed for DAC
}

void loop() {
    // Output ~1.66V on DAC channel 1 (GPIO25)
    dacWrite(25, 128);  // 0-255, Vref = 3.3V
    // 128/255 * 3.3V = 1.66V
}
Try It: ESP32 DAC Output Simulation

If you want a hardware-style simulator after using the in-page simulator, launch Wokwi and test the DAC example directly in a full browser tab:

Open Wokwi ESP32 Workspace Open Wokwi ESP32 Guide

Challenge: Generate a smooth voltage sweep from 0V to 3.3V

Steps:

  1. Open the ESP32 workspace and create a new blank project
  2. Paste the DAC example from this chapter into the sketch
  3. Add code in the loop: dacWrite(25, value) where value sweeps from 0 to 255
  4. Connect GPIO25 to an LED with 220Ω resistor (observe smooth brightness change)
  5. Verify the voltage formula: Vout=value255×3.3VV_{out} = \frac{value}{255} \times 3.3V
  6. For value=128: Vout=128255×3.3V1.66VV_{out} = \frac{128}{255} \times 3.3V \approx 1.66V (measure with multimeter in simulation)
  7. Compare this smooth DAC output to PWM’s rapid on/off switching

What to observe: True DAC provides genuine analog voltage with no high-frequency switching, ideal for audio and precision applications where PWM ripple would cause problems.


33.7 PWM as Pseudo-DAC

Most microcontrollers lack true DACs but use PWM (Pulse Width Modulation) to simulate analog output.

How PWM Works:

  • Rapidly toggle digital output between 0V and 5V
  • Duty cycle (% time HIGH) determines average voltage
  • Low-pass filter smooths PWM to quasi-analog signal

PWM Formula:

Vaverage=Vhigh×Duty Cycle100%V_{average} = V_{high} \times \frac{\text{Duty Cycle}}{100\%}

Example: 50% Duty Cycle at 5V

Vaverage=5V×0.5=2.5VV_{average} = 5V \times 0.5 = 2.5V

PWM Specifications:

  • Resolution: Arduino Uno = 8-bit (0-255); ESP32 = 8-16 bit. Typical use: motor speed control and LED dimming.
  • Frequency: Arduino Uno = 490-980 Hz; ESP32 = 1 Hz to 312 kHz at 8-bit resolution. Typical use: audio-oriented PWM usually needs >20 kHz to avoid audible whine.
  • Channels: Arduino Uno = 6; ESP32 = 16. Typical use: multiple motors or LED channels at the same time.

Resolution, frequency, and channel count decide whether a design stays simple or needs extra hardware.

33.7.1 Interactive: PWM & DAC Calculator

Use the sliders below to explore how duty cycle, supply voltage, and DAC input value affect output voltage.

PWM Duty Cycle & DAC Output Calculator

33.8 PWM to Analog Conversion (RC Filter)

For smooth analog output, add RC low-pass filter:

fcutoff=12πRCf_{cutoff} = \frac{1}{2\pi RC}

Example: Smoothing 1 kHz PWM for motor control

  • Choose fcf_c = 100 Hz (10x below PWM frequency)
  • Use R = 10k ohm, solve for C:

C=12π×10000Ω×100Hz=0.159μF0.22μFC = \frac{1}{2\pi \times 10000\Omega \times 100\text{Hz}} = 0.159\mu\text{F} \approx 0.22\mu\text{F}

Result: The ideal 100 Hz design gives 0.159uF. A common 0.22uF capacitor with 10k ohm resistance gives about 72 Hz cutoff, which is still low enough to smooth a 1 kHz PWM signal but responds more slowly.

RC Filter Design Guidelines:

  • f_cutoff should be 10-20x below PWM frequency
  • Higher cutoff = faster response, more ripple
  • Lower cutoff = slower response, smoother output
  • Settling time = 5 x RC (to reach 99% of target)

Voltage VeraCheckpoint: PWM Filtering

You now know:

  • A 75% duty cycle on 5V PWM averages to 3.75 V before losses and filtering details.
  • For a 1 kHz PWM example, a 100 Hz cutoff target keeps the filter well below the switching frequency.
  • A 0.22uF capacitor with 10k ohm gives about 72 Hz cutoff and a slower but smoother output.

33.8.1 Interactive: RC Filter Design Calculator

PWM Low-Pass Filter Calculator

33.9 Hands-On Labs

The labs turn the same formulas into measurement tasks: code value, expected voltage, and load behavior should agree.

33.9.1 Lab 1: DAC Output with ESP32

Objective: Generate analog voltages using ESP32’s built-in DAC.

Materials:

Use the example as a sequence from setup to observable result: ESP32 development board. LED with 220 ohm resistor. Multimeter. Jumper wires.

Circuit:

Use the example as a sequence from setup to observable result: DAC output: GPIO25 or GPIO26. LED anode → 220 ohm resistor → GPIO25. LED cathode → GND.

void setup() {
    // DAC channels: 25 and 26
    Serial.begin(115200);
}

void loop() {
    // Sweep from 0V to 3.3V
    for (int i = 0; i <= 255; i += 5) {
        dacWrite(25, i);  // 8-bit DAC (0-255)

        float voltage = (i / 255.0) * 3.3;
        Serial.print("DAC Value: ");
        Serial.print(i);
        Serial.print(" | Voltage: ");
        Serial.print(voltage);
        Serial.println("V");

        delay(100);
    }
}

Measurements:

Use the example as a sequence from setup to observable result: Use multimeter to verify output voltage. Observe LED brightness changes smoothly. Calculate: V_out = (DAC_value / 255) x 3.3V.

Expected Learning:

Use the example as a sequence from setup to observable result: DAC converts digital to analog; 8-bit resolution (256 steps). Smooth voltage transitions.


33.9.2 Lab 2: PWM LED Dimming with Arduino

Objective: Use PWM to smoothly dim an LED and observe the relationship between duty cycle and perceived brightness.

Materials (or simulate in TinkerCAD / Wokwi):

  • Arduino Uno
  • 1x LED (any color)
  • 1x 220 ohm resistor
  • Jumper wires

Circuit:

  • LED anode → 220 ohm resistor → Pin 9 (PWM)
  • LED cathode → GND
const int ledPin = 9;  // PWM pin

void setup() {
    pinMode(ledPin, OUTPUT);
    Serial.begin(9600);
}

void loop() {
    // Sweep brightness up
    for (int duty = 0; duty <= 255; duty += 5) {
        analogWrite(ledPin, duty);

        float dutyCyclePct = (duty / 255.0) * 100.0;
        float avgVoltage = (duty / 255.0) * 5.0;

        Serial.print("PWM: ");
        Serial.print(duty);
        Serial.print(" | Duty: ");
        Serial.print(dutyCyclePct, 1);
        Serial.print("% | V_avg: ");
        Serial.print(avgVoltage, 2);
        Serial.println("V");

        delay(50);
    }

    // Sweep brightness down
    for (int duty = 255; duty >= 0; duty -= 5) {
        analogWrite(ledPin, duty);
        delay(50);
    }
}

Expected Learning:

Use the example as a sequence from setup to observable result: PWM duty cycle controls average voltage and perceived brightness; 8-bit resolution gives 256 brightness levels. Human eye perceives brightness logarithmically, so linear PWM steps appear nonlinear.


33.10 Common Pitfalls

These mistakes happen when a design assumes ideal DAC accuracy, ignores PWM frequency, or forgets what the load averages.

DAC Resolution vs Accuracy

The Mistake: Assuming an 8-bit DAC with a 3.3V reference produces exact voltages at every step (e.g., expecting exactly 1.650V for value 128).

Why It Happens: The formula Vout=Vref×D/(2n1)V_{out} = V_{ref} \times D / (2^n - 1) gives the ideal voltage, but real DAC output is affected by integral nonlinearity (INL), differential nonlinearity (DNL), offset error, and gain error. An 8-bit DAC has 12.9 mV steps at 3.3V, but typical INL of +/-1 LSB means actual output can deviate by +/-12.9 mV from the ideal.

The Fix: Check the DAC IC datasheet for INL and DNL specifications. For precision applications, use a higher-resolution DAC (12-bit or 16-bit) and calibrate against a known reference voltage. ESP32 built-in DAC has approximately +/-1% accuracy without calibration.

Rule of Thumb: Usable accuracy is typically 2-3 bits fewer than advertised resolution once all error sources are combined.

PWM Frequency Too Low

The Mistake: Using the default Arduino PWM frequency (490 Hz on most pins) for motor control, resulting in audible motor whine, or for LED dimming causing visible flicker in video recordings.

Why It Happens: The default frequency is a compromise that works for basic demos but is too low for many real applications. Cameras recording at 30-60 fps can capture individual PWM cycles, and human hearing extends to ~20 kHz.

The Fix: Increase PWM frequency to match the application:

  • LED dimming: >200 Hz for flicker-free to human eye; >1 kHz for flicker-free on camera
  • DC motor control: >20 kHz (ultrasonic) to eliminate audible whine
  • Servo motors: Fixed at 50 Hz (industry standard), do not change

On ESP32, use ledcSetup(channel, freq, resolution) to set custom PWM frequency. On Arduino Uno, modify timer prescaler registers.

Rule of Thumb: Use the highest PWM frequency your hardware supports, keeping in mind that higher frequency reduces effective resolution.


DACs are like translators who speak the language of motors and lights!

33.10.1 Reverse Translator Story

the microcontroller had a new challenge. “I know the motor needs to spin at 50% speed, and I can think in numbers like 128 out of 255. But the motor only understands smooth voltage, not step-numbers!”

the LED agreed. “Same for me! I want to glow at half brightness, but I need a smooth amount of power, not a number!”

That is when DAC Danny showed up. “I am the opposite of ADC Andy! Andy translates smooth signals INTO numbers for Max. I translate numbers FROM Max back into smooth signals for motors and LEDs!”

the battery was impressed. “So you are a reverse translator!”

Danny smiled. “Exactly! When Max says 128, I convert that into 1.65 volts — just the right amount to make Lila glow at half brightness.”

But Temperature Terry noticed something. “Wait, Danny, you are not on every microcontroller. What happens when you are not around?”

Danny pointed to his friend PWM Pete. “Pete has a clever trick! He blinks the power ON and OFF really, really fast. If he is ON half the time and OFF half the time, the average power is 50% — and it happens so fast that Lila cannot even tell she is blinking!”

Lila blinked. “I had no idea! I thought I was glowing smoothly this whole time!”

33.10.2 Key Words for Kids

WordWhat It Means
DACA reverse translator that turns numbers into smooth voltage
PWMBlinking power ON and OFF so fast it looks smooth
Duty CycleHow much of the time the power is ON (50% = half the time)
Motor ControlChanging how fast a motor spins using voltage
LED DimmingMaking a light brighter or dimmer

33.10.3 Try This at Home!

The Blinking Brightness Game!

  1. Get a flashlight and a dark room
  2. Turn the flashlight ON for 1 second, then OFF for 1 second. Repeat. (That is 50% duty cycle — but you can SEE the blinking!)
  3. Now try blinking it ON for half a second, OFF for half a second. Faster!
  4. Keep going faster and faster until you cannot see the blinks anymore

What you learned: When blinking is fast enough, your eyes blend it into steady light. That is exactly how PWM works — it blinks so fast (hundreds of times per second) that LEDs and motors respond smoothly!

ESP32 DAC: Digital to 2.59V

The big picture: A DAC is the reverse of an ADC - it uses an R-2R resistor ladder to convert an 8-bit digital value (0-255) into a proportional analog voltage (0-3.3V).

Step-by-step breakdown:

  1. Digital Input: Code calls dacWrite(25, 200) - 200 in binary is 11001000 - Real example: ESP32 GPIO25 DAC receives this 8-bit value
  2. Resistor Ladder: Each bit switches a 2R resistor to either Vref or ground, creating weighted currents - Real example: Bit 7 (MSB) contributes Vref/2 = 1.65V, bit 6 contributes Vref/4 = 0.825V, and so on with each successive bit halving
  3. Summing Amplifier: Op-amp sums all bit contributions to produce output voltage - Real example: V_out = 3.3V × (200/255) = 2.59V

Why this matters: Understanding that PWM average voltage (3.75V at 75% duty cycle) requires RC filtering to become smooth DC explains why motors work with PWM directly (coil inductance acts as filter) but audio needs a true DAC.

DAC/PWM Actuator Control
  • DAC Resolution (8-bit) -> ADC Resolution: Both use the same 2n2^n idea. An 8-bit DAC has 256 output levels, while a 12-bit ADC has 4,096 input levels.
  • PWM Duty Cycle -> Motor Speed Control: Average voltage is Vhigh×duty_cycleV_{high} \times duty\_cycle, so motors respond to the average energy delivered, not each individual pulse.
  • RC Filter Cutoff Frequency -> Sampling Theory: The filter cutoff should usually sit about 10x below the PWM frequency so ripple is smoothed before the load sees it.

Cross-module connection: PWM Actuator Control - Explains how DC motors respond to PWM average voltage via back-EMF and inductance

Voltage VeraCheckpoint: Choosing DAC or PWM

You now know:

  • Use true DAC output for audio, instrumentation, references, and analog circuits expecting clean DC levels.
  • Use PWM when the load averages pulses: LEDs, motors, heaters, servos, and many multi-channel outputs.
  • ESP32 has 2 DAC pins but 16 PWM-capable GPIOs, so channel count often decides the practical route.

33.11 Continue to the Next Part

Carry this evidence into DAC and PWM: Actuator Selection and Validation, which begins with Key Takeaway.