Перейти к содержимому

Почему я выбрал ESP-IDF для программирования ESP32, а не Arduino?

Данная статья – начало цикла статей, посвященных программированию популярного ESP32 на “родном” для этого микроконтроллера фреймворке ESP-IDF. Без использования Arduino. В статье рассмотрен вопрос, зачем же это все-таки нужно и почему в конце-концов я выбрал ESP32 как основу для всех своих последних проектов домашней автоматизации. Ведь существует огромное количество микроконтроллеров других производителей: PIC (Mictochip), AVR (Atmel), ATM (STMicroelectronics), ESP8266??? Некоторые из них обладают гораздо лучшими характеристиками, например по экономичности, да и стоят иногда дешевле…

Сразу оговорюсь: я не профессиональный разработчик ESPressif Iot Development Framework (ESP IDF) – такой же любитель, как и большинство из вас. Статей по программированию в Arduino – пруд пруди. А вот статей по ESP IDF – очень мало. Сам сталкивался с этим, когда осваивал. Поэтому, только спустя несколько лет, когда появилось какое-то более менее “системное” понимание возможностей и технологий, я решил поделиться этой информацией со всеми.

Очень скоро я понял, что мне критически важны удаленный контроль и удаленное управление устройствами. А это означает, что устройство должно иметь возможность подключения к сети, желательно посредством WiFi, чтобы не плодить паутину кабелей и проводов. Встроенный WiFi “на борту” имеют ESP8266 и ESP32 производства Espressif Systems. Да, я знаю, что есть платы сетевых интерфейсов для Arduino, но…

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

Кроме того, ESP8266 и ESP32 (и платы на их основе) достаточно дёшевы, широкого распространены и надежны.

 

Зачем нужно это удаленное управление?

Во-первых это позволяет минимизировать количество органов управления при создании устройств – в большинстве случаев для автоматизации какого-либо процесса не нужно подключать экран, использовать много кнопок и переключателей для управления. Не нужно создавать встроенные меню для настройки каких-либо параметров. Отображение данных и настройку параметров можно перенести на смартфон или компьютер. Это позволяет использовать в качестве корпуса стандартные различные разветвительные коробки для монтажа электропроводки – это дешево и выглядит достаточно аккуратно. Либо использовать достаточно дешевый стандартные корпуса. Примеры на фотографиях ниже. Конечно, при наличии 3D-принтера можно создать любой корпус, но лично у меня пока такой возможности нет.

Контроллер управления вентиляцией в санузле. Собрано в стандартной коробке для скрытого монтажа

Устройство в стандартной монтажной коробке TDM100x100мм под столешницей стола

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

В третьих, наличие доступа устройства в сеть позволяет осуществлять обновление прошивки устройства не только с помощью кабеля, но и “по воздуху” – так называемое OTA-обновление. Это существенно облегчает и ускоряет “массовую” перепрошивку “умных” устройств при внесении каких-либо изменений и дополнений. Процесс совершенствования прошивок не останавливается с момента, когда закручен последний винт в корпус устройства.

Замена ESP8266 на ESP32

Поначалу я использовал для своих поделок ESP8266, программируя их в уже привычной среде Arduino IDE. Однако достаточно быстро столкнулся с её недостатками. Это небольшое количество выводов для подключения периферии (особенно у платок ESP-01), только один вывод ADC и, увы, нестабильная работа даже на самых простых скетчах (впрочем, возможно, в этом были виноваты достаточно “кривоватые” внешние библиотеки, которые я использовал; либо мои кривые руки).

Потом я увидел и заказал на одной известной китайской торговой площадке отладочные платы с новым (по сравнению с ESP8266, разумеется) контроллером – ESP32 Devkit V4. По стоимости эти платы не намного выше ESP8266, и одно всем известное зеленое земноводное не сильно сопротивлялось при заказе.

Один из вариантов отладочных плат с ESP32. В основном я использую именно эти

Возможности ESP32 по сравнению с ESP8266 гораздо шире:

  • двухядерный процессор и гораздо больше памяти
  • многопоточная операционная система FreeRTOS на борту (даже в Arduino, не удивляйтесь – подробности ниже)
  • достаточно большое количество выводов для подключения датчиков и периферии
  • гораздо большее количество выводов ADC (АЦП – аналого-цифрового-преобразователя). Впрочем, на ESP32 ADC выводы достаточно коряво сделаны и далеко не все их можно использовать, оказывается (этому вопросу я планирую посвятить отдельную статью)
  • две отдельные шины I2C, которые можно использовать одновременно
  • отличная документация на сайте Espressif Systems. Конечно, документация на английском, но Гуголь легко справляется с переводом

