Найти в Дзене
K12 :: О ESP32 и не только

Arduino ESP32 шаг за шагом. Телеметрия через WiFi и MQTT для чайников. Часть 1

Доброго здравия, уважаемые читатели! Дисклеймер. Данная и последующие статьи на Дзене - разделенная на несколько частей полная статья, опубликованной на сайте kotyara12.ru. Всю статью целиком вы уже можете прочитать здесь: https://kotyara12.ru/iot/esp32mqtt-arduino/. В основной версии можно скопировать код примеров (Дзен не подходит для таких технических статей, как эта), а также вносятся правки при необходимости - поэтому версии на Дзене могут отличаться от статей на сайте. Благодарю за понимание. Постоянные читатели моего канала и сайта, наверное, знают, что я практически не использую в своих “рабочих” проектах для ESP32 Arduino IDE и Arduino-фреймворки. Я предпочитаю использовать “родной” для ESP32 фреймворк – ESP-IDF, непосредственно или с помощью PlatformIO. Об этом я писал не уже раз – можете поискать на этом сайте, почему я так делаю. Поэтому и статей на тему Arduino стараюсь избегать. Когда-то я написал статью Телеметрия на ESP8266 + MQTT. Пошаговое руководство по созданию DIY-
Оглавление

Доброго здравия, уважаемые читатели!

Дисклеймер. Данная и последующие статьи на Дзене - разделенная на несколько частей полная статья, опубликованной на сайте kotyara12.ru. Всю статью целиком вы уже можете прочитать здесь: https://kotyara12.ru/iot/esp32mqtt-arduino/. В основной версии можно скопировать код примеров (Дзен не подходит для таких технических статей, как эта), а также вносятся правки при необходимости - поэтому версии на Дзене могут отличаться от статей на сайте. Благодарю за понимание.

Пролог

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

Когда-то я написал статью Телеметрия на ESP8266 + MQTT. Пошаговое руководство по созданию DIY-проекта с удаленным управлением, в которой было достаточно подробно (на мой взгляд) рассказано, как создать проект для Arduino и ESP8266. Насколько мне известно, очень многие читатели пытались адаптировать код, приведенный в ней, и для ESP32. Но сделать это оказалось не очень просто и не всем под силу, потому что: 1) ESP8266 отличается от ESP32 довольно значительно, 2) в фреймворке Arduino ESP32 (который как раз и является адаптацией ESP-IDF под принципы Arduino) используются немного другие библиотеки, классы и методы работы. Разумеется, у начинающих программистов это может вызывать некоторые трудности. Многие просили помочь с адаптацией кода.

Поэтому я и решил написать новую статью, специально ориентированную под фреймворк Arduino ESP32, все-таки ESP8266 сильно устарел. Хотя мне и не очень нравится такой подход в программировании ESP32.

Но в данной статье я, возможно, в некоторых случаях “пойду своим путём” и предложу альтернативные подходы, отличающиеся от уже известных примеров в сети Интернет. А кроме этого, расскажу про “путь самурая”, или как можно легко и просто использовать библиотеки ESP-IDF в проектах Arduino.

Я то расскажу, но Вы сами вольны решать – какой способ вы будете использовать для вашего проекта.

О чем эта статья?

Данная статья ориентирована в первую очередь на начинающих программистов, которые хотят научиться программированию микроконтроллеров ESP32. Не тупо переписать код из примеров, а разобраться и понять – почему это сделано так и как можно сделать по другому. Поэтому без необходимой “теории” не обойдется, будет много “лишнего” текста. В этой и последующих статьях серии я постараюсь максимально подробно рассказать, как создать проект на ESP32 с подключением к сети WiFi и удаленным управлением через MQTT с помощью фреймворка Arduino. Ибо зачем ещё связываться с ESP32, если не подключать его к сети? – для автономной работы есть огромная куча других микроконтроллеров. Конечно, никто не запрещает использовать ESP32 в полностью автономном режиме, но по опыту знаю, что ESP32 обычно в первый раз покупают, чтобы подключить его к сети и порулить им на расстоянии. Ведь вы за этим и открыли данную страницу сайта? Итак…

