Рубрики
Схемы на Arduino

Программирование модуля ESP32 в двухъядерном режиме с помощью Arduino IDE

Модули ESP весьма популярны в современной радиоэлектронике благодаря наличию в них функциональности Wi-Fi. К подобным модулям можно отнести ESP8266, ESP-12E и т.д. Но среди этих модулей есть один, который отличается большей вычислительной мощностью и большей универсальностью чем другие подобные модули – это модуль ESP32. В нем реализована поддержка Bluetooth, BLE и Wi-Fi, благодаря чему он весьма часто используется в проектах, связанных с технологией интернета вещей (IoT – Internet of Things). Но не все знают, что ESP32 является двухъядерным (Dual-core) микроконтроллером. Иногда его называют не микроконтроллером, а модулем.

ESP32 имеет в своем составе два 32-битных микропроцессора Tensilica Xtensa LX6, благодаря которым он является достаточно мощным двухъядерным (core0 и core1) микроконтроллером. ESP32 доступен в двух вариантах – одноядерный и двухъядерный, но более распространен двухъядерный вариант поскольку он стоит лишь немногим дороже чем одноядерный.

Структурная схема микроконтроллера ESP32 представлена на следующем рисунке.

ESP32 можно программировать с помощью Arduino IDE, Espressif IDF, Lua RTOS и т.д. При программировании с помощью Arduino IDE код программы будет исполняться только на первом ядре (Core1) поскольку нулевое ядро (Core0) будет уже запрограммировано для решения задач радиочастотной связи. Но в данной статье мы рассмотрим как использовать оба ядра ESP32 для выполнения двух операций одновременно. Первой из этих задач будет мигание встроенным светодиодом, а второй – считывание данных температуры с датчика DHT11. Но вначале давайте рассмотрим преимущества многоядерных микропроцессоров над одноядерными.

Преимущества многоядерных микропроцессоров

  1. Многоядерные микропроцессоры особенно полезны когда требуется выполнять два или более процесса одновременно.
  2. Поскольку работа распределена между несколькими ядрами, то это позволяет выполнить некоторые задачи быстрее.
  3. Для многоядерных микропроцессоров можно уменьшить энергопотребление, поскольку когда какое-нибудь ядро находится в холостом режиме (idle mode), оно может быть использовано для отключения периферийных устройств, которые не используются в текущий момент времени.
  4. Двухъядерным микропроцессорам нет необходимости так часто переключаться между различными потоками задач как одноядерным микропроцессорам, поскольку они могут обрабатывать два потока задач одновременно вместо одного.

ESP32 и FreeRTOS

Модуль ESP32 имеет встроенное в него программное обеспечение FreeRTOS, которое представляет собой операционную систему реального времени, особенно полезное при выполнении многозадачных процессов. RTOS помогает в управлении ресурсами и максимизирует производительность системы. FreeRTOS имеет множество API (прикладного программирования) функций для различных целей и с помощью этих функций мы можем запускать различные задачи на различных ядрах.

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

Определение идентификатора ядра (core ID) ESP32

В этом проекте мы будем использовать среду Arduino IDE для загрузки кода программы в модуль ESP32. Для определения идентификатора ядра (core ID), на котором исполняется код, существует специальная API функция.

Эту функцию можно вызывать внутри функций void setup() и void loop() для определения идентификатора ядра, на котором эти функции выполняются.

Вы можете протестировать эту API функцию при помощи следующего скетча:

После загрузки этого скетча в модуль откройте окно монитора последовательной связи (Serial monitor) и вы в результате выполнения представленного скетча увидите, что обе эти функции выполняются на первом ядре (core1) как показано на следующем рисунке.

Из представленного примера можно сделать вывод, что по умолчанию скетч Arduino выполняется на первом ядре (core1) модуля ESP32.

Программирование обоих ядер ESP32

Arduino IDE поддерживает FreeRTOS для ESP32 и поэтому API функции FreeRTOS позволяют нам создавать задачи, которые будут независимо исполняться на обоих ядрах. Задача в данном случае – это кусок кода программы, который выполняет определенные задачи, например, мигание светодиода, передача значения температуры и т.д.

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

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

1. Первым делом необходимо создать задачи в функции void setup. В данной статье мы создадим две задачи: одну для мигания светодиодом каждые полсекунды, а другую – для считывания значения температуры каждые 2 секунды.

Функция xTaskCreatePinnedToCore() будет содержать у нас 7 аргументов:

  1. Имя функции для выполнения задачи (task1).
  2. Любое имя, которое необходимо будет дать задаче (“task1” и т.д.).
  3. Размер стека в словах, выделенный для задачи (1 слово = 2 байта).
  4. Входные параметры задачи (может быть NULL, то есть входных параметров может не быть).
  5. Приоритет задачи (0 – это самый низкий приоритет).
  6. Идентификатор задачи (может быть NULL).
  7. Идентификатор ядра, на котором будет выполняться задача (0 или 1).

