Программирование ARM ESP32 ADC Fri, December 13 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


ESP32 ADC Печать
Добавил(а) microsin   

На кристалле ESP32 MCU интегрировано 2 блока АЦП (ADC), работающих по принципу последовательного приближения (Successive Approximation Register, SAR). Эти два АЦП поддерживают до 18 каналов, которые могут быть направлены на определенные ножки MCU.

Примечание: в этой статье приведен перевод главы, посвященной ADC из документации [1]. Незнакомые термины и сокращения см. в Словарике, в конце статьи.

[Основные возможности ADC]

ADC1: поддерживает 8 каналов (GPIO32 - GPIO39).
ADC2: поддерживает 10 каналов (GPIO0, GPIO2, GPIO4, GPIO12 - GPIO15, GOIO25 - GPIO27).

Таблица 1. Характеристики ADC.

Аттенюация Условия min MAX Ед.
DNL (дифференциальная нелинейность) Контроллер RTC, ко входу ADC подключен конденсатор 100 нФ, сигнал на входе подается по постоянному току, температура окружающей среды 25°C, блоки Wi-Fi и Bluetooth выключены. -7 7 LSB(1)
INL (интегральная нелинейность) -12 12
Частота выборок (sample rate) Контроллер RTC - 200 ksps
Контроллер DIG - 2 Msps

Примечание (1): вес младшего разряда.

Когда аттенюация == 3 (ADC_ATTEN_DB_11), и результат чтения АЦП больше 3000 (напряжение достигло 2450 mV), точность ADC будет хуже, чем представлено в таблице 1.

Чтобы получить лучшие параметры DNL, пользователь может произвести несколько измерений сигнала, пропущенных через входной фильтр, либо вычислить среднее значение от нескольких выборок сигнала.

Диапазон входного напряжения ножек GPIO в домене VDD3P3_RTC должно строго соответствовать уровням напряжения питания (например, от 0 до 3.3V). Иначе будут наблюдаться ошибки измерений, и может ухудшиться производительность чипа.

По умолчанию между разными экземплярами чипа могут быть ±6% различий в результатах чтения АЦП. Библиотеки ESP-IDF предоставляют набор методов калибровки для ADC1. В качестве примера в таблице 2 приведены результаты измерения с использованием коэффициентов калибровки eFuse Vref. Для повышения точности пользователи могут применить другие методы калибровки, предоставленные в ESP-IDF, либо реализовать собственные методы калибровки.

Таблица 2. Результаты калибровки ADC. В столбце "Ошибка" приведено значение отклонения в милливольтах результата измерения от действительного значения.

Аттенюация Ошибка, mV
ADC_ATTEN_DB_0 ±23
ADC_ATTEN_DB_2_5 ±30
ADC_ATTEN_DB_6 ±40
ADC_ATTEN_DB_11 ±60

Ослабление по входу ADC. Входные уровни напряжений оцифровываются по отношению к внутреннему опорному напряжению Vref. Таким образом, диапазон входных измеряемых уровней напряжения составляет от 0V до Vref. На разных экземплярах кристаллов Vref может варьироваться, среднее значение Vref составляет 1.1V. Чтобы можно было преобразовывать входные напряжения, превышающие Vref, уровни на входе должны быть уменьшены. Существует 4 опции уменьшения уровней (attenuation), чем больше ослабление, тем больше может быть уровень измеряемого напряжения на входе АЦП.

Таблица 3. Опции ослабления (аттенюации) уровней на входе АЦП.

Аттенюация Измеряемый диапазон входных уровней (mV)
ADC_ATTEN_DB_0 100 .. 950
ADC_ATTEN_DB_2_5 100 .. 1250
ADC_ATTEN_DB_6 150 .. 1750
ADC_ATTEN_DB_11 150 .. 2450

Преобразование ADC. Это процесс преобразования уровня сигнала в цифровое значение. Результаты преобразования предоставляются API-функциями драйвера ADC в виде сырых данных. Разрешающая способность ESP32 ADC в режиме Single Read составляет 12 бит. Для преобразования используются функции adc1_get_raw и adc2_get_raw.

Для вычисления реального напряжения на основе сырого результата, предоставленного ADC, можно использовать формулу:

Vout = Dout * Vmax / Dmax                       (Формула 1)

Здесь Vout это результат измерения напряжения (в милливольтах), Dout сырой цифровой результат преобразования АЦП, Vmax максимальное измеряемое напряжение на входе (см. выше секцию "Ослабление по входу ADC"). Dmax максимальный сырой результат преобразования АЦП (который в режима Single Read и Continuous Read равен 212 - 1 = 4095).

Для плат, у которых есть биты калибровки eFuse ADC, может использоваться функция esp_adc_cal_raw_to_voltage для получения калиброванных результатов преобразования. Это результаты будут реальным напряжением (в mV). Нет необходимости преобразовывать эти данные по формуле 1. Если API-функции калибровки используются на платах, где нет бит калибровки eFuse ADC, будут генерироваться предупреждения, см. секцию "Калибровка ADC".

Дополнительную информацию по использованию АЦП см. в главе "On-Chip Sensors and Analog Signal Processing" технического руководства ESP32 (ESP32 Technical Reference Manual, esp32_technical_reference_manual_en.pdf).

[Ограничения ADC]

Не могут свободно использоваться некоторые ножки ADC2, на которых совмещена функция управления загрузкой (strapping pins GPIO0, GPIO2, GPIO15). Такой случай имеет место на следующих официальных платах разработчика (Development Kits):

ESP32 DevKitC: GPIO0 не может использоваться из-за внешних схем автоматического программирования.
ESP-WROVER-KIT: GPIO0, GPIO2, GPIO4 и GPIO15 не могут использоваться, потому что эти ножки используются внешними схемами для разных целей.

Поскольку модуль ADC2 также используется для Wi-Fi, одновременно можно использовать только одну из этих функций. Т. е. функция adc2_get_raw может блокировать выполнение до тех пор, пока не остановится использование Wi-Fi, и наоборот.

[Использование драйвера ADC]

Оба блока ADC поддерживают одиночный режим чтения (Single Read mode), который подойдет для низкочастотных оцифровок сигнала.

Примечание: чтение никуда не подключенных (висящих) входов ADC будут давать случайные результаты.

Single Read. Это режим одиночного чтения АЦП. Перед тем, как можно будет считывать результаты измерений, ADC должно быть сконфигурировано.

● Для ADC1 конфигурируется желаемая точность (precision) и ослабление (attenuation) с помощью вызова функций adc1_config_width и adc1_config_channel_atten.
● ADC2 конфигурируется ослабление с помощью функции adc2_config_channel_atten. Разрядность чтения (width) для ADC2 конфигурируется каждый раз при чтении результата.

Конфигурация ослабления осуществляется для каждого канала отдельно с помощью типов adc1_channel_t и adc2_channel_t, эти значения устанавливаются в качестве параметров для вышеупомянутых функций настройки ослабления.

Результаты преобразования считываются вызовами функций adc1_get_raw и adc2_get_raw. Ширина результата ADC2 должна быть установлена в параметре adc2_get_raw, вместо того, чтобы это настраивать функцией конфигурации.

Пример режима Single Read можно найти в папке peripherals/adc/single_read среди примеров ESP-IDF [4].

С помощью ADC1 также можно считывать внутренний датчик Холла (hall effect sensor) путем вызова специальной функции hall_sensor_read. Обратите внимание, что несмотря на то, чт датчик Холла внутренний для кристалла ESP32, для его чтения используются каналы 0 и 3 ADC1 (GPIO36 и GPIO39). Ничего не подключайте к этим выводам, и не меняйте их конфигурацию, иначе это может повлиять на измерение слабого сигнала от сенсора.

API предоставляет удобный способ конфигурирования ADC1 для чтения из режима ULP [5]. Для этого вызовите функцию adc1_ulp_enable, и затем установите точность (precision) и ослабление (attenuation), как обсуждалось выше.

Есть еще одна специальная функция adc_vref_to_gpio, которая используется для перенаправления внутреннего опорного напряжения Vref на ножку GPIO. Это удобно для калибровки ADC, и обсуждается в секции "Калибровка ADC".