В данной статье я достаточно подробно расскажу как:

  1. Создать Arduino – проект для ESP32 в различных IDE: Arduino IDE v2, Visual Studio Code+PlatformIO и Visual Studio Code+ESP-IDF в режиме “Arduino как компонент ESP-IDF”.
  2. Настроить проект в минимальной комплектации
  3. Подключить необходимые библиотеки к проекту
  4. Подключить ESP32 к вашей сети WiFi.
  5. Получить точное текущее время с NTP-сервера в интернете.
  6. Подключиться к MQTT-брокеру, в том числе и по TLS/SSL-протоколу
  7. Отправить HTTP или HTTPS запрос на какой-нибудь сервер в сети интернет
  8. Сохранять значения параметров на FLASH-памяти ESP32

Вам понадобятся:

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

Оглавление

Ссылки по прежнему ведут на основную статью - я их не исправлял здесь!Знакомство с ESP32
Особенности программирования в многозадачной среде RTOS
Загрузчик (bootloader) и flash-память
Фреймворк (платформа) Arduino ESP32
Настройка параметров native библиотек и проекта
Настройка таблицы разделов flash-памяти

1. Создаем и настраиваем новый проект
1.1. Arduino IDE
1.1.1. Подготовка Arduino IDE к работе
1.1.2. Создаем новый проект
1.1.3. Настраиваем проект Arduino IDE
1.1.4. Подключение сторонних библиотек к проекту Arduino IDE
1.2. Visual Studio Code + PlatformIO
1.2.1. Подготовка PlatformIO к работе
1.2.2. Создаем новый проект
1.2.3. Настраиваем проект PlatformIO
1.2.4. Подключение сторонних библиотек к проекту PlatformIO
1.3. ESP-IDF + Arduino как компонент в проекте ESP-IDF
1.3.1. Подготовка к работе
1.3.2. Создаем новый проект
1.3.3. Настраиваем проект ESP-IDF + Arduino ESP32 1.3.4. Подключение сторонних библиотек к проекту ESP-IDF + Arduino ESP32

2. Подключение к сети WiFi
2.1. Простой пример подключения в режиме STA
2.2. Классы WiFi и с чем их едят
2.2.1 Подключение к сети WiFi в режиме STA
2.2.1.1 Управление автоматическим подключением и переподключением
2.2.1.2 Выбор наилучшей точки доступа
2.2.1.3 Ожидание подключения
2.2.1.4 Как проверить состояние подключения или если вдруг что-то пошло не так
Лирическое отступление от основной темы: const или #define?
2.3. Оптимизируем процесс подключения2.3.1. Отслеживаем состояние WiFi в рабочем цикле
2.3.2. Отслеживаем состояние WiFi через calback

3. Получение актуальной даты и времени с серверов NTP
3.1. Вариант “на языке Arduino”
3.2. Вариант “на языке ESP-IDF”

4. Подключение к MQTT-брокеру
4.1. Подключение к MQTT серверу с помощью PubSubClient
4.1.1. Подключаем библиотеку PubSubClient к проекту
4.1.2. Класс PubSubClient и с чем его едят
4.1.3. Подключение к MQTT без шифрования
4.1.4. Подключение к MQTT с использованием TLS-шифрования
4.1.4.1. Библиотека NetworkClientSecure
4.1.4.2. Добавляем TLS-подключение в функцию подключения к MQTT серверу
4.1.4.3. Переключение режимов сборки скетча с помощью условных макросов
4.1.5. Публикация исходящих данных на MQTT-сервере
4.1.6. Оформление подписки и получение входящих данных от MQTT-сервера
4.2. Подключение к MQTT серверу с помощью ESP MQTT Client
4.2.1. Подключение к MQTT серверу

5. Создаем и отправляем HTTP(S) запросы
5.1. Отправка запросов с помощью Arduino WiFiClient
5.1.1 Динамическое и статическое создание экземпляра WiFiClient
5.1.2 Отправка GET-запроса с использованием WiFiClient
5.1.3 Отправка POST-запроса с использованием WiFiClient
5.2. Библиотека Arduino HTTPClient
5.2.1 Отправка GET-запроса с использованием HTTPClient
5.2.2 Отправка POST-запроса с использованием HTTPClient
5.3. Библиотека ESP-IDF ESP HTTP Client
5.3.1 Отправка GET-запроса с использованием ESP HTTP Client
5.3.2 Отправка GET-запроса с использованием ESP HTTP Client