В итоге, несколько платок с ESP8266 уже пару лет пылятся в коробочке, а количество заказанных ESP32 и устройств на них исчисляется десятками. В июле было отключено последнее устройство, которое, впрочем более-менее успешно работало несколько лет.

 

FreeRTOS и нафига она нужна…

Первые опыты с ESP32 я проводил в старой-доброй Arduino IDE. Привычный интерфейс, привычные loop() и setup(). Однако у меня сразу же возник закономерный вопрос – если Arduino это сугубо однопоточная система, а ESP32 имеет сразу два ядра, то как использовать это самое второе ядро?

Изучая примеры для ESP32, легко находится масса примеров программирования ESP32 с использованием операционной системы реального времени FreeRTOS для микроконтроллеров. Хорошо помню, что на тот момент изучать FreeRTOS у меня не было никакого, я сделал очередной проект “по образу и подобию” и закрыл тему.

Но любопытство дало свои результаты. Через какое-то время я обнаружил в файлах платформы Esp32 для Arduino файл-“обертку” для всех скетчей (%profile%\packages\esp32\hardware\esp32\%version%\cores\esp32\main.cpp). Содержимое этого файла таково:

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "Arduino.h"

TaskHandle_t loopTaskHandle = NULL;

#if CONFIG_AUTOSTART_ARDUINO

bool loopTaskWDTEnabled;

void loopTask(void *pvParameters)
{
setup();
    for(;;) {
        if(loopTaskWDTEnabled){
            esp_task_wdt_reset();
        }
        loop();
    }
}

extern "C" void app_main()
{
    loopTaskWDTEnabled = false;
    initArduino();
    xTaskCreateUniversal(loopTask, "loopTask", 8192, NULL, 1, &loopTaskHandle, CONFIG_ARDUINO_RUNNING_CORE);
}

#endif

Эта “обертка” используется для всех скетчей, которые Вы создаете в классической Arduino IDE.