Минимизация шума. ESP32 ADC может быть чувствителен к шуму, что приводит к большим расхождениям между отдельными результатами чтения ADC. В зависимости от сценария использования можно подключить на входную ножку ADC блокирующий конденсатор (например керамический конденсатор на 100 нФ). Кроме того, для уменьшения эффектов от шума может использоваться техника передискретизации и усреднения (multisampling, также см. [6]).

adc noise graph

Рис. 1. График, иллюстрирующий уменьшение шума с помощью конденсатора на входе и усреднения 64 выборок.

[Калибровка ADC]

Заголовок esp_adc_cal/include/esp_adc_cal.h представляет API-функции для корректировки ошибок измерения из-за разброса уровня опорного напряжения (Vref) на разных кристаллах ESP32. Источник опорного напряжения был разработан на напряжение 1100 mV, однако в действительности этот уровень может быть в диапазоне от 1000 mV до 1200 mV.

adc vref graph

Рис. 2. График, показывающий эффект влияния различного напряжения Vref на результат оцифровки АЦП.

Коррекция результатов чтения ADC с помощью этого API включает в себя один из ADC на определенной аттенюации, с целью получить кривую характеристики (зависимость результат ADC - напряжение), которая учитывает неточность опорного напряжения. Кривая характеристики представляется в форме y = coeff_a * x + coeff_b, и она используется для преобразования сырых результатов чтения ADC в напряжения в mV. Вычисление кривой характеристики основано на значениях калибровки, которые можно сохранить в энергонезависимую память eFuse [9], или они могут быть предоставлены пользователем.

Значения калибровки. Эти значения используются для генерации кривой характеристики ADC, которая учитывает погрешность опорного напряжения каждого конкретного кристалла ESP32. На ESP32 существует 3 источника значений калибровки. Доступность этих значений калибровки зависит от типа чипа/модуля ESP32 и даты его производства.

● Two Point. Это 2 значения (точки калибровки), каждое представляет собой результат чтения ADC для входных уровней 150 mV и 850 mV. Чтобы получить точные результаты калибровки, эти значения должны быть измерены пользователем и прошиты в eFuse BLOCK3.
● eFuse Vref. Это значение представляет реальное значение опорного напряжения ADC. Оно измеряется и прошивается в eFuse BLOCK0 при калибровке на заводе.
● Default Vref. Это опорное напряжение по умолчанию - оценка опорного напряжения ADC, предоставленная пользователем в качестве параметра во время вычисления характеристики. Если значения Two Point или eFuse Vref недоступны, то будет использоваться Default Vref.

Индивидуальное измерение и прошивка eFuse Vref было применено для чипов ESP32-D0WD и ESP32-D0WDQ6, которые произведены начиная с 1 недели 2018 года. Такие чипы можно распознать по кодам даты, которая равна или больше 012018, см. рис. 3. Здесь WW это код недели, YYYY код года изготовления.

chip surface marking

Рис. 3. Маркировка чипа ESP32.

Если Вы хотите купить чипы или модули с калибровкой, свяжитесь с дистрибьютором или напрямую с Espressif (sales@espressif.com).

Если Вы не можете проверить код даты (например, когда чип закрыт крышкой модуля), то все еще можете проверить наличие eFuse Vref путем запуска espefuse.py с параметром adc_info. Пример командной строки запуска espefuse.py в среде Linux (замените /dev/ttyUSB0 реальным именем последовательного порта подключенной через USB платы ESP32):

$IDF_PATH/components/esptool_py/esptool/espefuse.py --port /dev/ttyUSB0 adc_info

Примечание: как запускать скрипты администрирования на языке Python *.py в операционной системе Windows см. врезку "Как запустить idf.py menuconfig" из статьи [10]. Скрипт espefuse.py и другие скрипты запускаются аналогично.

Чип, у которого есть запрограммированное значение eFuse Vref (в этом примере 1093 mV) покажет следующее сообщение:

ADC VRef calibration: 1093 mV

Другой пример сообщения, когда значение eFuse Vref не запрограммировано:

ADC VRef calibration: None (1100 mV nominal)

Для чипа, у которого есть 2 точки калибровки, сообщение будет выглядеть примерно так:

ADC VRef calibration: 1149 mV
ADC readings stored in efuse BLK3:
    ADC1 Low reading  (150 mV): 306
    ADC1 High reading (850 mV): 3153
    ADC2 Low reading  (150 mV): 389
    ADC2 High reading (850 mV): 3206

Пример целиком см. в каталоге peripherals/adc/single_read установки среды разработки ESP-IDF [4].

Характеристика АЦП при определенной аттенюации:

#include "driver/adc.h"
#include "esp_adc_cal.h"
 
...
esp_adc_cal_characteristics_t *adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit,
                                                        atten,
                                                        ADC_WIDTH_BIT_12,
                                                        DEFAULT_VREF,
                                                        adc_chars);
// Проверка типа значения калибровки, используемого для характеристики ADC:
if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF)
   printf("eFuse Vref");
else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP)
   printf("Two Point");
else
   printf("Default");

Чтение ADC, затем преобразование результата чтения в напряжение:

#include "driver/adc.h"
#include "esp_adc_cal.h"
 
...
uint32_t reading =  adc1_get_raw(ADC1_CHANNEL_5);
uint32_t voltage = esp_adc_cal_raw_to_voltage(reading, adc_chars);

Направление опорного напряжения ADC на ножку GPIO, после чего оно может быть измерено вручную (для Default Vref):

#include "driver/adc.h"
 
...
esp_err_t status = adc_vref_to_gpio(ADC_UNIT_1, GPIO_NUM_25);
if (status == ESP_OK)
   printf("v_ref routed to GPIO\n");
else
   printf("failed to route v_ref\n");

Макросы назначения GPIO. Доступны макросы, предназначенные для указания номера GPIO канала ADC, или наоборот, например:

ADC1_CHANNEL_0_GPIO_NUM это номер ножки GPIO канала 0 ADC1.
ADC1_GPIOn_CHANNEL это номер канала ADC1 для ножки GPIOn.

[Справочник по API-функциям ADC]

API-функции ADC разделены на 3 категории:

● Драйвер ADC (заголовочный файл components/driver/include/driver/adc.h)
● Калибровка ADC (заголовочный файл components/esp_adc_cal/include/esp_adc_cal.h)
● Макросы назначения GPIO (GPIO Lookup Macros, заголовочный файл components/soc/esp32/include/soc/adc_channel.h)

Типы, используемые в API-функциях ADC, определены в заголовочном файле components/hal/include/hal/adc_types.h.

Таблица 4. Общее описание API-функций ADC.

Функция Описание
adc_power_on Разрешает работу блоков ADC.
adc_power_off Выключает блоки ADC.
adc_power_acquire Инкрементирует счетчик использования модуля ADC. ADC остается активным и получает питание, пока счетчик больше 0. Вызовите adc_power_release, когда завершили использование ADC.
adc_power_release Декрементирует счетчик использования модуля ADC. ADC остается активным и получает питание, пока счетчик больше 0. Вызовите эту функцию, когда завершили использование ADC.
adc1_pad_get_io_num Получение номера ножки GPIO, соответствующей определенному каналу ADC1.
adc1_config_channel_atten Устанавливает ослабление (attenuation) указанного канала ADC1, и конфигурирует его соответствующий вход GPIO. По умолчанию ослабление установлено 0 dB (ADC_ATTEN_DB_0).
adc1_config_width Конфигурирует разрядность выборок ADC1. Эта конфигурация затрагивает все каналы ADC1.
adc1_get_raw Считывает сырой результат преобразования ADC1 указанного канала.
adc_set_data_inv Установка инверсии данных указанного блока ADC.
adc_set_clk_div Установка источника тактирования ADC.
adc_set_data_width Конфигурирует разрядность выборок ADC.
adc1_ulp_enable Конфигурирует возможность использования ADC1 в режиме ULP.
adc2_pad_get_io_num Получает номер ножки GPIO для указанного канала ADC2.
adc2_config_channel_atten Конфигурирует канал ADC2, включая установку аттенюации. По умолчанию ослабление установлено 0 dB (ADC_ATTEN_DB_0).
adc2_get_raw Считывает сырой результат преобразования ADC2 указанного канала.
adc_vref_to_gpio Выводит опорное напряжение ADC1 или ADC2 на указанную ножку GPIO.
adc2_vref_to_gpio Выводит опорное напряжение ADC2 на указанную ножку GPIO.
adc_digi_initialize Инициализирует Digital ADC.
adc_digi_read_bytes Считывает байты Digital ADC через DMA.
adc_digi_start Запускает периферийные устройства Digital ADC и DMA. После этого начнет работать аппаратный опрос АЦП.
adc_digi_stop Останавливает периферийные устройства Digital ADC и DMA. После этого перестает работать аппаратный опрос АЦП.
adc_digi_deinitialize Отменяет инициализацию Digital ADC.
adc_digi_controller_configure Конфигурирует контроллер Digital ADC.
adc_set_i2s_data_source Устанавливает источник данных I2S.
adc_i2s_mode_init Инициализирует режим I2S ADC.
esp_adc_cal_check_efuse Проверяет, прошиты ли значения калибровки ADC в энергонезависимую память eFuse (опорное напряжение Vref или значения Two Point).
esp_adc_cal_characterize Опрос способа корректировки считываемого значения ADC (characterization).
esp_adc_cal_raw_to_voltage Преобразует результат чтения ADC в напряжение (единицы mV). Преобразование реализовано на основе характеристик ADC (см. функции esp_adc_cal_check_efuse и esp_adc_cal_characterize).
esp_adc_cal_get_voltage Выполняет чтение ADC и преобразует результат чтения в милливольты (mV). Эта функция считывает АЦП, затем преобразует сырое считанное значение в mV на основе предоставленных характеристик. Считываемый АЦП также определяется характеристиками.
hall_sensor_read Считывает значение с датчика Холла.

Полный справочник по API-функциям, макросам и структурам ADC см. в документации [1].

analogRead

Эта функция используется для получения сырого значения из регистра ADC для указанной ножки/канала ADC. Параметр pin задает вывод порта GPIO.

uint16_t analogRead (uint8_t pin);

analogReadMillivolts

Эта функция выдает значение в милливольтах на указанной ножке/канале ADC. Параметр pin задает вывод порта GPIO.

uint32_t analogReadMilliVolts (uint8_t pin);

analogReadResolution

Эта функция используется для установки разрешающей способности возвращаемого значения функции analogRead (разрядности результата в битах).

void analogReadResolution (uint8_t bits);

Параметр bits задает разрядность считываемого значения, диапазон значений 1 .. 16. Если функция analogReadResolution не используется, то будет действовать разрядность по умолчанию 12 (диапазон значений 0 .. 4096) для всех чипов, кроме ESP32-S3, у которого по умолчанию 13 бит (диапазон от 0 до 8192). Когда устанавливается другая разрешающая способность, считанные значения будут подвергаться сдвигу для получения указанной разрешающей способности.

Примечание: для ESP32 разрешающая способность в диапазоне 9 .. 12 соответствует аппаратным возможностям ADC, в этом случае считываемое значение берется как есть, без сдвига. Если для разрешающей способности используется другое значение, то результат чтения ADC сдвигается.

analogSetClockDiv

Эта функция используется для установки коэффициента деления тактовой частоты ADC. Параметр clockDiv задает коэффициент деления, диапазон значений 1 .. 255. По умолчанию используется коэффициент деления 1.

void analogSetClockDiv (uint8_t clockDiv);

analogSetAttenuation

Эта функция используется для установки коэффициента ослабления (attenuation) для всех каналов ADC.

void analogSetAttenuation (adc_attenuation_t attenuation);

Входные напряжения могут быть уменьшены перед тем, как попадут на вход ADC. Существует 4 доступные опции ослабления. Чем больше ослабление, тем может быть измерен более высокий уровень входного напряжения.

Диапазоны измеряемых входных напряжений отличаются для каждого чипа, см. таблицу ниже для получения подробной информации.