6. Сохранение значений переменных в энергонезависимой памяти
6.1. Библиотека EEPROM (устаревший способ)
6.2. Библиотека Preferences (рекомендуемый способ)
6.2.1. Порядок работы с библиотекой Preferences
6.2.2. Пример использования
6.3. Библиотека NVS для ESP-IDF

Знакомство с ESP32

Прежде чем мы начнем, необходим четко уяснить, чем ESP32 отличается от ESP8266 и Arduino-контроллеров, с которыми вы, возможно, имели дело ранее.

Весь программный интерфейс (API) ESP32 спроектирован так, чтобы всегда работать под управлением операционной системы реального времени FreeRTOS. То есть “внутри” прошивки любого ESP32 будет всегда работать планировщик, задачи, очереди, мьютексы и вот это все.

– “Позвольте“, спросит кто-то, “я запускаю Arduino IDE”, создаю новый проект, там есть setup() и loop(), и нет никаких портосов! Знать ничего не знаю и не знать хочу!

Ответ состоит в том, что если вы не видите суслика FreeRTOS, это ещё не значит что его нет! Он запускается на нулевом ядре при старте ESP32 и сидит тихо мирно и починяет примус выполняет некоторые фоновые задачи – работает планировщик, службы таймеров, сторожевой таймер WDT и некоторые другие.

Дело в том, что ваш Arduino-проект, код которого вы видите у себя на экране – это всего-лишь пользовательская задача FreeRTOS, которая запускается уже на первом ядре с размером стека 8 килобайт. По умолчанию, Arduino Core создает задачу, которая вызывает функции setup() и затем бесконечно вызывает loop() внутри FreeRTOS-задачи.

Пример простейшего Arduino-кода:

-2

Внутри Arduino-ESP32 этот скетч запускается примерно так (упрощённо)

-3

Примерно так же можете и вы – запускать задачи, создавать очереди, события и прочие объекты FreeRTOS. Даже из Arduino IDE. А также пользоваться многими другими API, которые есть в ESP-IDF. Для всего этого в Espressif разработали платформу Arduino ESP32 (мне еще попадалось название просто Arduino32).

Особенности программирования в многозадачной среде RTOS

Поскольку ESP32 работает под управлением операционной системы реального времени (RTOS), это необходимо всегда “держать в уме”. Даже если вы не создаете никаких задач, очередей и каких-либо других объектов FreeRTOS.

Повторю ещё и ещё раз: ваш Arduino-скетч – это одна из задач FreeRTOS. В связи с этим вам придется познакомиться с понятиями как задача, планировщик задач, приоритет и т.д. и т.п.

Кардинальная смена идеологии программирования

Давайте вспомним, как нас учили (и учат до сих пор) программировать в Arduino на простых однопоточных контроллерах без каких то там RTOS:

  • Рабочий цикл loop() должен выполняться непрерывно и каждый его цикл должен занимать как можно меньше времени
  • Использование функций для генерации задержек типа delay() считается дурным тоном, так как “крадет” время процессора и противоречит предыдущему пункту

На ESP32 это уже не совсем так. Можно даже сказать – наоборот. Этот момент требует отдельного пояснения.

В FreeRTOS используется вытесняющая многозадачность (preemptive multitasking). Это значит, что любая задача может быть прервана планировщиком операционной системы, если появляется задача с более высоким приоритетом, или для переключения между задачами с одинаковым приоритетом (тайм-слисинг, то есть по таймеру). Таким образом, задачи не обязаны сами уступать управление — планировщик сам решает, когда и какую задачу запускать, чтобы обеспечить справедливое распределение времени между ними. Но, с другой стороны, управление задачам с меньшим приоритетом может быть передано только в том случае, если нет “бодрствующих” задач с большим приоритетом.

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

Если не соблюдать это требование (добровольный уход в сон) и попытаться выполнять цикл задачи непрерывно, через какое время сработает сторожевой таймер WDT и погрозит пальчиком – “ай-ай-ай, нехорошо это!”.

В связи с этим и принцип работы delay() кардинально изменился на противоположный: если раньше с помощью него мы просто тупо приостанавливали выполнение программы, то на ESP32 в фреймворке Arduino ESP32 он просто вызывает тот же самый vTaskDelay(), который просто заставляет задачу “заснуть” на заданное количество тиков операционной системы. То есть не “приостанавливает выполнение всего-всего-всего“, а “передает управление другому“.

-4

Обо всем этом более подробно можно почитать в другой статье: ESP-IDF: а что под капотом? Обзор базовых объектов.

Подведем итоги:

  • Было на Arduino AVR и ESP8266 (NO RTOS)loop() должен выполняться как можно быстрее и непрерывно, delay() не желателен, так как “крадет” время процессора
  • Стало на ESP32 (причем не важно – ESP-IDF или Arduino ESP32): желательно, чтобы цикл задачи добровольно периодически отдавал управление задачам с меньшим приоритетом с помощью delay()vTaskDelay() или функций ожидания; delay() работает по другому.

К слову, есть ещё один вариант добровольно отдать управление – макрос taskYIELD(), но он просто позволяет отдать управление планировщику до истечения выделенного задаче кванта времени и не влияет на задачи с меньшим приоритетом.

Необходимость защиты персональных данных блокировки совместного доступа к одним и тем же ресурсам из разных задач

Каждая задача имеет свой собственный и глубоко личный стек и некоторые другие данные, которые в совокупности называются контекстом задачи. Контекст задачи — это среда выполнения кода внутри задачи RTOS, со всеми её атрибутами: собственным стеком, приоритетом и возможностью быть вытесненной планировщиком задач. В стеке сохраняются локальные переменные, аргументы и адреса возврата вызываемых функций и состояние регистров процессора при переключении управления при прерываниях. Залезать в “чужой” стек категорически не допускается.

Кроме вашей задачи, в системе запущены и работают и другие задачи, например системный цикл событий, который по обрабатывает поступающие сигналы из всех других задач. А ещё есть обработчики прерываний. Все они могут вызывать те или иные функции обратного вызова (callbacks). И эти самые обработчики функций обратного вызова, если вы их используете, как правило вызываются не из контекста вашего скетча, а из контекста цикла событий или прерываний!

Из всего этого следует простой вывод: на ESP32 “по умолчанию” запрещен прямой доступ к данным задач из функций обратного вызова и прерываний. Даже если вы знать ничего не хотите об этой вашей RTOS. Конечно, иногда могут быть исключения. Например – атомарные операции, когда данные в переменную записываются за один такт процессора. Теоретически это должны быть целые числа до INT32, но…. официальная документация Espressif знать об этом ничего не знает. А по этому не стоит надеяться на это на все 100%.

Прерывание выполнения задачи в любой момент

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

Выводы

Из всех вышесказанного можно сделать вывод: хотите сами программировать ESP32 – будьте добреньки изучить хотя бы самый минимум по FreeRTOS и многопоточной безопасности. По другому – никак. Иначе будут проблемы, глюки, сбои и спонтанные перезагрузки по казалось бы непонятным причинам.

Загрузчик (bootloader) и flash-память

Чипы ESP8266 и ESP32 имеют довольно небольшой размер встроенной EPROM-памяти – в него помещается только специальная программа – загрузчик первой очереди. Для хранения и запуска двоичного скомпилированного кода программ и данных используется внешняя (или в некоторых случаях встроенная непосредственно в чип) микросхема flash-памяти. Под словом “внешняя” в данном случае понимается то, что она находится вне корпуса чипа (но для модулей она находится внутри модуля, под жестяной крышечкой). Микросхема flash-памяти подключена к микроконтроллеру через один из интерфейсов SPI. Стандартный размер flash-памяти – 4Мб, но могут быть и другие варианты – 2, 8 или 16 Мб.

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

  • если вы планируете хранить какие-либо настройки, вам потребуется раздел nvs,
  • для хранения прошивки – необходим раздел app,
  • если планируете использовать “обновления по воздуху” (OTA) – то нужны уже как минимум два раздела app,
  • для создания файлов потребуется раздел spiffs или ffat.

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

Итак, ваша прошивка храниться на flash-памяти. Как она запускается? При запуске CPU из встроенной EPROM запускается загрузчик первой очереди. Он инициализирует некоторое “железо”, регистры, подключается к flash-памяти и запускает из специального раздела загрузчик второй очереди. Загрузчик второй очереди выполняет всю остальную работу по считыванию и запуску вашей прошивки.

Этот же самый bootloader управляет и записью прошивки на flash-память. Он позволяет загружать скомпилированный вами код в микроконтроллер без использования специальных аппаратных программаторов. То есть по сути это программный программатор ESP. Именно он берет на себя функции получения двоичных данных из UART и записи на flash-память.

Перевод загрузчика в режим программирования (приема прошивки) производится с помощью strapping pin GPIO0 – низкий уровень на этом выводе при сбросе микроконтроллера означает, что загрузчику нужно быть готовым к принятию двоичных данных прошивки. К этому выводу почти на всех платах с ESP подключена кнопка BOOT. Соответственно для перевода ESP32 в режим программирования необходимо зажать кнопку BOOT, и не отпуская её, кратковременно нажать кнопку RESET. После данных манипуляций микроконтроллер переходит в режим программирования.

На платах разработчика (ESP32-DevKit-V1, ESP32-DevKitС-V4 и подобных) обычно стоит специальная схема для управления уровнями на GPIO0 и RESET, поэтому нажимать кнопку BOOT обычно не требуется. Но для плат типа ESP32 Relay X4 приходится выполнять данные манипуляции вручную.

Фреймворк (платформа) Arduino ESP32

Arduino ESP32 — это платформа, предоставляющая поддержку микроконтроллеров серии ESP32 (и их вариантов, таких как ESP32-C3, ESP32-S2, ESP32-S3 и др.) в среде разработки Arduino. Это позволяет использовать привычный и простой язык программирования Arduino (C++) и его экосистему библиотек для разработки приложений под чипы Espressif, не вдаваясь в детали низкоуровневого программирования или работы с официальным фреймворком ESP-IDF. Проект поддерживается Espressif и сообществом, и его документация доступна онлайн здесь.

В его состав входит Arduino core (ядро Arduino для ESP32) — это программный слой, который реализует совместимость между аппаратной платформой ESP32 и стандартным API Arduino. Он включает драйверы, библиотеки и интеграцию с Arduino IDE, чтобы код, написанный для Arduino, мог работать на ESP32. Таким образом, Arduino core для ESP32 — это адаптация Arduino API и среды для работы с чипами Espressif.

В состав фреймворка Arduino ESP32 входят как адаптации под ESP32 уже привычных стандартных Arduino-библиотек; так и специальные библиотеки, реализующие работу с аппаратными возможностями чипов ESP32:

  • ArduinoOTA — обеспечивает обновление прошивки “по воздуху” (OTA)
  • AsyncUDP — асинхронная работа с UDP-протоколом
  • BLE — поддержка Bluetooth Low Energy (BLE) v4.2
  • BluetoothSerial — сервер последовательной передачи данных по Bluetooth Classic (только для ESP32, не поддерживается на ESP32-S2, ESP32-C3, ESP32-S3)
  • DNSServer — базовый DNS-сервер, включая captive portal
  • EEPROM — эмуляция EEPROM в NVS-разделе Fдфыр-памяти, можно использовать для быстрого перехода с других микроконтроллеров
  • ESP32 — здесь собраны дополнительные примеры для работы с аналоговым выводом, камерой, DeepSleep, FreeRTOS, GPIO, I2S, Touch и др.
  • ESPmDNS — сервис mDNS
  • Ethernet — поддержка Ethernet-соединений для плат, которые имеют контроллер Ethernet
  • FFatLittleFSSPIFFS — поддержка различных файловых систем для работы с Flash-памятью
  • HTTPClientHTTPUpdateHTTPUpdateServer — работа с HTTP-запросами и обновлениями по HTTP
  • NetBIOS — NetBIOS name advertiser
  • Preferences — энергонезависимое хранилище параметров в виде пар “ключ”-“значение”, более удобная и во всем лучшая альтернатива EEPROM
  • ESP RainMaker — поддержка платформы RainMaker для быстрого создания IoT-устройств
  • SDSD_MMC — библиотека для работы с SD-картами
  • SimpleBLE — минимальный BLE advertiser
  • SPI — драйвер SPI, поддерживается только режим master
  • SR — библиотека для AI-решений на базе ESP32-S3 и ESP32-P4 (например, распознавание речи)
  • Ticker — таймер для вызова функций по интервалам
  • Update — библиотека для обновления скетча через OTA
  • USB — драйвер USB (только device)
  • WebServer — простой HTTP-сервер
  • WiFi — драйвер Wi-Fi
  • NetworkClientSecure — Wi-Fi клиент с поддержкой TLS-шифрования
  • Wire — драйвер шины I2C

Для каждой библиотеки есть примеры использования, которые можно найти в папке examples соответствующей библиотеки. Некоторые библиотеки реализуют стандартные Arduino API, другие — специфичны только для ESP32 и расширяют возможности платформы Arduino. Полный список и описание библиотек можно найти в официальной документации и в README arduino-esp32.

Но для разработчиков Arduino ESP32 доступны нее только эти библиотеки, но и многие библиотеки ESP-IDF – в чем мы сегодня с вами и убедимся. В данной статье будут примеры использования нативных библиотек ESP-IDF в обычном коде Arduino.

Что мы теряем при использовании Arduino ESP32?

То есть получается, что нет необходимости использовать ESP-IDF? Ведь все равно все и так доступно.

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

С одной стороны это, конечно же так. Но давайте посмотрим, что мы теряем, если отказываемся от “чистой” ESP-IDF. Если использовать Arduino ESP32 вместо ESP-IDF, вы получаете более простой и быстрый старт, но теряете ряд возможностей и гибкости, которые предоставляет официальный фреймворк Espressif:

  • Ограниченный доступ к низкоуровневым функциям и настройкам. Arduino core инкапсулирует только часть функций ESP-IDF, поэтому некоторые продвинутые возможности и тонкая настройка железа могут быть недоступны или сильно ограничены.
  • Ограниченные возможности настройки. В Arduino IDE отсутствует штатная возможность редактирования файла sdkconfig.h, который используется для настройки проекта. В стандартной Arduino IDE изменить параметры sdkconfig напрямую нельзя, так как Arduino ESP32 использует заранее скомпилированные библиотеки, и изменения в файлах sdkconfig или sdkconfig.h внутри проекта Arduino не повлияют на итоговую прошивку. См. следующий раздел.
  • Ограниченные возможности отладки. В Arduino IDE отсутствуют продвинутые инструменты отладки, которые доступны в ESP-IDF (например, интеграция с VSCode/Eclipse, трассировка, профилирование и др.).
  • Меньше гибкости для сложных проектов. Для сложных и профессиональных проектов, где требуется модификация низкоуровневого кода, использование оригинального ESP-IDF гораздо предпочтительнее, так как Arduino core не позволяет менять внутренние механизмы работы фреймворка.
  • Ограниченная поддержка новых функций и чипов. Некоторые новые возможности и поддержка последних чипов могут появляться в ESP-IDF раньше, чем в Arduino core, либо быть недоступны вовсе.
  • Меньше возможностей для оптимизации. В ESP-IDF доступны гибкие настройки компиляции, управления памятью, энергопотреблением и т.д.

Таким образом, Arduino ESP32 подходит для новичков и быстрой разработки, прототипирования и простых проектов, но для профессиональной разработки и использования всех возможностей чипа рекомендуется использовать другой фреймворк ESP-IDF, который предоставляет больше гибкости и необходимых инструментов.

И я с этим полностью согласен и поэтому я не использую Arduino ESP32 в своих проектах. И вам не советую. Но вы ж меня не слушаете, и продолжаете “стоять на своем”. Что ж… Сами просили, сами виноваты – теперь читайте…

Настройка параметров native библиотек и проекта