Какую информацию отсюда можно почерпнуть? Видно, что FreeRTOS всегда по умолчанию подключается к Вашему скетчу (через #include “freertos/FreeRTOS.h”), а любой классический скетч Arduino (то есть якобы написанный без использования задач) – это всегда задача FreeRTOS, которая выполняется на втором ядре процессора #1, и которой выделено всего 8192 байт стека! Сама FreeRTOS при этом выполняется на ядре процессора #0. Становится немного понятнее, как на ESP32 реализована работа с двумя ядрами.

Дальнейшее исследование данного вопроса привело на ресурсы, посвященные ESP-IDF. Оказалось, что ESP-IDF (Espressif IoT Development Framework) – это основной (legacy) фреймворк для программирования микроконтроллеров на базе ESP32, разработанный тем же Espressif Systems. А используемый в Arduino IDE фреймворк Arduino Core for ESP32 это адаптация ESP-IDF, чтобы втиснуть его в узкие рамки Arduino IDE.

Если вы продолжите программирование в данном классическом варианте (один скетч – одна задача), то ваш Arduino скетч получит только доступ только к 8192 байт стека (на ESP32 стек указывается именно в байтах, а не словах, как в классической FreeRTOS). В принципе, это достаточно много, даже слишком много. Почти наверняка вы даже не сможете его (стек задачи) полностью израсходовать (если только не будете предпринимать к этому специальных усилий, вроде 100500 аргументов в каждой функции). Остальную память вы сможете использовать в качестве общей кучи (heap). Подробнее о распределении памяти на ESP32 вы можете почитать в другой статье.

На самом деле, параллельно с вашим скетчем при этом будут работать ещё несколько задач, созданных и запущенных самим фреймворком Arduino Core for ESP32, например: планировщик задач, цикл событий, IPC и т.д., но это не отразится на вашем скетче. В принципе, на этом можно и закончить статью – вы вполне сможете написать рабочий классический скетч в классической Arduino IDE, но с ограничение стека 8192 байт.

Отсюда вывод: если Вы хотите использовать ESP32 “на всю катушку” придется осваивать FreeRTOS (как основу ESP-IDF)Хотите этого Вы или нет. Иначе это выглядит как “микроскопом гвозди забивать”.

ESP-IDF – основной framework для ESP32

ESP-IDF представляет собой основную среду разработки программного обеспечения для оборудования на основе чипа ESP32 от Espressif. ESP-IDF по сути это портированная на ESP32 версия FreeRTOS. Как вы, наверное, заметили, этот тот же старый – добрый Си и Си++, никакой принципиальной разницы в языках программирования нет. Если вы научились сносно разбираться в скетчах Arduino, то осваивать принципиально новый язык вам не придется. Разница будет заметна только в подходах к программированию для однозадачной среды и многозадачной.

В привычной для многих Arduino главной задачей каждой из функций в главном цикле loop() было как можно быстрее завершить свою работу и передать управление следующей. Взаимодействие между различными частями программы осуществлялось с помощью callback-ов. Использование delay() считается плохой практикой, так как это непосредственно повлияет на остальные части вашей программы.

В многозадачной среде каждый из модулей вашей прошивки работает поочередно, когда ОС выделяет задаче квант процессорного времени. И, в принципе delay() не мешает другим процессам, однако его использование всё равно можно считать нежелательным. Когда какая-либо из задач завершила очередной цикл своей работы (например отправила HTTPS-запрос), её следует отправить в ожидание следующего “входящего” события, и тогда ОС не будет “попусту” выделять ей процессорное время.

Возможности многозадачной операционной системы лично меня просто восхищают. Создав несколько задач для разных функций прошивки, можно больше не опасаться, что пауза в одной из задач вызовет завивание всего контроллера. Например отключение WiFi роутера не вызывает катастрофы в сервисах измерения данных с сенсоров и обработки результатов. ESP-IDF уже включает в себя встроенные драйверы, библиотеки и модули почти “на все случаи жизни”: GPIO, UART, Modbus, SPI, SDIO, I2C, I2S, PWM, WIFI, PING, клиент MQTT, HTTP(S) и многое, многое другое. Для основных прикладных задач больше не нужны библиотеки сторонних разработчиков – почти все необходимое уже включено в состав платформы. Просто отлично, на мой взгляд, реализовано хранение параметров на flash-памяти: не по адресам, а по именами переменных (это ооочень удобно, по сравнению с arduino-вскими способами). Всё это достаточно хорошо документировано и описано, есть много примеров.

ESP-IDF – это Open Source проект, что позволяет любому участвовать в совершенствовании проекта и устранении багов, если таковые вдруг будут найдены. В настоящий момент “в работе” у разработчиков ESP-IDF находится issue для добавления нового функционала для MQTT-клиента, а ещё раньше были исправлены две найденные мной проблемы.

Но, как всегда, есть “подводные камешки”.

Во-первых, придется отказаться от привычной Arduino IDE, так как возможности установить “чистый” ESP-IDF в Arduino IDE нет. А использовать “урезанный” вариант мне не хотелось. Впрочем, нет худа без добра – я перешел на гораздо более удобную и бесплатную IDE – VS Code (хотя и без недостатков).

Во-вторых: в ESP-IDF отсутствуют как класс драйвера для всевозможных датчиков и экранов (например DHT22, LCD1602 и т.д.). Производители плат создают драйвера для ArduinoIDE, так как она очень популярна; а вот для ESP-IDF драйвера придется написать самому, копаясь в даташитах, благо это не сложно. Но в этом есть и свои плюсы – написав собственный драйвер, вы лучше разберетесь как работает то или иное периферийное устройство, а заодно и драйвер можно улучшить. Например: пока я пользовался готовыми драйверами для датчиков температуры и влажности, я и понятия не имел, что внутри многих из них есть встроенные нагреватели для исправления дрейфа показаний во сильно влажной среде.

Впрочем, сейчас довольно много готовых драйверов можно найти на GitHub. В частности, вы можете бесплатно использовать и мои драйвера.

Плюсы и минусы ESP-IDF

В качестве некоторого итога статьи, приведу плюсы и минусы использования ESP-IDF в своих проектах, с моей точки зрения:

Достоинства:

  • “Родная” ( native ) для микроконтроллера среда программирования, предоставляемая разработчиком чипов. Уже только одно это говорит само за себя
  • Многопоточная операционная система жесткого реального времени позволяет легко наращивать функционал системы без усложнения прошивки и превращения кода в “клубок спагетти”
  • Возможность использования всех аппаратных возможностей чипа (например из под Arduino нет возможности одновременного использования двух шин I2C)
  • Возможность конфигурирования ESP-IDF под свои нужды и задачи (в Arduino IDE хотя и используется базовая часть ESP-IDF, но настройка опций невозможна)
  • Возможность произвольного конфигурирования разделов FLASH – памяти (в Arduino IDE есть только несколько заранее определенных схем разметки, сформированным каким-то дядей)
  • Использование циклов событий (это такой микро MQTT-брокер внутри RTOS) позволяет организовать “правильное” взаимодействие между различными функциональными модулями прошивки и избавиться от многоярусных callback-ов.
  • Встроенный MQTT клиент с outbox-ом (очередью отправки)
  • NVS-хранилище для хранения данных и параметров

Недостатки:

  • В “комплекте поставки” ESP-IDF отсутствуют драйвера для сенсоров, устройств, дисплеев и т.д. Сторонних библиотек драйверов для ESP-IDF создано пока гораздо меньше, чем для Arduino. Кроме того, вам придется поискать их вручную на GitHub или в реестре библиотек PlatformIO. Но в ESP-IDF есть всё необходимое, чтобы создать такой драйвер самому.
  • Придется отказаться от привычной для многих Arduino IDE.

Что лично для вас важнее – решать только вам.

Visual Studio Code + PlatformIO

Как я уже писал выше, чтобы начать “кодить” с использованием ESP-IDF, необходимо использовать другую IDE. Существует несколько вариантов, но самыми популярными вариантом является бесплатный Visual Studio Code. Но собственно VSCode это просто универсальный редактор для любых языков программирования, чтобы иметь возможность писать программы для ESP32, ESP8266 и других микроконтроллеров, необходимо установить специальное расширение – plugin. Существует как минимум два plugin-а, позволяющих работать с ESP-IDF:

  • родной plugin от Espressif, который позволяет работать только с ESP-IDF, собственно
  • популярный проект PlatformIO, который позволит вам работать с множеством самых разных микроконтроллеров и с помощью разных технологий. Кстати, PlatformIO легко позволяет продолжить работу с Arduino кодом, но в более комфортной обстановке.

На PlatformIO, собственно, я и остановился. Более подробно процесс установки VSCode и PlatformIO описан в другой статье.

Почему не Arduino?

PlatformIO позволяет работать с очень многими платформами и микроконтроллерами. В принципе, ничто не мешало мне продолжить работу с уже привычными платами. Но, поскольку я довольно плотно подсел на ESP32 и ESP-IDF, мне уже совсем не хочется распылять свои время и усилия на совершенно разный код, писать и модифицировать целый ворох различных библиотек и т.д. Я практически не собираю устройств “для опытов” – есть задача – решаем её, только так. Возможностей ESP32 с лихвой хватает для всех бытовых задач, цена позволяет поставить её в любую розетку – что еще нужно? Поэтому в настоящее время я покинул мир Arduino, возможно это временно, возможно навсегда. Прощай и спасибо за опыт!

Вместо заключения

Поскольку я довольно продолжительное время занимаюсь программированием для “взрослых” компьютеров, освоение многопоточного (многозадачного) программирования не вызывало у меня трудностей, однако у новичков некоторые моменты могут вызывать трудности, в частности синхронизация потоков, совместное использование ресурсов и т.д. Вот все эти моменты мы и будем обсуждать в следующих статьях. Пока я планирую поделиться с вами, с чего начать; и с какими трудностями лично мне пришлось столкнуться; какие модули и библиотеки и для чего можно использовать.

PS: Я не профессиональный программист встраиваемых систем (хотя профессиональный программист учетных программ и баз данных), и я не освоил и четверти всех возможностей, которые предоставляет ESP32 и ESP-IDF. Просто потому, что мне пока не нужно было использовать некоторые возможности. Предлагаю вам осваивать этот микроконтроллер и его среду программирования вместе.

Подписывайтесь, будет интересно… 👍

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

  1. Официальная документация по ESP-IDF (на английском)
  2. Андрей Курниц “FreeRTOS — операционная система для микроконтроллеров”
  3. FreeRTOS — практическое применение
  4. Справочник по Free RTOS API
  5. Канал на Дзене
  6. Мои репозитории

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *