Найти в Дзене
Электроника, ESP32, Arduino

FreeRTOS в среде Aduino IDE ESP32

Папа, а что такое многозадачность Windows? - Подожди, сейчас дискету отформатирую - тогда покажу. Посмотрим как у нас с этим обстоят дела в ESP32 решив какую-нибудь практическую задачу. Информации в Интернет на эту тему более чем достаточно, копипастить её всю у меня нет ни какого желания.

Схема:

С компьютера через USB-UART на скорости 5'000'000 бод отправляется массив размером 76800 байт. Данные этого массива позволяют закрашивать дисплей последовательно в красный, зеленый, синий цвета.

Код для Arduino:

-2

Функция Serial2.readBytes(disIMG, 76800); ожидает массив с компьютера размером 76800 байт через интерфейс UART2 и сохраняет его в оперативной памяти SRAM - время выполнения 198ms

Функция myGLCD.pushImage(0, 0, 320, 240, disIMG); отправляет массив данных из оперативной памяти SRAM на экран через интерфейс SPI - время выполнения 38ms

-3

Суммарное время выполнение этих двух операторов составляет 236ms и вроде бы обновлять картинку чаще чем один раз в 236ms нет ни какой возможности, но наша еспешка работает под управлением FreeRTOS — многозадачной операционной системой реального времени.

А еще у нас есть целое ядро с индексом 0, которое в данном проекте пинает балду. В среде Arduino IDE, при разработке IoT проектов, оно используется для сетевых коммуникаций (Wi-Fi, Bluetooth), при подключении соответствующих библиотек. Библиотеки для работы с коммуникациями используют это ядро втихаря, стараясь не привлекать внимание ардуинщиков и поэтому мы можем продолжать уверенно мигать светодиодом используя различный "овнокод" - на нашем подключении например к вафле это ни как не отразится.

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

Очевидно, что SPI у нас работает быстрее чем UART и зачем нам тогда ждать отправки картинки на дисплей? Будем делать все параллельно - массив мы вычитываем быстрее, чем туда пишем. Алгоритм:

-4
  • 1-е ядро занимается приемом данных и пишет их в массив в SRAM;
  • 0-е ядро читает данные из того-же массива в SRAM и шлет их в дисплей;

Поскольку, картинку на дисплей через SPI мы выводим быстрее, чем успеваем принимать её через интерфейс UART - мы её успеем вычитать раньше, чем её перезапишет новая порция данных (0-е ядро еще и чаю попить успеет). Общую скорость работы программы мы сможем сократить до самого узкого места - времени приема данных по UART т.е. с 236ms => 198ms.

Пишем:

-5

Тут ничего интересного, создаем массив для картинки дисплея и объект для работы с дисплеем, открываем два UART порта (один для отладки, второй для передачи данных)

-6

А вот тут уже поинтереснее. В 20-й строке мы принимаем данные, а вот отправку картинки запускаем на 0-м ядре и соответственно сразу переходим к ожиданию новой порции данных. Вызываем: Task1code - выглядит как обычная функция C++, за исключением расширения vTaskDelete(). После его вызова FreeRTOS узнает, что задача завершена и ее не следует переносить. Не забудьте вызвать эту функцию, иначе сторожевой таймер перезапустит ESP32.

Отправляем с компьютера 76800 байт и видим, что наша программа стала работать на 38ms быстрее.

-7

Теперь мы ограничены только скоростью UART.

Код для Windows написан на языке С# - отправляем каждые 200ms

-8

Все работает, цвета не сыплются и ничего не виснет.

Прототип на макетной плате
Прототип на макетной плате

Что и где можно почитать по теме в Интернет:

Multitasking on ESP32 with Arduino and FreeRTOS
Распределение памяти в ESP32 – kotyara12.ru

Понятно, что FreeRTOS тема очень не простая, и то что у меня запустилась такая достаточно тяжелая задача (да еще и на библиотечных функциях) - это скорее исключение чем правило. Фишка в том, что ядра то два, а периферия то одна. Представьте, чтобы было если попытаться подергать 2 ядрами одновременно один и тот-же SPI например, ну и повезло что библиотеки не используют какие-либо общие прерывания.

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

Оглавление канала ТУТ

Всем удачи!