Файл sdkconfig в проекте ESP-IDF (и Arduino ESP32 тоже) хранит текущие значения всех параметров конфигурации проекта, таких как настройки железа, опции компиляции, таблица разделов flash-памяти, параметры компонентов и т.д. Этот файл автоматически обновляется при изменении конфигурации через специальные инструменты и не рекомендуется для ручного редактирования, так как между параметрами могут быть зависимости, которые легко нарушить вручную.

Как редактировать sdkconfig:

  • Основной способ — использовать команду py menuconfig, которая открывает текстовый интерфейс для настройки всех параметров. После сохранения изменения автоматически записываются в файл sdkconfig.
  • Также можно использовать IDE с поддержкой ESP-IDF (например, Visual Studio Code с ESP-IDF плагином или Espressif-IDE), где есть графический редактор конфигурации, работающий с этим файлом.

Но изменение sdkconfig в случае использования Arduino ESP32 напрямую невозможно! Это связано с тем, что ESP-IDF библиотеки включаются в проект Arduino как уже собранные бинарные файлы, см. FAQ Arduino-esp32.

Если вам все-таки нужно изменить параметры sdkconfig, есть два поддерживаемых способа:

  1. Использовать Arduino как компонент в проекте ESP-IDF
    Вы создаёте проект на ESP-IDF и добавляете Arduino как компонент. В этом случае вы получаете доступ к инструменту
    menuconfig и можете настраивать sdkconfig так же, как в обычном проекте ESP-IDF. Подробнее: Arduino as an ESP-IDF component.
  2. Использовать Arduino Library Builder
    Этот инструмент позволяет собрать Arduino core с нужными параметрами
    sdkconfig. В составе Lib Builder есть редактор sdkconfig, где вы можете изменить нужные опции перед компиляцией библиотек. Подробнее: Library Builder — Sdkconfig Editor.

В данном проекте нам не потребуется что-либо изменять, можно оставить значения по умолчанию. Этот раздел был изложен просто для общего понимания ситуации, и может пригодится вам в будущем.

Настройка таблицы разделов flash-памяти

Одним из самых важных параметров ESP32, является таблица разделов flash-памяти. Если вы когда-либо создавали проекты с помощью ESP-IDF, то наверняка знаете, что можно создать произвольную “разметку диска”, которую потом подгрузить в систему сборки с помощью вышеупомянутой системы конфигурации ESP-IDF menuconfig. Об этом я писал в статье Настройка таблицы разделов FLASH-памяти для ESP32.

Но… как я уже написал чуть выше, фреймворк Arduino ESP32 лишает нас нормальной возможности пользоваться menuconfig. Дабы обойти это ограничение, разработчики придумали набор заранее настроенных таблиц разметок, из которых вы можете подобрать себе один приемлемый вариант. Набор разметок будет зависеть от того, какую именно плату вы выбрали в вашей IDE.

От выбранной таблицы разметки, в свою очередь, напрямую зависит размер раздела (или разделов) APP, в который(е) загружается ваше приложениеВы можете иметь 4 Мб flash-памяти, но не сможете, например, загрузить скетч размером более 512 Кб.

Например, для платы ESP32 Dev Module этот перечень может выглядеть так:

  • Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)разметка для модулей с 4 Мб flash “по умолчанию” с поддержкой SPIFFS и OTA:
    раздел nvs размером 0x5000 байт (что составляет 20480 байт в десятичном выражении или 20 Кб),
    2 раздела app (ota_0 & ota_1) по 0x140000 байт (что составляет 1,25 Мб) каждый,
    раздел
    spiffs размером 0x160000 байт (что составляет 1,375 Мб),

    раздел
    coredump размером 0x10000 байт (что составляет 64 Кб).
  • Default 4MB with ffat (1.2MB APP/1.5MB FATFS)почти то же самое, но раздел SPIFFS заменен на FFAT:
    раздел nvs размером 0x5000 байт,
    2 раздела app (ota_0 & ota_1) по 0x140000 байт каждый,
    раздел
    ffat размером 0x160000 байт,

    раздел
    coredump размером 0x10000 байт.
  • 8M with spiffs (3MB APP/1.5MB SPIFFS) разметка для модулей с 8 Мб flash с поддержкой SPIFFS и OTA:
    раздел nvs размером 0x5000 байт,
    2 раздела app (ota_0 & ota_1) по 0x330000 байт каждый,
    раздел
    spiffs размером 0x180000 байт,

    раздел
    coredump размером 0x10000 байт.
  • Minimal (1.3MB APP/700KB SPIFFS)минималистичный вариант для модулей с 4 Мб flash, имеет только один раздел app, поэтому не подходит для OTA
    раздел nvs размером 0x5000 байт,
    1 раздел app (ota_0) размером 0x140000 байт,
    раздел
    spiffs размером 0xA0000 байт,

    раздел
    coredump размером 0x10000 байт.
  • No OTA (2MB APP/2MB SPIFFS) вариант без ОТА для модулей с 4 Мб flash, имеет только один раздел app
    раздел nvs размером 0x5000 байт,
    1 раздел app (ota_0) размером 0x200000 байт,
    раздел
    spiffs размером 0x1E0000 байт,

    раздел
    coredump размером 0x10000 байт.
  • No OTA (1MB APP/3MB SPIFFS) вариант без ОТА для модулей с 4 Мб flash, имеет только один раздел app
    раздел nvs размером 0x5000 байт,
    1 раздел app (ota_0) размером 0x100000 байт,
    раздел
    spiffs размером 0x2E0000 байт,

    раздел
    coredump размером 0x10000 байт.
  • No OTA (2MB APP/2MB FATFS) аналогично пред-предыдущему варианту, но с FFAT
    раздел nvs размером 0x5000 байт,
    1 раздел app (ota_0) размером 0x200000 байт,
    раздел
    ffat размером 0x1E0000 байт,

    раздел
    coredump размером 0x10000 байт.
  • No OTA (1MB APP/3MB FATFS) аналогично пред-предыдущему варианту, но с FFAT
    раздел nvs размером 0x5000 байт,
    1 раздел app (ota_0) размером 0x100000 байт,
    раздел
    ffat размером 0x2E0000 байт,

    раздел
    coredump размером 0x10000 байт.
  • Huge APP (3MB No OTA/1MB SPIFFS) вариант без ОТА с относительно небольшим разделом spiffs для модулей с 4 Мб flash
    раздел nvs размером 0x5000 байт,
    1 раздел app (ota_0) размером 0x300000 байт,
    раздел
    spiffs размером 0xE0000 байт,

    раздел
    coredump размером 0x10000 байт.
  • Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS)вариант для модулей с 4 Мб flash с поддержкой OTA и минимальным разделом SPIFFS
    раздел nvs размером 0x5000 байт,
    2 раздела app (ota_0 и ota_1) размером по 0x1E0000 байт каждый,
    раздел
    spiffs размером 0x20000 байт,

    раздел
    coredump размером 0x10000 байт.
  • 16M Flash (2MB APP/12.5MB FATFS) разметка для модулей с 16 Мб flash с огромным разделом FFAT и с поддержкой OTA:
    раздел nvs размером 0x5000 байт,
    2 раздела app (ota_0 & ota_1) по 0x200000 байт каждый,
    раздел
    spiffs размером 0xBE0000 байт,

    раздел
    coredump размером 0x10000 байт.
  • 16M Flash (3MB APP/9.9MB FATFS) – разметка для модулей с 16 Мб flash с большим разделом FFAT и с поддержкой OTA:
    раздел nvs размером 0x5000 байт,
    2 раздела app (ota_0 & ota_1) по 0x300000 байт каждый,
    раздел
    spiffs размером 0x9E0000 байт,

    раздел
    coredump размером 0x10000 байт
  • RainMakerразметка без файловых систем, но с поддержкой “больших” OTA и двумя NVS-разделами для разных задач
    2 раздела nvs размерами 0x5000 и 0x6000 байт,
    2 раздела app (ota_0 & ota_1) по 0x1E0000 байт каждый,
    раздел
    coredump размером 0x10000 байт

Примечание: числа 0x00000 представлены в шестнадцатеричном формате.

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

А как же собственные варианты? А никак! Точнее – в Arduino IDE почти никак. Добавить свою разметку можно, путем редактирования существующей, но при обновлении платформы ваши изменения будут уничтожены.

Курс молодого бойца-ардуинщика будем считать пройденным, можно создавать проект.

Продолжение следует...