Embedded HandbookApps
All sections › XVIII. ESP32: the second microcontroller
ESP32 · level intermediate · 14 min read
Open in the interactive handbook

154. ESP32 ADC and DAC: attenuation, calibration, ADC2 and Wi-Fi, continuous mode, DAC and cosine

The STM32 ADC from section 14 is 12 bits, the reference equals the supply, the accuracy is on the order of one LSB, and the formula "code × 3.3 / 4096" works. The ESP32 ADC is also 12 bits and also successive approximation, but its reference is internal and different on every die, the input does not cover the whole supply range, and the linearity is such that without calibration the error is measured in tens of millivolts. Hence everything in this section: four attenuation windows, calibration from eFuse, a second ADC that goes off together with Wi-Fi, and two eight-bit DACs with a cosine generator. The driver logic is checked by QEMU (_verify/esp154/), the numbers by the datasheet (the excerpt datasheet_adc.txt) and the ESP-IDF headers, the arithmetic by a Python model.

Terms used in the documentation

Term Meaning
SAR ADC successive approximation ADC
attenuation (0 / 2.5 / 6 / 12 dB) input attenuation: widens the measured window
effective measurement range the window where accuracy is promised
calibration, line fitting, two point calibration: along a line or by two points
Vref, eFuse Vref the ADC reference and its value written to eFuse
DNL, INL differential and integral nonlinearity
total error the full error after calibration
oneshot / continuous mode a single read / a stream through DMA
RTC controller / DIG controller the ADC controller for single reads / for streaming
conversion frame a frame of DMA results
DAC, cosine wave generator the DAC, the cosine generator

154.1 Two blocks, 18 channels, and where they are

ADC1: ch0=GPIO36 ch1=GPIO37 ch2=GPIO38 ch3=GPIO39 ch4=GPIO32 ch5=GPIO33 ch6=GPIO34 ch7=GPIO35
ADC2: ch0=GPIO4 ch1=GPIO0 ch2=GPIO2 ch3=GPIO15 ch4=GPIO13 ch5=GPIO12 ch6=GPIO14 ch7=GPIO27 ch8=GPIO25 ch9=GPIO26

The channels are tied to the pins rigidly — the GPIO matrix from section 153 does not extend to analog signals. ADC1 sits on inputs 32–39: six of them are inputs only, which is just what an ADC needs. ADC2 is scattered over pins 0–27, among them three strapping pins (0, 2, 15) and both DAC outputs (25, 26). And most importantly: ADC2 does not work while Wi-Fi is on — the radio uses the same block to measure its own power. For a product with Wi-Fi you are left with ADC1: the bare chip has eight channels, and the WROOM-32 module has six (GPIO32–36 and 39): pins 37 and 38 are not on the module.

The ESP32 ADC: attenuation selects the input window, the 12-bit SAR produces a code, calibration by the Vref from eFuse turns the code into millivolts; ADC2 is switched off by the radio


154.2 Attenuation: four windows

The ADC reference is about 1.1 V inside the chip, and without attenuation the input measures up to roughly 1 V. To measure up to 3.3 V, a divider with an attenuation of 2.5, 6 or 12 dB is placed in front of the ADC. The datasheet (table 4-4) promises accuracy only inside the windows:

Attenuation Window Total error after calibration
0 dB 100 … 950 mV ±23 mV
2.5 dB 100 … 1250 mV ±30 mV
6 dB 150 … 1750 mV ±40 mV
12 dB 150 … 2450 mV ±60 mV

Below 100–150 mV and above the upper limit the ADC works, but no accuracy is promised; at 12 dB above code 3000 (about 2450 mV) it is noticeably worse — this is a separate note of table 4-3. So ESP32 does not measure "3.3 V at the input" at all: an external divider is needed too. The nonlinearity per the same table is DNL up to ±7 and INL up to ±12 LSB, which is why averaging several samples is recommended. Each window has its own quantization step — it is the slope of the calibration line from 154.3 over codes 0…2048 (at 12 dB above code 2880 the driver switches to a table, and the curve bends). The accuracy window is narrower than the full code range, so you cannot divide the window by 4096:

