Найти тему
K12 :: О ESP32 и не только

Работа с портами ввода-вывода GPIO из ESP-IDF

Добрый день, уважаемый читатель! В этой статье обсудим методы работы со встроенными портами ввода-вывода GPIO в цифровом режиме.

Если вы создавали скетчи для Arduino IDE, то наверное, знаете, как осуществляется работа с GPIO для Arduino:

pinMode(10, OUTPUT); // Настраиваем PIN10 на выход
digitalWrite(10, HIGH); // Записываем в PIN10 высокий уровень

В данном случае pinMode настраивает порт ввода-вывода на режим "выход", а digitalWrite служит для записи в ранее настроенный порт логической единицы (или нуля). Это унифицированные функции Arduino, которые "внешне" не зависят от аппаратной платформы, а вот их внутренняя реализация будет зависеть от того, какой микроконтроллер вы используете. Это позволяет сравнительно легко переносить код с одного микроконтроллера на другой без адаптации (на самом деле это не всегда прокатывает, но тем не менее, разработчики платформы Arduino к этому стремятся).

На ESP-IDF необходимости в такой унификации нет, поэтому используются более специфичные функции. Их мы сегодня и обсудим.

Какие выводы GPIO можно использовать для ввод и вывод

Давайте вспомним, какие выводы можно использовать на ESP32 (я буду рассматривать линейки ESP32-WROOM или ESP32-WROVER).

Чип ESP32 имеет 34 физических контакта GPIO. Каждая контактная площадка может использоваться как вход/выход общего назначения (GPIO) или может быть подключена к внутреннему периферийному сигналу. Мультиплексоры IO_MUX, RTC IO_MUX и матрица GPIO отвечают за маршрутизацию сигналов от периферийных устройств к контактам GPIO. Вместе эти системы обеспечивают гибко настраиваемый ввод-вывод.

Порты ввода-вывода для ESP32-DevKitC V4
Порты ввода-вывода для ESP32-DevKitC V4
  • На ввод и вывод для ESP32-WROOM можно смело использовать следующие 18 выводов GPIO: 2, 4, 5, 12, 14, 15, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 32, 33. Все указанные выводы имеют встроенные программно-подключаемые резисторы подтяжки 45 кОм (в документации это называется "слабая подтяжка"). Я буду называть эти порты "универсальными", для простоты понимания. Некоторые из них можно назначить для использования различных интерфейсов: I2C, SPI и т.д. Примечания: выводы 5, 12, 14, 15 использовать следует с осторожностью; для ESP32-WROVER выводы 16 и 17 использовать нельзя.
  • Выводы GPIO 34, 35, 36, 39 можно использовать только на ввод, и у них отсутствуют встроенные резисторы слабой подтяжки. На эти же выводы выведен канал ADC1.
  • Можно ещё использовать GPIO 0, но так как он используется в схеме сброса контроллера после прошивки, его нельзя подтягивать его к питанию через резистор.

Более подробно об выводах GPIO можно почитать здесь:

На все эти выводы можно подключить обработчики прерываний для отслеживания изменения уровня извне микроконтроллера, но прерывания обсудим в следующей статье.

Хочу обратить ваше внимание только на то, что, согласно спецификации, выводы GPIO допускают ток аж до 40 mA "высокого" уровня и до 28 mA "низкого" уровня. Это позволяет управлять различными слаботочными устройствами типа светодиодов напрямую, без применения коммутирующих транзисторов, нужно только учитывать напряжение на выводе не более 3.3В.

Настройка порта GPIO

Для работы с портами GPIO необходимо подключить модуль "driver/gpio.h":
# include "driver/gpio.h"

Как и в Arduino IDE, прежде чем начинать работу с GPIO, его нужно настроить (сконфигурировать). Каждый "универсальный" порт можно настроить:

  • направление: на вход или выход
  • слабая подтяжка (45 КОм) к +3,3В или к "земле"
  • прерывание (если необходимо)

ESP-IDF предлагает два метода конфигурации:

  • Пакетная конфигурация сразу нескольких портов: с помощью функции gpio_config (const gpio_config_t* pGPIOConfig). Эта функция позволяет за один вызов настроить все параметры для выбранных портов: направление, подтяжки, прерывания. Соответственно это чуть более быстрый способ.
  • С помощью набора функций gpio_set_direction, gpio_set_pull_mode, и т.д. Это более "детализированные" функции и работают они только для одного выбранного порта. Я чаще использую именно этот способ, скорее всего "по привычке" (так как они более похожи на способ из Arduino IDE).

Выбор вывода для работы в режиме GPIO

Прежде всего необходимо настроить GPIO для использования в режиме ввода-вывода (так как GPIO на ESP32 могут быть использованы для разных целей с помощью мультиплексора выводов IO_MUX). Разработчики ESP32 не гарантируют, что после аппаратного сброса микроконтроллера все его выводы установятся в режим ввода-вывода. Поэтому операцию перевода нужных выводов в режим GPIO желательно делать всегда.

Сделать это можно с помощью функции:

esp_err_t gpio_reset_pin(gpio_num_t gpio_num)

где:

  • gpio_num - номер вывода GPIO

Эта функция настраивает IOMUX для этого вывода на работу с GPIO, включает встроенную слабую подтяжку и отключает режимы работы на вход и на выход (то есть устанавливается режим GPIO_MODE_DISABLE – см. следующий раздел).

Для этой же цели можно воспользоваться другой функцией, которая просто перенастраивает IOMUX для этого вывода на работу с GPIO:

void gpio_pad_select_gpio(uint8_t gpio_num)

где:

  • gpio_num – номер вывода GPIO

Режимы работы портов ввода-вывода

ESP32 поддерживает несколько режимов GPIO:

-2
  • GPIO_MODE_DISABLE - порт отключён
  • GPIO_MODE_INPUT - порт работает только на вход
  • GPIO_MODE_OUTPUT - порт работает только на выход
  • GPIO_MODE_OUTPUT_OD - порт работает только на выход в режиме "открытый коллектор" (open-drain)
  • GPIO_MODE_INPUT_OUTPUT_OD - порт может работать одновременно и на вход и на выход с открытым коллектором
  • GPIO_MODE_INPUT_OUTPUT - порт может работать одновременно и на вход и на выход

Для выбора режима порта используйте функцию

esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode)

где:

  • gpio_num - идентификатор GPIO
  • mode - режим работы

Переключить режим работы порта можно в любой момент, не обязательно делать это только при старте прошивки.

Встроенная подтяжка

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

Универсальная функция:

esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull)

где:

  • gpio_num - идентификатор GPIO
  • pull - режим подтяжки

Режим gpio_pull_mode_t может принимать одно из нескольких значений:

  • GPIO_PULLUP_ONLY - подтяжка к питанию +3,3В
  • GPIO_PULLDOWN_ONLY - подтяжка к "земле"
  • GPIO_PULLUP_PULLDOWN - подтяжка одновременно к питанию +3,3В и "земле"
  • GPIO_FLOATING - подтяжка отключена

Однако можно использовать и несколько более простых функций:

Какой метод использовать - выбирайте на вкус.

Настройка допустимого выходного тока

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

esp_err_t gpio_set_drive_capability (gpio_num_t gpio_num , gpio_drive_cap_t strength)

где:

  • gpio_num - идентификатор GPIO
  • strength - максимально допустимый ток

Режим gpio_drive_cap_t может принимать одно из нескольких значений:

  • GPIO_DRIVE_CAP_0 - слабый, до ~5мА
  • GPIO_DRIVE_CAP_1 - сильнее, до ~10мА
  • GPIO_DRIVE_CAP_2 - средний (по умолчанию), до ~20мА
  • GPIO_DRIVE_CAP_3 - максимальный, до ~40мА

Как видите, по умолчанию ток высокого уровня ограничен на уровне 20мА. В большинстве случаев вызывать данную функцию при настройке порта не требуется. Но если ваше устройство на ESP32 требует большего тока (например при управлении мощным биполярным транзистором), то вы можете столкнуться с "неправильным" поведением.

Запись логического уровня в GPIO

Для записи данных в выходной порт необходимо воспользоваться функцией:

esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level)

где:

  • gpio_num - идентификатор GPIO
  • level - логический уровень, 0 (низкий) или 1 (высокий)

Ничего сложного, всё предельно просто.

Чтение логического уровня из GPIO

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

uint32_t gpio_get_level(gpio_num_t gpio_num)

где:

  • gpio_num - идентификатор GPIO

Если GPIO не настроен для ввода (или ввода и вывода), возвращаемое значение всегда равно 0.

Практическое использование GPIO в режиме вывода - мигаем светодиодом

Допустим, мы хотим использовать светодиод, подключенный к одному из выводов через токоограничительный резистор, например это GPIO12. Классика жанра.

Источник: Яндекс Картинки
Источник: Яндекс Картинки

Светодиод можно подключить двумя способами:

  • С управлением по высокому уровню. Анод через резистор к GPIO, катод - к общему проводу. В этом случае следует использовать режим GPIO_MODE_OUTPUT.
  • С управлением по низкому уровню. Анод к +3,3В, катод через резистор к GPIO. В этом случае лучше использовать режим GPIO_MODE_OUTPUT_OD.

Для ESP32 наверное оптимальнее использовать первый способ, так как ток GPIO для высокого уровня может достигать до 40мА, а для низкого - только 28мА. Хотя для светодиода вполне достаточно 10мА, в крайнем случае - 20мА (для старых советских светодиодов зеленого цвета).

Настройка вывода будет выглядеть так:

-4

Для мигания светодиодов создадим задачу (пример создания задач мы рассматривали в одной из предыдущих статей).

Функция задачи для мигания светодиодом будет выглядеть примерно так:

-5

Использование GPIO для пробуждения микроконтроллера

Если вы используете в своих разработках режим глубокого сна (например при питании от батарей), то вы можете использовать вывод GPIO для пробуждения микроконтроллера по внешнему сигналу. Задействовать данную функцию можно с помощью функции:

esp_err_t gpio_wakeup_enable (gpio_num_t gpio_num, gpio_int_type_t intr_type)

где:

  • gpio_num - идентификатор GPIO
  • intr_type - логический уровень на GPIO для пробуждения. Можно использовать только GPIO_INTR_LOW_LEVEL или GPIO_INTR_HIGH_LEVEL.

Отключить пробуждение можно с помощью функции gpio_wakeup_disable (gpio_num_t gpio_num).

Ну вот и всё, о чем я хотел рассказать в данной статье. Пример вы можете посмотреть на GitHub.

dzen/gpio at master · kotyara12/dzen

Прерывания по изменению уровня на GPIO мы обсудим в следующей статье, так как это отдельная большая тема.

Полезные ссылки

_______________

На этом пока всё, до встречи на сайте и на dzen-канале!

👍 Понравилась статья? Поддержите канал лайком или комментарием! Каналы на Дзене "живут" только за счет ваших лайков.

📌Подпишитесь на канал и вы всегда будете в курсе новых статей.

🔶 Полный архив статей вы найдете здесь

Благодарю за вашу поддержку! 🙏