Найти в Дзене
DGO шпаргалка

Zephyr RTOS в PlatformIO. Эксперименты. Часть 3. app.overlay. Нужно помигать чем-то другим!

Zephyr RTOS в PlatformIO. Эксперименты. Часть 1. UART Zephyr RTOS в PlatformIO. Эксперименты. Часть 2. prj.conf. Нужно чем-то помигать! Всем привет! Продолжаем эксперименты с Zephyr RTOS в среде PlatformIO. На этот раз познакомимся с таким важным файлом как app.overlay. Целью оверлеев devicetree обычно является настройка аппаратного обеспечения, используемого приложением. Система сборки автоматически ищет этот файл и берет конфигурацию из него в более приоритетном порядке, чем из zephyr.dts, так что мы можем настроить всю нужную нам периферию не копаясь в перегруженной общей конфигурации. Создать файл можно кликнув правой кнопкой мыши по тому же каталогу, в котором находится наш prj.conf и создать новый файл с именем app.overlay: Нужно что-то туда написать! Например настроим работу светодиода на пине PA2. Описание периферии происходит в соответствии со стандартом Devicetree, описанном на одноименном сайте. Так же о работе с "деревом" можно узнать и в официальной документации к Zeph
Оглавление

Zephyr RTOS в PlatformIO. Эксперименты. Часть 1. UART

Zephyr RTOS в PlatformIO. Эксперименты. Часть 2. prj.conf. Нужно чем-то помигать!

Всем привет! Продолжаем эксперименты с Zephyr RTOS в среде PlatformIO. На этот раз познакомимся с таким важным файлом как app.overlay.

Электрический светодиодный зефир. Как обычно.
Электрический светодиодный зефир. Как обычно.

Целью оверлеев devicetree обычно является настройка аппаратного обеспечения, используемого приложением. Система сборки автоматически ищет этот файл и берет конфигурацию из него в более приоритетном порядке, чем из zephyr.dts, так что мы можем настроить всю нужную нам периферию не копаясь в перегруженной общей конфигурации.

Создание файла.

Создать файл можно кликнув правой кнопкой мыши по тому же каталогу, в котором находится наш prj.conf и создать новый файл с именем app.overlay:

создали пустой файл
создали пустой файл

Нужно что-то туда написать! Например настроим работу светодиода на пине PA2. Описание периферии происходит в соответствии со стандартом Devicetree, описанном на одноименном сайте. Так же о работе с "деревом" можно узнать и в официальной документации к Zephyr.

Содержимое!

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

Синтаксис в соответствии со стандартом devicetree по примеру оформления в файле prj.conf.

В самом начале корневой узел "/ " - он является началом дерева устройств. Все остальные узлы и свойства находятся внутри этого корневого узла.

/ { // Корневой узел /

Далее настройка псевдонимов:

aliases { // псевдонимы
myled = &led_green; // сделаем псевдоним myled для ссылки на переменную led_green
};

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

leds { //группа "светодиоды"
compatible = "gpio-leds"; //совместимость
led_green: led_3 { //наш псевдоним
gpios = < &gpioa 0x2 GPIO_ACTIVE_HIGH>; // синтаксическое описание GPIO
};
};

compatible = "gpio-leds"; — это свойство указывает, что данный узел совместим с драйвером gpio-leds. Это означает, что операционная система будет использовать драйвер для управления светодиодами, подключенными через GPIO.

&gpioa — ссылка на GPIO-контроллер (в данном случае, это порт A).

0x2 — номер пина на GPIO-контроллере (в данном случае, это пин 2).

GPIO_ACTIVE_HIGH — указывает, что светодиод будет активен (включен) при высоком уровне сигнала на этом пине.

Теперь просто меняем в main.c идентификатор диода на только что созданный myled и проверяем.

Собираем по схеме из первой статьи. Не нужно забывать перемычку BOOT0-3V3
Собираем по схеме из первой статьи. Не нужно забывать перемычку BOOT0-3V3

Прошиваем и всё работает. После удаления перемычки и перезагрузки.

Диодик мигает, ручки трясутся от радости!
Диодик мигает, ручки трясутся от радости!

... и ещё немного подробностей!

Почему так сложно просто помигать светодиодом?

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

код функции main().
код функции main().

Например, функция gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE) настраивает GPIO-пин как выход (output) и устанавливает на нем активный уровень — высокий, GPIO_ACTIVE_HIGH. И сразу же проверяется удалась ли конфигурация, если ret < 0 — конфигурация не удалась (например, пин недоступен или произошла ошибка) и программа завершается.

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

-7

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

Предупреждение return type of 'main' is not 'int' [-Wmain].

Код проекта компилируется и работает. Это же код из стандартного примера для мигания светодиодиком, но функция void main() подчеркивается угрожающей волнистой линией желтого цвета и на вкладке "проблемы" появляется та самая надпись из заголовка. Это возникает потому, что стандарт языка C требует, чтобы функция main возвращала значение типа int. Это значение используется для индикации статуса завершения программы:

  • 0 — программа завершилась успешно.
  • Любое другое значение (обычно положительное) — программа завершилась с ошибкой.

Давайте это поправим!

Везде, где программа завершается из-за ошибки, будем возвращать -1 (или другое ненулевое значение), а в конце функции добавим return(0); чтобы показать, что функция завершилась успешно.

Обновленный код функции.
Обновленный код функции.

Теперь наш код соответствует стандарту и предупреждений не выдается.

Интересно так же то, что наша функция никогда не завершится с возвращением 0 из ее конца. На пути стоит бесконечный цикл while(1) и программа будет так же работать бесконечно. Если не возникнет других проблем, например отключения питания.

Заключение.

С этими знаниями можно уже пробовать реализовывать что-то более сложное, например подключить какой-то датчик и зажигать светодиод, исходя из его показаний или сделать настоящие часы, ведь на плате присутствует всё, что для этого нужно, а именно батарейка для поддержания работы модуля RTC микроконтроллера, когда система отключена от внешнего питания и часовой кварц для точного хода. А ещё в комплекте есть огромный сенсорный дисплей! Так и до реального применения РТОС не далеко. Со всей ее многозадачностью, безопасностью и широким выбором уже настроенной периферии. Если кому-нибудь, вдруг, интересно подключение чего-то конкретного, то можем в этом разобраться вместе в телеграм чате канала. Там пока тихо, но это может измениться и коллективный разум победит любую проблему. Так же, если кому-то нужны исходники проекта из статьи, могу закинуть туда. Всем спасибо за просмотр! Как всегда буду рад комментариям. До свидания!