3,3 В / 4096 = 0.806 мВ — так считать нельзя: шаг у окон разный, а прямая не проходит через ноль
0 дБ    окно  100… 950 мВ: шаг 0.235 мВ, ошибка после калибровки ±23 мВ = ±98 шагов
2,5 дБ  окно  100…1250 мВ: шаг 0.312 мВ, ошибка после калибровки ±30 мВ = ±96 шагов
6 дБ    окно  150…1750 мВ: шаг 0.432 мВ, ошибка после калибровки ±40 мВ = ±93 шагов
12 дБ   окно  150…2450 мВ: шаг 0.806 мВ, ошибка после калибровки ±60 мВ = ±74 шагов

At 12 dB the step coincides with 3.3 V / 4096, but the line is offset by 142 mV, so the formula "code × 0.806" lies there too.

An error of 75–100 steps at 12 bits means: there are 12 bits, but more than six of them are eaten by the error, and in absolute terms you can trust about five — that is ±2.5…2.7 % of the window. For a thermistor and a potentiometer this is enough, for a voltmeter it is not; there you use an external ADC over I²C or SPI. In ESP-IDF 5 the 11 dB attenuation is renamed to 12 dB, the old name ADC_ATTEN_DB_11 is marked deprecated and means the same thing.

The four attenuation windows of the ESP32 ADC on a scale up to 3.3 V: the limits, the error after calibration and the quantization step


154.3 Calibration: code → millivolts

Every die has its own reference, and at the factory it is measured and written to eFuse. The calibration driver reads eFuse and builds a code → voltage line; if eFuse is empty, it takes 1100 mV:

        adc_cali_line_fitting_config_t cfg = { .unit_id = ADC_UNIT_1, .atten = att, .bitwidth = ADC_BITWIDTH_12, .default_vref = 1100 };
        adc_cali_handle_t h = NULL;
        esp_err_t e = adc_cali_create_scheme_line_fitting(&cfg, &h);
калибровка 0 дБ ESP_OK:    0→  75 мВ 1000→ 310 мВ 2048→ 557 мВ 3000→ 781 мВ 4095→1039 мВ
калибровка 2,5 дБ ESP_OK:    0→  78 мВ 1000→ 390 мВ 2048→ 718 мВ 3000→1015 мВ 4095→1357 мВ
калибровка 6 дБ ESP_OK:    0→ 107 мВ 1000→ 539 мВ 2048→ 992 мВ 3000→1404 мВ 4095→1877 мВ
калибровка 12 дБ ESP_OK:    0→ 142 мВ 1000→ 948 мВ 2048→1792 мВ 3000→2543 мВ 4095→3134 мВ
eFuse калибровки: нет — Vref по умолчанию 1100 мВ

The line does not pass through zero: code 0 at 12 dB is already 142 mV, and 4095 is 3134 mV. This is how the driver accounts for the ADC offset and slope; your own formula "code × step" would give an error of hundreds of millivolts. The full 12 dB range reaches 3.1 V, but the promised accuracy ends at 2450 mV. adc_cali_raw_to_voltage is the only correct way to get volts; adc_cali_scheme_line_fitting_check_efuse tells you whether Vref or two points are written. In the emulator eFuse is empty, and the answer is "none".


154.4 Single read and streaming

A single read is three calls: adc_oneshot_new_unit, adc_oneshot_config_channel with attenuation and bit width, adc_oneshot_read. The first two pass in the emulator, the third does not:

adc_oneshot: блок и канал ADC1 ch6 (GPIO34) настроены; чтение ждёт флага готовности, которого в эмуляторе нет

QEMU does not model the ADC: the read waits for the "ready" flag forever, and after 300 ms the interrupt watchdog fires (section 152). So levels are checked only on a board, and everything else is checked in the emulator.

Continuous mode drives samples through DMA without the CPU — on ESP32 through the I²S controller, hence its limits:

непрерывный режим: 20000 … 2000000 Гц, 9…12 бит, кадр результата 2 байта
adc_continuous_config 10 кГц: ESP_ERR_INVALID_ARG
adc_continuous_config 20 кГц: ESP_OK
adc_continuous_config 2 МГц: ESP_OK
adc_continuous_config ADC2: ESP_ERR_INVALID_ARG

A stream cannot be slower than 20 kHz: if you want 1 kHz, you read single samples on a timer. Faster than 2 MHz is not possible either, and at 2 MHz it is 4 MB/s:

  20000 Гц × 2 байта = 40000 байт/с, кадр 256 байт — раз в 6.40 мс
2000000 Гц × 2 байта = 4000000 байт/с, кадр 256 байт — раз в 0.06 мс

A 256-byte frame at 2 MHz completes every 64 µs — the handler must keep up. ADC2 cannot be used for streaming at all (ESP_ERR_INVALID_ARG): only the first block has DMA. The datasheet gives the limits: 200 ksps through the RTC controller (single reads) and 2 Msps through the digital one.


154.5 What the ADC does in 12 steps

Successive approximation is 12 comparisons, one per bit: a Python model for an input of 1730 mV with a nominal reference of 2450 mV:

шаг  1: пробуем 2048 ( 1225.0 мВ) — оставляем
шаг  2: пробуем 3072 ( 1837.5 мВ) — сбрасываем
шаг  3: пробуем 2560 ( 1531.2 мВ) — оставляем
шаг 12: пробуем 2893 ( 1730.4 мВ) — сбрасываем
код 2892 = 0b101101001100, 1729.8 мВ, ошибка 0.17 мВ

Twelve steps of successive approximation for an input of 1730 mV: the trial voltage jumps around the input and the range halves each time; the result is code 2892

Each step sets the next bit, compares with the input and keeps or clears it; 12 steps are 12 ADC clock cycles, hence the speed limit. For an input of 1730 mV the error is 0.17 mV, 0.28 of a step (the step is 0.598 mV). An ideal ADC that, as here, discards the remainder errs by zero to one step, and the spread of the error over many inputs is step/√12 ≈ 0.29 of a step; a real one, as seen from 154.2, errs by almost a hundred steps. The ideal limit of the signal-to-noise ratio is 6.02·N + 1.76 dB:

 8 бит: SNR = 49.92 дБ
12 бит: SNR = 74.00 дБ

154.6 DAC: two channels and a cosine

dac_oneshot_output_voltage 128 (половина VDD): ESP_OK
dac_cosine 100 Гц: ESP_ERR_NOT_SUPPORTED
dac_cosine 1000 Гц: ESP_OK

Two 8-bit DACs on GPIO25 and GPIO26 — a resistor string with a buffer, the reference is the supply, so the step is 3.3 V / 256 ≈ 13 mV and there is no accuracy better than a percent. Three modes: a constant level (dac_oneshot), a stream from memory through DMA (dac_continuous) and the built-in cosine generator, which needs neither DMA nor the CPU: a frequency from about 130 Hz with the standard clock (the driver rejects 100 Hz), phase 0 or 180°, an offset and four amplitude steps. For sound and arbitrary waveforms use DMA, for testing the ADC or a simple generator use the cosine. The remark from section 15 still holds: the built-in buffer is weak, the DAC output is suitable for a high-impedance input, and anything that draws noticeable current (headphones, a long cable, a low-resistance divider) is connected through an external op-amp.


154.7 Practice: how to measure correctly

Task Solution
a 0–3.3 V sensor a divider down to 2.4 V, 12 dB attenuation, calibration
a thermistor, a potentiometer 12 dB, averaging of 16–64 samples
a 0–1 V signal 0 dB — the best accuracy
a ±0.5 % voltmeter an external ADC over I²C or SPI, the built-in one will not do
sound, vibration ADC1 continuous mode, 20 kHz and above
a product with Wi-Fi ADC1 only; ADC2 only with the radio off
a 1 MHz oscilloscope continuous mode up to 2 MHz, 4 MB/s into RAM

154.8 Pitfalls

