На кристалле чипа микроконтроллера ESP32-C3 интегрированы 2 аналого-цифровых преобразователя (Analog to Digital Converter, ADC, или по-нашему АЦП), работающие по принципу заполнения данными регистра с последовательным приближением (SAR, Successive Approximation Register). Эти АЦП 12-разрядные, и поддерживают вместе 6 каналов АЦП (внешние выводы, на которых разрешена работа считывания аналоговых уровней).
Имя
Количество каналов
Внешние выводы
ADC1
5
GPIO0 .. GPIO4
ADC2
1
GPIO5
Работа с аппаратными модулями АЦП осуществляется через библиотеку драйвера ADC системы программирования ESP-IDF [2].
[Ограничения ADC]
Аппаратные органичения. У микроконтроллера ESP32-C3 есть 2 блока АЦП:
typedefenum{ ADC_UNIT_1,///< SAR ADC 1 ADC_UNIT_2,///< SAR ADC 2
}adc_unit_t;
По входам АЦП (порты GPIO0 .. GPIO5) эти блоки АЦП распределены следующим образом:
GPIO
Блок АЦП
Канал АЦП
Аппаратная функция, вывод корпуса
GPIO0(1)
ADC1
CH0
Функции RTC, вывод 4 корпуса
GPIO1(1)
CH1
Функции RTC, вывод 5 корпуса
GPIO2(1,3)
CH2
Функции RTC и strapping, вывод 6 корпуса
GPIO3(1)
CH3
Функции RTC, вывод 7 корпуса
GPIO4(1)
CH4
Функции RTC, вывод 9 корпуса
GPIO5(1,2)
ADC2
CH5
Функции RTC, вывод 10 корпуса, есть ограничения на Wi-Fi
Важные замечания:
(1) Все АЦП каналы ESP32-C3 имеют функции RTC. Это означает, что все они могут работать в спящих режимах (Deep Sleep). (2) Есть ограничение ADC2 при использовании Wi-Fi: ADC2 (GPIO5) недоступен при активном Wi-Fi. Поэтому для проектов с Wi-Fi используйте только ADC1 (GPIO0-GPIO4). (3) Вывод GPIO2 обладает аппаратной функцией управления загрузкой, как и выводы GPIO8 и GPIO9. Это так называемые strapping pins (см. врезку ниже). Поэтому вывод GPIO2 для нормального включения и запуска должен иметь подтяжку к лог. 1, и по этой причине он практически бесполезен для использования как вход АЦП.
Функция управления загрузкой (strapping) является критически важной для корректного запуска ESP32-C3. Вот таблица с функциями управления загрузкой для соответствующих выводов:
GPIO
Функция при загрузке
Pull-up
Рекомендации
GPIO2
Strapping pin
внутреннего нет, нужен внешний
Для перевода в режим загрузки flash SPI (Download Mode) на этот вывод должна быть подана логическая «1» (высокий уровень).
GPIO8(1)
Strapping pin
внутреннего нет, нужен внешний
Логический уровень на этом выводе определяет выводом сообщений ROM-загрузчика (см. далее).
GPIO9
Strapping pin
слабый внутренний
Для перевода в режим загрузки flash SPI (Download Mode) на этот вывод должна быть подана логическая «1» (высокий уровень).
Примечание (1): уровень на выводе GPIO8 при включении питания может управлять печатью отладочных сообщений загрузчика (ROM Messages Print in SPI Boot Mode).
Логический уровень на пине GPIO8 в момент сброса или включения питания определяет, будет ли UART0 (GPIO21-TX, GPIO20-RX) использоваться для печати отладочных сообщений загрузчика (ROM Messages Print in SPI Boot Mode).
GPIO8 = HIGH (VCC / 3.3V): включена печать сообщений загрузчика. Вы увидите всю диагностическую информацию на UART0. GPIO8 = LOW (GND): выключена печать сообщений загрузчика. UART0 молчит во время фазы начальной загрузки.
В даташите и технической документации ESP32-C3 GPIO8 также обозначается как MTDI. Его функция как strapping-пина — контроль детализации вывода загрузчика (UART ROM log level). Назначение: U0TXD_ROM_MSG_LVL (уровень сообщений для UART0 TX).
Когда нужно включать печать (GPIO8 = HIGH)?
1. Разработка и отладка: это основной сценарий. Когда вы создаете прошивку и что-то идет не так (например, устройство не загружается), эти сообщения — единственный источник информации о том, на каком этапе загрузчик споткнулся (проверка чипа, загрузка заголовка приложения, ошибка SHA, запуск и т.д.). 2. Диагностика "bricked" устройств: если ваша плата перестала отвечать, сообщения загрузчика помогут понять, жива ли она вообще и до какого этапа доходит.
Когда нужно отключать печать (GPIO8 = LOW)?
1. Финальный продукт: в серийно выпускаемом устройстве вам не нужны отладочные сообщения. Они только занимают ресурсы и могут мешать работе приложения, если вы используете UART0 для других целей. 2. Энергосбережение: неактивный UART потребляет чуть меньше энергии. 3. Освобождение UART0: если в вашем приложении вы хотите использовать UART0 (GPIO21, GPIO20) для общения с другим устройством с самого старта, отключение сообщений загрузчика предотвратит конфликт и порчу данных.
Как это выглядит на практике? Представим, что у вас есть плата разработки ESP32-C3 и USB-UART мост, подключенный к GPIO20 (RX) и GPIO21 (TX).
Сценарий 1: GPIO8 подключен к VCC (3.3V) или не подключен.
1. Подаете питание на плату. 2. Сразу же в последовательном терминале (например, Arduino IDE Serial Monitor, `screen`, `putty`) со скоростью **115200 бод** вы увидите что-то вроде:
ets Jun 8 2016 00:22:57
rst:0x1 (POWERON),boot:0x2c (SPI_FAST_FLASH_BOOT) waiting for download
Эти строки — и есть сообщения загрузчика (ROM Bootloader). Они говорят о причине сброса и выбранном режиме загрузки.
Сценарий 2: GPIO8 подключен к GND
1. Подаете питание на плату. 2. В последовательном терминале — тишина. Никаких сообщений не выводится. Загрузчик молча пытается найти и запустить приложение из flash-памяти.
Важные нюансы:
1. Момент считывания: критически важно установить нужный уровень на GPIO8 до или во время сброса. Изменение уровня после того, как чип начал загрузку, не окажет никакого эффекта до следующего сброса. 2. Скорость UART: сообщения загрузчика всегда выводятся на скорость 115200 бод, независимо от скорости, которую вы установите в своей программе с помощью `Serial.begin()`. 3. Только для SPI Boot Mode: это поведение актуально для основного режима загрузки — `SPI_FAST_FLASH_BOOT`, когда прошивка загружается из внешней SPI flash-памяти. В других, более экзотических режимах загрузки, поведение может отличаться.
[Что такое Strapping Pins и как с ними работать]
Strapping Pins — это специальные выводы, состояние которых процессор считывает только в момент включения питания или сброса. На основе этих уровней напряжения определяется начальный режим работы чипа, например, разрешена ли загрузка через UART (Download Mode).
- Для GPIO2: чтобы микроконтроллер запустился в нормальном режиме (загрузка из flash-памяти), на выводе GPIO2 во время сброса должна быть установлена логическая единица (высокий уровень). Если вам не нужен режим загрузки по UART, вам, как правило, не нужно делать ничего — внутренняя или внешняя подтяжка к питанию (pull-up) обычно уже обеспечивает нужный уровень.
- Потенциальная проблема: если в вашей схеме на GPIO2 при старте установлен низкий уровень (например, он подключен к кнопке, которая при запуске замкнута на землю, или к выходу источника аналогового сигнала, если вы пытаетесь использовать GPIO2 как вход АЦП), ESP32-C3 может войти в режим ожидания загрузки firmware (активируется функция bootloader) и не запустить вашу программу.
Поэтому при проектировании схемы убедитесь, что на strapping-выводах, особенно на GPIO2, во время включения питания и сброса присутствует необходимый логический уровень. Избегайте подключений, которые могут создавать неопределённые состояния (например, плавающий вход). Более подробно про работу выводов управления загрузкой GPIO2, GPIO8, GPIO9 см. даташит ESP32-C3.
Ограничения, связанные с режимом работы. Поскольку модуль ADC2 также используется аппаратурой Wi-Fi, то операция чтения данных АЦП вызовом adc2_get_raw() (между вызовами esp_wifi_start() и esp_wifi_stop()) может быть неудачной. Используйте код возврата, чтобы определить успех операции чтения.
Определенный модуль ADC может работать одновременно только в одном из рабочих режимов: либо в режиме повторяющихся операций преобразование/чтение (Continuous Read Mode), либо в режиме однократного преобразования и чтения результата (Single Read Mode).
ADC1 и ADC2 не могут работать одновременно в режиме Single Read Mode. Один из них будет заблокирован, пока другой не завершит свою операцию.
Для режима непрерывного чтения (Continuous Read Mode) с использованием прямого доступа к памяти (DMA), частота выборок ADC (значение поля sample_freq_hz структуры конфигурации adc_digi_config_t) должно быть в пределах SOC_ADC_SAMPLE_FREQ_THRES_LOW и SOC_ADC_SAMPLE_FREQ_THRES_HIGH.
[Использование драйвера ADC]
Каждый из блоков ADC поддерживает 2 рабочих режима, ADC single read mode и ADC continuous read mode (DMA). Режим однократного чтения (ADC single read mode) подходит для низкочастотных измерений уровня. Режим постоянного чтения (ADC continuous read mode с использованием DMA) подходит для постоянно повторяющихся с высокой частотой измерений.
Примечание: значение уровня, прочитанное с помощью ADC из любого не подключенного вывода, может быть случайным.
Режим ADC Continuous (DMA) Read. Для запуска автоматически повторяющихся преобразований АЦП с использованием DMA выполните следующие шаги:
· Инициализируйте драйвер ADC вызовом функции adc_digi_initialize(). · Инициализируйте контроллер ADC вызовом функции adc_digi_controller_config(). · Запустите автоматические преобразования ADC вызовом функции adc_digi_start(). · После этого ADC вы можете получить прочитанные значения вызовом функции adc_digi_read_bytes(). Перед остановкой ADC (вызовом adc_digi_stop()) драйвер будет продолжать преобразования аналоговых данных в цифровые данные. · Остановка чтений ADC производится вызовом adc_digi_stop(). · Драйвер ADC деинициализируется вызовом adc_digi_deinitialize().
Режим ADC Single Read. ADC должен быть предварительно сконфигурирован.
· Для ADC1 сконфигурируйте желаемую точность (precision) и ослабление (attenuation) вызовом функций adc1_config_width() и adc1_config_channel_atten(). · Для ADC2 сконфигурируйте ослабление вызовом adc2_config_channel_atten(). Чтение ADC2 конфигурируется при каждом его чтении.
Конфигурирование ослабления делается отдельно для каждого канала, см. adc1_channel_t и adc2_channel_t, значения которых устанавливаются как параметры к показанным выше функциям.
После этого можно прочитать результат преобразования ADC вызовом adc1_get_raw() и adc2_get_raw(). Разрядность чтения ADC2 должно быть установлено параметром adc2_get_raw() вместо использования функций конфигурации.
Примечание: при использовании ADC имеются описанные выше ограничения, см. раздел "Ограничения ADC".
Пример приложения, которое использует ADC в режимах одиночного чтения (single read mode) и режиме автоматической оцифровки (continuous (DMA) read mode) можно найти в директории peripherals/adc/esp32c3 примеров ESP-IDF.
Макросы для идентификации GPIO. Следующие макросы могут использоваться для указания номера вывода GPIO для канала ADC, или наоборот.
ADC1_CHANNEL_0_GPIO_NUM это номер порта GPIO канала 0 для ADC1.
ADC1_GPIOn_CHANNEL это номер канала ADC1 для порта n GPIO.
Разрешение/запрет фильтра цифрового контроллера ADC. Фильтрация данных ADC применяется для получения плавных данных на повышенных скоростях дискретизации.
adc_digi_monitor_set_config
Установка конфигурации монитора цифрового контроллера ADC.
Структура установки правил преобразования цифрового контроллера ADC (режим DMA).
adc_digi_output_data_t
Структура формата выходных данных цифрового контроллера ADC (режим DMA). Используется для анализа захваченных данных ADC (режим DMA).
adc_digi_clk_t
Структура установки системных тактов цифрового контроллера ADC (режим DMA). Формула для вычисления: controller_clk = (APLL или APB) / (div_num + div_a / div_b + 1).
adc_digi_config_t
CONFIG_IDF_TARGET_ESP32. Параметры конфигурации цифрового контроллера ADC (режим DMA). Примеры настроек см. в описании adc_digi_config_t документации [1].
adc_arbiter_t
Настройки режима рабочего арбитража и приоритета ADC.
Макрос конфигурации по умолчанию арбитра ADC. Замечание: ESP32S2 поддерживает только арбитр ADC2 (нуждается в нем).
adc_unit_t
Перечисление блока ADC. Замечание: для цифрового контроллера ADC (режим DMA) ESP32 не поддерживает ADC_UNIT_2, ADC_UNIT_BOTH, ADC_UNIT_ALTER.
adc_channel_t
Дескриптор (handle) каналов ADC. См. adc1_channel_t, adc2_channel_t. Замечание: для ESP32 ADC1 не используйте ADC_CHANNEL_8, ADC_CHANNEL_9. См. adc1_channel_t.
adc_atten_t
Параметр ослабления ADC (attenuation). Различные параметры определяют диапазон работы ADC. См. adc1_config_channel_atten.
adc_i2s_source_t
Выбор источника ESP32 ADC DMA.
adc_bits_width_t
Установка опции разрешающей способности ADC.
adc_digi_convert_mode_t
Рабочий режим цифрового контроллера ADC (режим DMA). Замечание: режим преобразования влияет на частоту выборки: SINGLE_UNIT_1 - когда сработало измерение, только ADC1 сделало одну выборку. SINGLE_UNIT_2 - когда сработало измерение, только ADC2 сделало одну выборку. BOTH_UNIT - когда сработало измерение, ADC1 и ADC2 сделали выборки одновременно. ALTER_UNIT - когда сработало измерение, ADC1 или ADC2 сделали выборки поочередно.
adc_digi_output_format_t
Опция формата выходных данных цифрового контроллера ADC (режим DMA).
adc_arbiter_mode_t
Опция рабочего режима арбитра ADC.
adc_digi_filter_idx_t
Опции индекса фильтра цифрового контроллера ADC (режим DMA). Замечание: для ESP32-S2 объект фильтра ADC фиксирован.
adc_digi_filter_mode_t
Опции типа фильтра цифрового контроллера ADC (режим DMA). Выражение: filter_data = (k-1)/k * last_data + new_data / k.
adc_digi_monitor_idx_t
Опции индекса монитора цифрового контроллера ADC (режим DMA). Замечание: для ESP32-S2 объект монитора ADC фиксирован.
adc_digi_monitor_mode_t
Установка режима монитора цифрового контроллера ADC. MONITOR_HIGH: если ADC_OUT > порога, то генерируется прерывание монитора. MONITOR_LOW: если ADC_OUT < порога, то генерируется прерывание монитора.
Инкрементирует счетчик использования (usage counter) модуля 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. В описании этой функции документации [1] приведена таблица напряжения по умолчанию ADC для ослабления 0 dB. Путем установки повышенного ослабления можно оцифровывать напряжения более высокого уровня. Из-за особенностей характеристик ADC самые точные результаты получаются в рекомендуемом диапазоне ("suggested range"), показанном в таблице (см. описание adc1_config_channel_atten в документации [1]). Для достижения максимальной точности используйте API калибровки ADC и измерять напряжения в этих рекомендуемых диапазонах. Замечания: для любого указанного канала эта функция должна быть вызвана перед первым вызовом adc1_get_raw() для этого канала. Эта функция может быть вызвана несколько раз, чтобы одновременно сконфигурировать несколько каналов ADC. Вы можете вызвать adc1_get_raw() только после конфигурирования канала.
adc1_config_width
Конфигурируется ширина захвата ADC1 вместе с включением инверсии выхода для ADC1. Эта конфигурация делается для всех каналов ADC1.
adc1_get_raw
Берет одно чтение ADC1 из одного канала. ESP32: когда ключ питания SARADC1, SARADC2, HALL-сенсора и AMP-сенсора включен, вход GPIO36 и GPIO39 будет подтянут к низкому уровню примерно на 80 нс. Когда разрешается питание для любых из этих периферийных устройств, игнорируйте вход из GPIO36 и GPIO39. Описание этой проблемы см. в секции 3.11 "ECO_and_Workarounds_for_Bugs_in_ESP32". В качестве обходного решения вызовите в приложении adc_power_acquire(). Это приведет к повышенному потреблению энергии (примерно на 1 мА), но устранит эти выбросы на GPIO36 и GPIO39. Вызовите adc1_config_width() перед первым вызовом этой функции. Для любого указанного канала функция adc1_config_channel_atten(канал) должна быть вызвана перед первым вызовом этой функции. Конфигурирование нового канала не защищает от чтения ранее сконфигурированного канала.
adc2_pad_get_io_num
Извлекает номер GPIO определенного канала ADC2.
adc2_config_channel_atten
Конфигурирует канал ADC2, включая установку ослабления (attenuation). В описании этой функции документации [1] приведена таблица напряжения по умолчанию ADC для ослабления 0 dB. Путем установки повышенного ослабления можно оцифровывать напряжения более высокого уровня. Из-за особенностей характеристик ADC самые точные результаты получаются в рекомендуемом диапазоне ("suggested range"), показанном в таблице (см. описание adc2_config_channel_atten в документации [1]). Для достижения максимальной точности используйте API калибровки ADC и измерять напряжения в этих рекомендуемых диапазонах. Эта функция также конфигурирует мультиплексор входов портов GPIO для подключения их к каналу ADC2. Замечания: для любого указанного канала эта функция должна быть вызвана перед первым вызовом adc1_get_raw() для этого канала. Эта функция может быть вызвана несколько раз, чтобы одновременно сконфигурировать несколько каналов ADC, перед вызовом adc2_get_raw(). Вы можете вызвать adc2_get_raw() только после конфигурирования канала.
adc2_get_raw
Делает чтение одного канала ADC2. ESP32: когда ключ питания включает SARADC1, SARADC2, HALL-сенсор и AMP-сенсор, вход GPIO36 и GPIO39 будет подтянут к низкому уровню на время около 80 нс. Когда разрешается питание для любого из этих периферийных устройств, игнорируйте ввод из GPIO36 и GPIO39. Описание этой проблемы см. в секции 3.11 "ECO_and_Workarounds_for_Bugs_in_ESP32". В качестве обходного решения вызовите в приложении adc_power_acquire(). Это приведет к повышенному потреблению энергии (примерно на 1 мА), но устранит эти выбросы на GPIO36 и GPIO39. ESP32: для определенного канала adc2_config_channel_atten() должна быть вызвана перед первым вызовом этой функции. Если Wi-Fi запускается вызовом esp_wifi_start(), то эта функция всегда потерпит неудачу с ошибкой таймаута ESP_ERR_TIMEOUT. ESP32-S2: ADC2 поддерживает аппаратный арбитр. Арбитр предназначен для повышения эффективности использования ADC2. После того, как права на управление нарушены высоким приоритетом, контроллер с низким приоритетом прочитает недостоверные данные ADC2. Приоритет по умолчанию: Wi-Fi -> RTC -> Digital.
adc_vref_to_gpio
Номер ножки порта adc2_channel_t выхода опорного напряжения ADC1 или ADC2. Эта функция маршрутизирует внутреннее опорное напряжение ADCn на один из каналов ADC2. Тогда это опорное напряжение может быть затем измерено вручную для калибровки. ESP32 поддерживает только вывод внутреннего опорного напряжения ADC2.
adc2_vref_to_gpio
Номер ножки порта adc2_channel_t выхода опорного напряжения ADC2. Эта функция маршрутизирует внутреннее опорное напряжение ADCn на один из каналов ADC2. Это опорное напряжение может быть затем измерено вручную для калибровки.
adc_digi_controller_config
Настройка цифрового контроллера ADC.
adc_digi_initialize
Инициализация Digital ADC.
adc_digi_start
Старт периферийных устройств Digital ADC и DMA. После этого аппаратура начнет работать.
adc_digi_stop
Остановка периферийных устройств Digital ADC и DMA. После этого аппаратура перестанет работать.
adc_digi_read_bytes
Считывает байты из Digital ADC через DMA.
adc_digi_deinitialize
Отменяет инициализацию Digital ADC.
adc_digi_init_config_s
Конфигурация ADC DMA.
ADC_ATTEN_0db
Опция ослабления rtc-контроллера ADC. Эти определения оставлены только для обратной совместимости.
adc_digi_init_config_s
Конфигурация Digital ADC DMA.
adc1_channel_t, adc2_channel_t
Перечисления для идентификации каналов ADC1 и ADC2.
Проверит, прошиты ли значения калибровки ADC в eFuse. Эта функция проверит, прошито ли опорное напряжение ADC или "значения двух точек" (Two Point values) в eFuse текущего экземпляра ESP32. Замечание: в ESP32S2 поддерживается только ESP_ADC_CAL_VAL_EFUSE_TP. Некоторые старые ESP32S2 тоже это не поддерживают. В случае, когда вы делаете калибровку вручную, есть возможность выполнить вашу собственную калибровку чипа по двум точкам.
esp_adc_cal_characterize
Характеристика ADC на определенном ослаблении (attenuation). Эта функция будет характеризовать ADC на определенной настройке ослабления, и генерировать кривую ADC-напряжение в форме [y = coeff_a * x + coeff_b]. Определение характеристики может быть основана на значениях Two Point, eFuse Vref, или Vref по умолчанию и значений калибровки, с приоритетом в этом порядке. Замечание: для ESP32, значения Two Point и калибровка eFuse Vref может быть разрешены/запрещены с помощью menuconfig. Для ESP32S2 могут поддерживаться только значения калибровки Two Point, и только ADC_WIDTH_BIT_13. Параметр default_vref не используется.
esp_adc_cal_raw_to_voltage
Преобразует считанное значение из ADC в напряжение в mV. Эта функция преобразовывает результат чтения из ADC в напряжение в mV, основываясь на характеристиках ADC. Структура с характеристиками должна быть инициализирована перед вызовом этой функции (вызовите esp_adc_cal_characterize()).
esp_adc_cal_get_voltage
Reads an ADC and converts the reading to a voltage in mV. Эта функция вычитывает ADC, затем преобразует сырое считанное значение в напряжение, выраженное в mV, на основе предоставленной характеристики. Считываемый ADC также определяется характеристиками. Структура с характеристиками должна быть инициализирована перед вызовом этой функции (вызовите esp_adc_cal_characterize()).
esp_adc_cal_characteristics_t
Структура, сохраняющая характеристики ADC. Вызовите esp_adc_cal_characterize() для инициализации этой структуры.
esp_adc_cal_value_t
Тип значения калибровки, используемой в определении характеристики.
[GPIO Lookup Macros]
Заголовочный файл: soc/esp32c3/include/soc/adc_channel.h. Макросы, предназначенные для преобразования каналов ADC в порты GPIO и обратно: