154. АЦП и ЦАП ESP32: затухание, калибровка, ADC2 и Wi-Fi, непрерывный режим, ЦАП и косинус
АЦП STM32 из раздела 14 — 12 бит, опора равна питанию, точность
порядка младшего разряда, и формула «код × 3,3 / 4096» работает. АЦП
ESP32 — тоже 12 бит и тоже поразрядного уравновешивания, но опора у
него внутренняя и своя у каждого кристалла, вход не покрывает весь
диапазон питания, а линейность такая, что без калибровки ошибка
измеряется десятками милливольт. Отсюда всё в этом разделе: четыре
окна затухания, калибровка по eFuse, второй АЦП, который отключается
вместе с Wi-Fi, и два восьмибитных ЦАП с генератором косинуса. Логику
драйверов проверяет QEMU (_verify/esp154/), числа — даташит (выписка
datasheet_adc.txt) и заголовки ESP-IDF, арифметику — модель на Python.
Как это называется в документации
Оригинал Перевод SAR ADC АЦП поразрядного уравновешивания attenuation (0 / 2.5 / 6 / 12 dB) затухание на входе: расширяет измеряемое окно effective measurement range окно, где обещана точность calibration, line fitting, two point калибровка: по прямой или по двум точкам Vref, eFuse Vref опора АЦП и её значение, записанное в eFuse DNL, INL дифференциальная и интегральная нелинейность total error полная ошибка после калибровки oneshot / continuous mode одиночное чтение / поток через DMA RTC controller / DIG controller контроллер АЦП для одиночных чтений / для потока conversion frame кадр результатов DMA DAC, cosine wave generator ЦАП, генератор косинуса
154.1 Два блока, 18 каналов, и где они
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
Каналы привязаны к выводам жёстко — матрица GPIO из раздела 153 на аналоговые сигналы не распространяется. ADC1 сидит на входах 32–39: шесть из них только входы, что для АЦП и нужно. ADC2 разбросан по выводам 0–27, среди них три strapping-вывода (0, 2, 15) и оба выхода ЦАП (25, 26). И главное: ADC2 не работает, пока включён Wi-Fi — радио использует тот же блок для измерения своей мощности. Для изделия с Wi-Fi остаётся ADC1: у голого чипа восемь каналов, а у модуля WROOM-32 — шесть (GPIO32–36 и 39): выводов 37 и 38 на модуле нет.
154.2 Затухание: четыре окна
Опора АЦП — около 1,1 В внутри чипа, и без ослабления вход измеряет примерно до 1 В. Чтобы измерять до 3,3 В, перед АЦП ставят делитель с затуханием 2,5, 6 или 12 дБ. Даташит (таблица 4-4) обещает точность только внутри окон:
| Затухание | Окно | Полная ошибка после калибровки |
|---|---|---|
| 0 дБ | 100 … 950 мВ | ±23 мВ |
| 2,5 дБ | 100 … 1250 мВ | ±30 мВ |
| 6 дБ | 150 … 1750 мВ | ±40 мВ |
| 12 дБ | 150 … 2450 мВ | ±60 мВ |
Ниже 100–150 мВ и выше верхней границы АЦП работает, но точности не обещано; при 12 дБ выше кода 3000 (около 2450 мВ) она заметно хуже — это отдельная оговорка таблицы 4-3. Значит, «3,3 В на входе» ESP32 не измеряет вовсе: делитель нужен и снаружи. Нелинейность по той же таблице — DNL до ±7 и INL до ±12 младших разрядов, поэтому советуют усреднять несколько выборок. Шаг квантования у каждого окна свой — это наклон прямой калибровки из 154.3 на кодах 0…2048 (при 12 дБ выше кода 2880 драйвер переходит на таблицу, и кривая загибается). Окно точности уже, чем весь размах кодов, поэтому делить окно на 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 шагов
При 12 дБ шаг совпал с 3,3 В / 4096, но прямая сдвинута на 142 мВ, так что формула «код × 0,806» врёт и там.
Ошибка в 75–100 шагов при 12 битах означает: разрядов 12, но больше
шести из них съедает ошибка, и по абсолютному значению доверять можно
примерно пяти — это ±2,5…2,7 % окна. Для термистора и потенциометра этого
достаточно, для измерителя напряжения — нет; там ставят внешний АЦП по
I²C или SPI. В ESP-IDF 5 затухание 11 дБ переименовано в
12 дБ, старое имя ADC_ATTEN_DB_11 помечено устаревшим и означает то
же самое.
154.3 Калибровка: код → милливольты
Опора у каждого кристалла своя, и на заводе её измеряют и записывают в eFuse. Драйвер калибровки читает eFuse и строит прямую код → напряжение; если в eFuse пусто, берёт 1100 мВ:
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 мВ
Прямая не проходит через ноль: код 0 при 12 дБ — это уже 142 мВ, а
4095 — 3134 мВ. Так драйвер учитывает смещение и наклон АЦП; своя
формула «код × шаг» дала бы ошибку на сотни милливольт. Полный
диапазон 12 дБ доходит до 3,1 В, но обещанная точность кончается на
2450 мВ. adc_cali_raw_to_voltage — единственный правильный способ
получить вольты; adc_cali_scheme_line_fitting_check_efuse говорит,
записан ли Vref или две точки. В эмуляторе eFuse пуст, и ответ «нет».
154.4 Одиночное чтение и поток
Одиночное чтение — три вызова: adc_oneshot_new_unit,
adc_oneshot_config_channel с затуханием и разрядностью,
adc_oneshot_read. Первые два в эмуляторе проходят, третье — нет:
adc_oneshot: блок и канал ADC1 ch6 (GPIO34) настроены; чтение ждёт флага готовности, которого в эмуляторе нет
QEMU не моделирует АЦП: чтение ждёт флага «готово» вечно и через 300 мс срабатывает сторож прерываний (раздел 152). Поэтому уровни — только на плате, а в эмуляторе проверяется всё остальное.
Непрерывный режим гонит выборки через DMA без участия процессора — на ESP32 через контроллер I²S, поэтому и ограничения его:
непрерывный режим: 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
Медленнее 20 кГц поток не бывает: кто хочет 1 кГц, тот читает одиночно по таймеру. Быстрее 2 МГц — тоже нет, а на 2 МГц это 4 МБ/с:
20000 Гц × 2 байта = 40000 байт/с, кадр 256 байт — раз в 6.40 мс
2000000 Гц × 2 байта = 4000000 байт/с, кадр 256 байт — раз в 0.06 мс
Кадр в 256 байт при 2 МГц заканчивается каждые 64 мкс — обработчик
должен успевать. ADC2 в поток не берётся вовсе (ESP_ERR_INVALID_ARG):
DMA есть только у первого блока. Даташит называет пределы: 200 квыб/с
через контроллер RTC (одиночные чтения) и 2 Мвыб/с через цифровой.
154.5 Что делает АЦП за 12 шагов
Поразрядное уравновешивание — 12 сравнений, по одному на бит: модель на Python для входа 1730 мВ при условной опоре 2450 мВ:
шаг 1: пробуем 2048 ( 1225.0 мВ) — оставляем
шаг 2: пробуем 3072 ( 1837.5 мВ) — сбрасываем
шаг 3: пробуем 2560 ( 1531.2 мВ) — оставляем
шаг 12: пробуем 2893 ( 1730.4 мВ) — сбрасываем
код 2892 = 0b101101001100, 1729.8 мВ, ошибка 0.17 мВ
Каждый шаг ставит очередной бит, сравнивает с входом и оставляет или сбрасывает; 12 шагов — 12 тактов АЦП, отсюда и предел скорости. Для входа 1730 мВ ошибка — 0,17 мВ, 0,28 шага (шаг 0,598 мВ). Идеальный АЦП, который, как здесь, отбрасывает остаток, ошибается от нуля до шага, а разброс ошибки по многим входам — шаг/√12 ≈ 0,29 шага; настоящий, как видно из 154.2, ошибается почти на сотню шагов. Идеальный предел отношения сигнал/шум — 6,02·N + 1,76 дБ:
8 бит: SNR = 49.92 дБ
12 бит: SNR = 74.00 дБ
154.6 ЦАП: два канала и косинус
dac_oneshot_output_voltage 128 (половина VDD): ESP_OK
dac_cosine 100 Гц: ESP_ERR_NOT_SUPPORTED
dac_cosine 1000 Гц: ESP_OK
Два ЦАП по 8 бит на GPIO25 и GPIO26 — резистивная цепочка с буфером,
опора — питание, то есть шаг 3,3 В / 256 ≈ 13 мВ и никакой точности
выше процента. Три режима: постоянный уровень (dac_oneshot), поток
из памяти через DMA (dac_continuous) и встроенный генератор косинуса,
которому не нужен ни DMA, ни процессор: частота от примерно 130 Гц
при штатном тактировании (100 Гц драйвер отвергает), фаза 0 или 180°,
смещение и четыре ступени амплитуды. Для звука и произвольных форм —
DMA, для проверки АЦП или простого генератора — косинус. Замечание из
раздела 15 остаётся в силе: встроенный буфер слабый, выход ЦАП годится для
высокоомного входа, а всё, что берёт заметный ток (наушники, длинный кабель,
низкоомный делитель), подключают через внешний ОУ.
154.7 Практика: как измерять правильно
| Задача | Решение |
|---|---|
| датчик 0–3,3 В | делитель до 2,4 В, затухание 12 дБ, калибровка |
| термистор, потенциометр | 12 дБ, усреднение 16–64 выборок |
| сигнал 0–1 В | 0 дБ — лучшая точность |
| измеритель напряжения ±0,5 % | внешний АЦП по I²C или SPI, встроенный не годится |
| звук, вибрация | непрерывный режим ADC1, 20 кГц и выше |
| изделие с Wi-Fi | только ADC1; ADC2 — лишь при выключенном радио |
| осциллограф 1 МГц | непрерывный режим до 2 МГц, 4 МБ/с в ОЗУ |
154.8 Грабли
| Симптом | Причина |
|---|---|
ADC2 … ESP_ERR_TIMEOUT при включённом Wi-Fi |
ADC2 занят радио; переставить на ADC1 |
| код 4095 при 2,6 В | окно 12 дБ кончается на 2450 мВ; нужен делитель |
| «код × 0,806 мВ» врёт на 100–300 мВ | опора не 3,3 В и прямая не через ноль; adc_cali_raw_to_voltage |
| результат прыгает на десятки кодов | шум: собственный шум АЦП, провалы питания на пиках тока Wi-Fi (раздел 161), высокоомный источник; 100 нФ на входе, усреднять 16–64 выборки |
| показания ровные, но ложатся не на прямую | DNL/INL: ошибка у каждого кода своя и постоянная; поправляет калибровка по нескольким точкам |
adc_continuous_config → ESP_ERR_INVALID_ARG |
частота ниже 20 кГц или блок ADC2 |
ADC_ATTEN_DB_11 — предупреждение об устаревшем |
в ESP-IDF 5 это ADC_ATTEN_DB_12, поведение то же |
dac_cosine → ESP_ERR_NOT_SUPPORTED |
частота ниже ≈130 Гц при штатном тактировании |
| АЦП на GPIO25/26 «не работает» | это выходы ЦАП, а по АЦП — ADC2 |
adc_oneshot_read в QEMU — сторож прерываний |
эмулятор не моделирует АЦП |
154.9 Итоги
- Два блока: ADC1 на GPIO32–39 (8 каналов, у модуля WROOM-32 — 6), ADC2 на 0–27 (10); ADC2 выключен при Wi-Fi.
- Опора ≈1,1 В; окна 0 / 2,5 / 6 / 12 дБ до 950 / 1250 / 1750 / 2450 мВ; ошибка после калибровки ±23…±60 мВ, то есть 75–100 шагов из 4096: доверять можно примерно пяти разрядам.
- Калибровка по eFuse, иначе Vref 1100 мВ; прямая не через ноль: при 12 дБ код 0 → 142 мВ, 4095 → 3134 мВ.
- Поток: 20 кГц … 2 МГц, 9–12 бит, только ADC1 через DMA; 2 МГц — 4 МБ/с.
- SAR: 12 сравнений на отсчёт; идеальный SNR 74 дБ на 12 битах.
- ЦАП: 2 × 8 бит на GPIO25/26, шаг ≈13 мВ; косинус от ≈130 Гц без DMA.
Полные исходники
main.c — АЦП и ЦАП ESP32: каналы, калибровка по прямой, непрерывный режим, генератор косинуса.
/* Раздел 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");
}
Дальше: раздел 155 — хранение: NVS, SPIFFS, FAT, таблица разделов.