Symptom Cause
ADC2 … ESP_ERR_TIMEOUT with Wi-Fi on ADC2 is taken by the radio; move to ADC1
code 4095 at 2.6 V the 12 dB window ends at 2450 mV; a divider is needed
"code × 0.806 mV" is off by 100–300 mV the reference is not 3.3 V and the line does not pass through zero; adc_cali_raw_to_voltage
the result jumps by tens of codes noise: the ADC's own noise, supply dips at Wi-Fi current peaks (section 161), a high-impedance source; 100 nF at the input, average 16–64 samples
the readings are steady but do not lie on a line DNL/INL: each code has its own constant error; multi-point calibration corrects it
adc_continuous_config → ESP_ERR_INVALID_ARG the frequency is below 20 kHz or the block is ADC2
ADC_ATTEN_DB_11 — a deprecation warning in ESP-IDF 5 it is ADC_ATTEN_DB_12, same behavior
dac_cosine → ESP_ERR_NOT_SUPPORTED the frequency is below ≈130 Hz with the standard clock
the ADC on GPIO25/26 "does not work" these are the DAC outputs, and as ADC inputs they belong to ADC2
adc_oneshot_read in QEMU — the interrupt watchdog the emulator does not model the ADC

154.9 Summary

Full sources

main.c — the ESP32 ADC and DAC: channels, line-fitting calibration, continuous mode, the cosine generator.

/* Раздел 154: АЦП и ЦАП ESP32 — каналы и выводы, калибровка «по прямой» без eFuse,
 * пределы непрерывного режима, ЦАП и генератор косинуса. Уровни на входах эмулятор не моделирует. */
#include <stdio.h>
#include "driver/dac_cosine.h"
#include "driver/dac_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "esp_adc/adc_continuous.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_err.h"
#include "esp_log.h"
#include "soc/soc_caps.h"

static const char *TAG = "adc154";