Теперь создадим нашу первую задачу (Task1) мигания светодиодом и укажем все необходимые аргументы для функции xTaskCreatePinnedToCore().

Аналогичным образом создадим задачу 2 (Task2), для которого 7-м аргументом в качестве идентификатора ядра укажем 1 (core id 1).

Вы можете изменить приоритет и размер стека в зависимости от сложности задачи.

2. Теперь мы можем выполнить функции Task1code и Task2code. Эти функции содержат код для выполнения требуемой задачи. В нашем случае первой задачей будет мигание светодиодом, а второй – считывание значения температуры. Поэтому создадим две отдельные функции для выполнения каждой из этих задач за пределами функции void setup.

Код функции Task1code для мигания светодиодом каждые 0.5 секунды при этом будет выглядеть следующим образом:

Аналогичным образом можно записать и код функции Task2code для считывания значения температуры.

3. Функцию void loop мы в нашем случае оставим пустой. Поскольку мы уже знаем, что функции loop и setup исполняются на первом ядре (core1), то мы можем выполнять задачу для первого ядра (core1) также в функции void loop.

На этом написание программы закончено, просто загрузите код программы в модуль с помощью Arduino IDE, выбрав в ней в меню Tools плату ESP32. Также убедитесь в том, что вы подсоединили датчик DHT11 к контакту D13 платы ESP32.

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

Более сложные системы реального времени можно проектировать аналогичным образом, запуская разные задачи одновременно на двух ядрах модуля ESP32.

Исходный код программы (скетча)

Видео, демонстрирующее работу проекта

14 ответов к “Программирование модуля ESP32 в двухъядерном режиме с помощью Arduino IDE”

Не совсем ясно, нулевое ядро можно использовать для задач радиочастотной связи ?

У меня наблюдаются рестарты почему-то, после того как перевел часть задачи на нулевое ядро

Теоретически это возможно, не вижу ограничений, но лично я этого не пробовал. Вы не слишком сильно его нагрузили, не перегреваются ядра? Хотя причин для рестарта может быть много

наверное от того, что я вторую задачу в лупе оставил, надо ее тоже вытащить в отдельную задачу, а луп сделать пустым

Возможно. Если у вас получится решится эту проблему — отпишитесь здесь плз. Возможно, кто то другой, читающий данную статью, столкнется с такой же проблемой как и у вас

ребутился по ватчдогу почему-то
E (22337) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (22337) task_wdt: — IDLE0 (CPU 0)
E (22337) task_wdt: Tasks currently running:
E (22337) task_wdt: CPU 0: Task2
E (22337) task_wdt: CPU 1: loopTask
E (22337) task_wdt: Aborting.
abort() was called at PC 0x40130cc8 on core 0

выставил приоритет второй задачи на 2, перестал ребутиться
но у меня в 1й задаче работа с дисплеем
во второй — wifi и blynk

Неплохо у вас так. Уже достаточно сложные задачи решаете на таком сравнительно дешевом микроконтроллере. У нас на сайте есть еще серия статей про работу в Arduino с помощью FreeRTOS (могу подсказать ссылки на них если нужно) — также можно очень продвинутые вещи в реальном времени делать, тогда ESP32 можно будет просто использовать для работы с WiFi.

Обязательно внутри задач нужно использовать delay(), тк в операционку по умолчанию включен watchdog перезапускающий ядра если нет delay() более несколько секунд.
Попробуйте без него запустить проект, если есп перезагружается , то поставьте.

Лично я этот проект не собирал, я только перевел его и на видео видно что у его авторов все заработало и без delay(). Этот проект собирали мои студенты и у них он тоже заработал без delay(). Но про необходимость использования delay() я тоже раньше читал, только вот не помню уже каких именно случаев он касается. Но в любом случае ваш комментарий останется здесь и если у кого то данный проект не получится без использования delay(), то ваш совет, возможно, поможет им доделать проект.

Ошибки в коде
(xTaskCreatePinnedToCore(Task1code, «Task1», 10000, NULL, 1, NULL, 1);
delay(500);
xTaskCreatePinnedToCore(Task2code, «Task2», 10000, NULL, 1, NULL, 0); )

Исправил. Попробуйте сейчас. Они в объяснении кода программы были записаны правильно, а в полный код программы в конце статьи закралась опечатка

Запустил на втором ядре сканирование BLE устройств.
ESP32 стала сильно греться. Если не запускать второе ядро со сканированием, то не греется.
Также при включениии второго ядра с блютус увеличивается сила тока питания до 0.12А.
Это нормально?

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

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

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