Аттенюация
Диапазон входных напряжений (mV)
ESP32 ESP32-S2, ESP32-C3 ESP32-S3
ADC_ATTEN_DB_0 100 .. 950 0 .. 750 0 .. 950
ADC_ATTEN_DB_2_5 100 .. 1250 0 .. 1050 0 .. 1250
ADC_ATTEN_DB_6 150 .. 1750 0 .. 1300 0 .. 1750
ADC_ATTEN_DB_11 150 .. 2450 0 .. 2500 0 .. 3100

analogSetPinAttenuation

Эта функция используется для установки ослабления (attenuation) для определенной ножки / канала ADC. Для дополнительной информации см. выше описание функции analogSetAttenuation.

void analogSetPinAttenuation (uint8_t pin, adc_attenuation_t attenuation);

adcAttachPin

Эта функция используется для подсоединения ножки порта к ADC (она также очистит любой аналоговый режим, который мог быть включен). Функция вернет true, если конфигурация была успешной, иначе вернет false.

bool adcAttachPin (uint8_t pin);

analogSetWidth

Используется для установки аппаратной разрешающей способности ADC. По умолчанию разрядность (разрешающая способность) ADC составляет 12 бит (диапазон считываемых значений 0 .. 4095). Параметр bits устанавливает разрядность в диапазоне 9 .. 12 бит.

void analogSetWidth (uint8_t bits);

analogSetVRefPin

Эта функция используется для установки ножки порта, используемой для калибровки ADC, если оно еще не было откалибровано (ножки 25, 26 или 27).

void analogSetVRefPin (uint8_t pin);

hallRead

Эта функция используется для получения значения ADC от датчика Холла, подключенного к выводам 36 (SVP) и 39 (SVN).

int hallRead ();

[Пример приложения]

Ниже приведен простой скетч Arduino, демонстрирующий работу с ADC.

void setup()
{
   // Инициализация последовательного обмена данными на скорости 115200 бит/сек:
   Serial.begin(115200);
  
   // Установка разрешающей способности ADC на 12 бит (0 .. 4096):
   analogReadResolution(12);
}
 
void loop()
{
   // Чтение сырого значения на ножке 2:
   int analogValue = analogRead(2);
   Serial.printf("ADC analog value = %d\n", analogValue);
   // Чтение значения напряжения в милливольтах на ножке 2:
   int analogVolts = analogReadMilliVolts(2);
   Serial.printf("ADC millivolts value = %d\n", analogVolts);
  
   // Задержка между измерениями для их комфортного чтения
   // через консоль Serial Monitor:
   delay(100);
}

[Словарик]

ADC Analog to Digital Converter, аналого-цифровой преобразователь (АЦП).

DIG DIGital, цифровой. В контексте ADC имеется в виду специальный контроллер для управления АЦП (Digital ADC).

DNL Differential Non-Linearity, дифференциальная нелинейность.

INL Integral Non-Linearity, общая нелинейность.

LSB Least Significant Bit, самый младший бит.

MCU MicroController Unit, микроконтроллер.

RTC Real Time Clock, блок часов реального времени.

SAR Successive Approximation Register, принцип работы АЦП - регистр последовательного приближения

ULP Ultra Low Power, сверхнизкое энергопотребление.

[Ссылки]

1. ESP32 Analog to Digital Converter (ADC) site:docs.espressif.com.
2. Arduino-ESP32 ADC API site:docs.espressif.com.
3. ESP32 Pinout Reference: Which GPIO pins should you use? site:randomnerdtutorials.com.
4. Установка среды разработки ESP-IDF для ESP32.
5. ULP Coprocessor programming site:docs.espressif.com.
6. Улучшение оцифровки с помощью передискретизации и усреднения.
7. Working with ESP32 Audio Sampling site:toptal.com.
8. ESP32 ADC not good enough for audio/music? site:electronics.stackexchange.com.
9. ESP32 eFuse Manager.
10. ESP-IDF FreeRTOS Task API.
11ESP32: оцифровка звука.

 

Добавить комментарий


Защитный код
Обновить

Top of Page