void app_main(void)
{
    /* какой канал на каком выводе */
    for (int unit = 0; unit < SOC_ADC_PERIPH_NUM; unit++) {
        printf("ADC%d:", unit + 1);
        for (int ch = 0; ch < SOC_ADC_CHANNEL_NUM(unit); ch++) {
            int io = -1;
            adc_oneshot_channel_to_io(unit, ch, &io);
            printf(" ch%d=GPIO%d", ch, io);
        }
        printf("\n");
    }

    /* калибровка по прямой: без записи Vref в eFuse берётся 1100 мВ */
    static const char *att_name[] = { "0 дБ", "2,5 дБ", "6 дБ", "12 дБ" };
    static const int raws[] = { 0, 1000, 2048, 3000, 4095 };
    for (int att = 0; att < SOC_ADC_ATTEN_NUM; att++) {
        adc_cali_line_fitting_config_t cfg = { .unit_id = ADC_UNIT_1, .atten = att, .bitwidth = ADC_BITWIDTH_12, .default_vref = 1100 };
        adc_cali_handle_t h = NULL;
        esp_err_t e = adc_cali_create_scheme_line_fitting(&cfg, &h);
        printf("калибровка %-6s %s:", att_name[att], esp_err_to_name(e));
        for (size_t i = 0; i < sizeof raws / sizeof raws[0]; i++) {
            int mv = -1;
            adc_cali_raw_to_voltage(h, raws[i], &mv);
            printf(" %4d→%4d мВ", raws[i], mv);
        }
        printf("\n");
        adc_cali_delete_scheme_line_fitting(h);
    }
    adc_cali_line_fitting_efuse_val_t ev;
    adc_cali_scheme_line_fitting_check_efuse(&ev);
    printf("eFuse калибровки: %s\n", ev == ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF ? "Vref" : ev == ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP ? "две точки" : "нет — Vref по умолчанию 1100 мВ");

    /* одиночное чтение: в эмуляторе входа нет */
    adc_oneshot_unit_handle_t adc1;
    adc_oneshot_unit_init_cfg_t ucfg = { .unit_id = ADC_UNIT_1 };
    ESP_ERROR_CHECK(adc_oneshot_new_unit(&ucfg, &adc1));
    adc_oneshot_chan_cfg_t ccfg = { .atten = ADC_ATTEN_DB_12, .bitwidth = ADC_BITWIDTH_12 };
    ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1, ADC_CHANNEL_6, &ccfg));
    printf("adc_oneshot: блок и канал ADC1 ch6 (GPIO34) настроены; чтение ждёт флага готовности, которого в эмуляторе нет\n");
    esp_err_t e;
    adc_oneshot_del_unit(adc1);

    /* непрерывный режим: пределы частоты дискретизации из soc_caps */
    printf("непрерывный режим: %d … %d Гц, 9…12 бит, кадр результата %d байта\n", SOC_ADC_SAMPLE_FREQ_THRES_LOW,
           SOC_ADC_SAMPLE_FREQ_THRES_HIGH, SOC_ADC_DIGI_RESULT_BYTES);
    adc_continuous_handle_t ch = NULL;
    adc_continuous_handle_cfg_t hcfg = { .max_store_buf_size = 1024, .conv_frame_size = 256 };
    ESP_ERROR_CHECK(adc_continuous_new_handle(&hcfg, &ch));
    adc_digi_pattern_config_t pat = { .atten = ADC_ATTEN_DB_12, .channel = ADC_CHANNEL_6, .unit = ADC_UNIT_1, .bit_width = ADC_BITWIDTH_12 };
    adc_continuous_config_t dcfg = { .pattern_num = 1, .adc_pattern = &pat, .sample_freq_hz = 10000,
                                     .conv_mode = ADC_CONV_SINGLE_UNIT_1, .format = ADC_DIGI_OUTPUT_FORMAT_TYPE1 };
    esp_log_level_set("adc_continuous", ESP_LOG_NONE);
    printf("adc_continuous_config 10 кГц: %s\n", esp_err_to_name(adc_continuous_config(ch, &dcfg)));
    dcfg.sample_freq_hz = 20000;
    printf("adc_continuous_config 20 кГц: %s\n", esp_err_to_name(adc_continuous_config(ch, &dcfg)));
    dcfg.sample_freq_hz = 2000000;
    printf("adc_continuous_config 2 МГц: %s\n", esp_err_to_name(adc_continuous_config(ch, &dcfg)));
    pat.unit = ADC_UNIT_2;
    dcfg.conv_mode = ADC_CONV_SINGLE_UNIT_2;
    printf("adc_continuous_config ADC2: %s\n", esp_err_to_name(adc_continuous_config(ch, &dcfg)));
    adc_continuous_deinit(ch);

    /* ЦАП: два канала по 8 бит на GPIO25/26, генератор косинуса */
    dac_oneshot_handle_t dac;
    dac_oneshot_config_t ocfg = { .chan_id = DAC_CHAN_0 };
    ESP_ERROR_CHECK(dac_oneshot_new_channel(&ocfg, &dac));
    printf("dac_oneshot_output_voltage 128 (половина VDD): %s\n", esp_err_to_name(dac_oneshot_output_voltage(dac, 128)));
    dac_oneshot_del_channel(dac);
    dac_cosine_handle_t cos;
    dac_cosine_config_t cc = { .chan_id = DAC_CHAN_1, .freq_hz = 100, .clk_src = DAC_COSINE_CLK_SRC_DEFAULT, .offset = 0, .phase = DAC_COSINE_PHASE_0,
                               .atten = DAC_COSINE_ATTEN_DEFAULT, .flags.force_set_freq = false };
    esp_log_level_set("dac_cosine", ESP_LOG_NONE);
    printf("dac_cosine 100 Гц: %s\n", esp_err_to_name(dac_cosine_new_channel(&cc, &cos)));
    cc.freq_hz = 1000;
    e = dac_cosine_new_channel(&cc, &cos);
    printf("dac_cosine 1000 Гц: %s\n", esp_err_to_name(e));
    if (e == ESP_OK) dac_cosine_del_channel(cos);
    ESP_LOGI(TAG, "done");
}

Next: section 155 — storage: NVS, SPIFFS, FAT, the partition table.

Open in the interactive handbook