micropython-dac-salida-analogica

How to use the DAC in MicroPython to generate analog signals

  • 5 min

A DAC (Digital to Analog Converter) is a converter that transforms a digital value into a real analog voltage.

Until now, when we wanted to vary the intensity of an LED or the speed of a motor, we used PWM (Pulse Width Modulation). As we saw, PWM is a trick: we turn the pin on and off very fast to simulate an average voltage.

But what if we need a real analog voltage? What if we want to generate a smooth sine wave or control audio equipment?

To obtain that output we use the DAC (Digital to Analog Converter). Unlike PWM, which only switches between 0 V and 3.3 V, a DAC can deliver intermediate voltages.

Watch out for your board! Unlike PWM or ADC, which are present in almost all microcontrollers, the DAC is a luxury peripheral.

  • Original ESP32: Has two DAC channels, on pins 25 and 26. The ESP32-S2 offers them on pins 17 and 18; other members of the ESP32 family do not include this peripheral.
  • Pyboard: Has an integrated DAC, although it is controlled via pyb.DAC.
  • ESP8266 / Raspberry Pi Pico (RP2040): Do not have DAC hardware (you would need to use an external chip like the MCP4725).

How a DAC works

You can imagine the DAC as a staircase. We cannot generate infinite voltage levels, but rather a quantity determined by its resolution in bits.

In the case of the ESP32, the DAC has a resolution of 8 bits. This means we can divide the reference voltage (3.3V) into 256 steps.

  • Value 0 → 0 V
  • Value 128 → 1.65 V (approx)
  • Value 255 → 3.3 V

Each voltage “step” is approximately 12.9 mV.

Basic usage of the DAC on ESP32

Using the DAC in MicroPython is incredibly easy thanks to the machine.DAC class.

Let’s generate a static voltage of about 1.65V (half the range) on GPIO 25.

from machine import Pin, DAC

# Initialize the DAC on Pin 25
# On the ESP32, only Pin(25) or Pin(26) are allowed
dac25 = DAC(Pin(25))

# Write an 8-bit value (0-255)
dac25.write(128)
Copied!

If you connect a multimeter between pin 25 and GND, you will see a stable, continuous voltage. No pulses, no switching noise. Pure electrical silence.

Generating waveforms

The true power of the DAC appears when we change that value quickly over time. Let’s generate a sawtooth wave.

from machine import Pin, DAC
import time

dac = DAC(Pin(25))

while True:
    for i in range(256): # From 0 to 255
        dac.write(i)
        # No sleep to make it as fast as possible
Copied!

The speed problem

If you observe the output above with an oscilloscope, you will see the waveform, but you’ll notice the frequency is low. This is because Python, being interpreted, takes time to execute the for loop.

To generate complex waveforms like a sine wave, we need to calculate the values:

import math
from machine import Pin, DAC

dac = DAC(Pin(25))

# Pre-calculate the sine table to avoid slow math in the loop
buf = bytearray(100)
for i in range(len(buf)):
    # Convert sine (-1 to 1) to the DAC range (0 to 255)
    val = int(127.5 + 127.5 * math.sin(2 * math.pi * i / len(buf)))
    buf[i] = val

# Infinite loop playing the wave
while True:
    for val in buf:
        dac.write(val)
Copied!

Pre-calculating the values in a list or bytearray (a Lookup Table) is a standard technique in embedded systems to gain speed.

Limitations and peculiarities of the ESP32

Although the ESP32’s DAC is very useful, it’s good to know its limitations so you don’t get frustrated:

  1. 8-bit resolution: 256 steps is not enough for high-fidelity audio, but sufficient for basic voice or control signals.
  2. Non-linearity at the extremes: The ESP32’s DAC does not reach perfect 0V or 3.3V. It has a “dead zone” at the beginning (up to ~0.08V) and at the end (up to ~3.2V) where the output does not respond linearly.
  3. Noise: The output may have some digital noise coupled from the CPU.

What is this actually useful for?

You might wonder, what do I need a fixed 1.6V for?

  1. Audio Generation: You can connect a small amplifier and play 8-bit sounds (retro console style).
  2. Instrumentation Control: Many industrial devices are controlled with voltage signals (e.g., 0-10V, using an op-amp to amplify the ESP32 output).
  3. Bias: Setting a reference point for an external analog circuit.

Looking for high-quality audio? If you need to play MP3s or high-quality audio, the internal DAC will fall short. In that case, you should use the I2S protocol, which the ESP32 supports in hardware, connected to a specialized external DAC like the PCM5102.

This closes the basic cycle of inputs and outputs. We now know how to read the world (Digital inputs, ADC) and act upon it (Digital outputs, PWM, DAC). It’s time to start connecting more complex devices!