RomanBashmakov2 часа назад
Клавиатура Vibe-кодера на Zephyr RTOS и двухъядерном микроконтроллере STM32WB55
Уровень сложностиПростойВремя на прочтение7 минОхват и читатели3.1KЭлектроника для начинающихОперационные системыГаджетыПрограммирование микроконтроллеров*Прототипирование*КейсВ статье приведен мой опыт знакомства с Zephyr RTOS на примере создания беспроводной клавиатуры с тремя кнопками (Enter, Copy, Paste). Затронуты ключевые аспекты: настройка BLE-стека и HID-сервиса, управление энергопотреблением (STOP2, параметры соединения, программный сон), работа с Devicetree (overlay и правки dtsi), отладка через RTT, а также типичные проблемы (прошивка CPU2, EXTI-конфликты, требования HID к шифрованию). Проект полностью воспроизводим и содержит ссылки на полный исходный код и готовую прошивку.
Введение
Zephyr RTOS выглядит крайне привлекательной для домашних поделок взамен того же Arduino, и по данной ОС много теоретических и обзорных материалов/курсов (например, платный пятидневный курс за 3500$ от Linux Foundation или бесплатный - от Nordic). Но практических примеров немного и из-за этого трудно сложить однозначное представление о ней, особенно с учетом быстрого развития. Лично у меня от неё большие ожидания.
Цель - ознакомиться с процессом разработки на Zephyr RTOS и понять её применимость для изделий с аккумуляторным питанием.Подход - сделать памятный сувенир.
Подготовка инструментов
В качестве аппаратной платформы выбрана плата от WeAct на STM32WB55 (двухъядерный чип с интегрированным BLE-радио). Плата поддерживается Zephyr и подходит для широкого круга беспроводных DIY-задач. Плата представляет собою современное и интересное продолжение широко полюбившейся платы blue pill (на stm32f103), поэтому возможность поэкспериментировать с ней для меня была самоценной и тут речи нет про техническую оптимальность выбора.
Изначально я попробовал поставить средства для сборки прошивок на Zephyr RTOS на свой ПК и некоторые компоненты оказались несовместимы с моей старенькой macOS Monterey, поэтому я переключился на сборку в Docker.
Toolchain в docker'eСкачать образ со всем необходимым можно по ссылке:
docker pull zephyrprojectrtos/zephyr‑build:latest
Далее следует перейти в папку, где хотите располагать свои проекты, и там выполнить:
docker run ‑rm ‑it ‑v $(pwd):/workdir zephyrprojectrtos/zephyr‑build:latest bash
Далее развернуть репозиторий Zephyr:
west init ‑m https://github.com/zephyrproject‑rtos/zephyr ‑mr main
После этого можно будет собирать свой проект на выбранной плате с помощью команды
west build ‑b weact_stm32wb55_core ‑p autoДля отладки проекта использовался VS Code с расширением Cortex-Debug и отладчик J-Link. Так как сборка выполнялась в Docker-контейнере, а отладка - на хост-машине напрямую через SWD, то потребовалась корректная подстановки путей к исходным файлам, поскольку внутри контейнера рабочая директория отличается от локальной.
Подстановка путей (substitutePath)Из-за того, что пути к исходным файлам внутри контейнера (/workdir/...) отличаются от локальных путей на хост-машине, GDB не может найти исходники для пошаговой отладки, если не указать соответствие. В добавленном к данной статье репозитории приведён конфигурационный файл .vscode/launch.json с помощью которого можно "совмещать" предсобранный elf-файл с имеющимися исходниками. Поле "substitutePath" задаёт замену префиксов: все пути, начинающиеся с /workdir/zephyr, заменяются на локальный путь к исходникам Zephyr и т.д.Внимание! в .vscode/launch.json указаны настройки для конкретно моего ПК, но любая нейронка на основе этого примера легко подскажет, что и как скорректировать именно вам.
Кнопки
Были взяты простейшие механические свитчи, которые работают по принципу замыкания цепи:
Внешний вид клавишВ моём наборе разброс времени дребезга был от 0,2 до 1,2 мс:
Замер дребезга контактовПишут, что типовое время дребезга для свитчей такого типа составляет до 30 мс, поэтому в проекте задана именно такая величина. Выглядит много, но на практике такая задержка незаметна.Подключение кнопок.
Обработку нажатий можно было бы сделать через периодическое сканирование, но по некоторым соображениям в данном случае для меня было принципиально разобраться именно с отложенной обработкой прерываний.
Первая кнопка очень легко подключилась на пин boot_button из базового DTS платы:
Описание клавиши Enter в device treeПервые проблемыНо далее я случайным образом выбрал PA0 и PA1 и не угадал. Сначала возникла проблема с тем, что именно эти два вывода уже заняты АЦП:
Надо знать про альтернативное использование аппаратных ресурсов в DTSНо даже после того, как я напрямую отключил adc1 в overlay - всё равно осталась коллизия по каналу EXTI, с которой я с ходу не разобрался. Пока что выбрал другие пустые пины.Две другие кнопки заняли свободные пины PB6 и PB7:
buttons {
compatible = "gpio-keys";
sw1: button_1 {
gpios = <&gpiob 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>;
label = "Copy Button (Ctrl+C)";
};
sw2: button_2 {
gpios = <&gpiob 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>;
label = "Paste Button (Ctrl+V)";
};
};Работа с кнопками в итоге выглядит так:
Алгоритм обработки нажатий с учетом BLE и энергосбереженияДля отладки и проверки каждый раз при нажатии любой из клавиш зажигается встроенный светодиод на выводе PE4.
Отладочная схема:
Предварительная сборка
Bluetooth
Принцип работы BLE в Zephyr.
Zephyr реализует Host-контроллерную архитектуру, где:
• Host — всё, что работает на CPU1 (HCI-драйвер, L2CAP, ATT, GATT, SMP).
• Controller — физический уровень, LL, PHY (реализовано в прошивке CPU2).В Zephyr для STM32WB55 используется драйвер st,stm32wb-rf, который через IPCC передаёт HCI-команды и данные между CPU1 и CPU2.
Настройка BLE.
В overlay ничего добавлять не нужно, т. к. DTS на SoC уже есть:
В описании платы включено описание SoCНо вprj.conf довольно много компонентов операционной системы связано с BLE:
Фрагмент prj.conf проекта связанный с BLE# ================================================================== #
# Bluetooth LE HID-устройство ( stm32_button ) #
# #
# Радиомодуль STM32WB55 (CPU2) управляется через IPCC/IPM-драйвер #
# (drivers/bluetooth/hci/ipm_stm32wb.c). Узел ble_rf уже включён #
# в stm32wb.dtsi, а zephyr,bt-hci = &ble_rf — в chosen. #
# Поэтому CONFIG_BT_STM32_IPM включается автоматически. #
# ================================================================== #
# Базовый стек Bluetooth LE (Host + Controller-драйвер IPM) CONFIG_BT=y
# Отладочный лог HCI-драйвера IPM (ipm_stm32wb.c): показывает запуск CPU2,
# ошибки IPCC/клоков, таймаут C2_STARTED и т.п. Временно для диагностики.
# CONFIG_BT_HCI_DRIVER_LOG_LEVEL_DBG=y
# Периферийная роль (обходимся как HID-клавиатура/пульт)
CONFIG_BT_PERIPHERAL=y
# Менеджер безопасности (SMP): HID требует шифрованного канала
CONFIG_BT_SMP=y
# Хранение ключей спаривания и ID-адреса во flash (NVS).
# ВКЛЮЧЕНО: сохраняет bonding между перезагрузками (ключи, IRK, CSRK).
# ВАЖНО: при CONFIG_BT_SETTINGS=y стек НЕ создаёт ID-адрес сам.
# Приложение обязано вызвать settings_load() ПОСЛЕ bt_enable()
# (в callback'е bt_ready в ble.c), иначе реклама падает с -EAGAIN (-11):
# "No ID address. App must call settings_load()".
CONFIG_BT_SETTINGS=y
CONFIG_SETTINGS=y
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
# Имя устройства, которое увидит хост (телефон/ПК) при сканировании
CONFIG_BT_DEVICE_NAME="Badge"
# Внешний вид (Appearance): 0x03C1 = 961 = HID Generic Keyboard
CONFIG_BT_DEVICE_APPEARANCE=961
# Увеличиваем стек системной очереди работ (settings/BT требуют больше)
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
# ================================================================== #
# Энергосбережение BLE (connection parameters) #
# #
# CPU1 теперь засыпает (CONFIG_PM + TICKLESS, см. верх файла). #
# Дополнительно минимизируем активность радио CPU2 через #
# большие connection interval + slave latency: #
# радио просыпается лишь раз в ~4 секунды. #
# #
# Параметры передаются хосту через GAP; хост применяет их #
# ПОСЛЕ успешного спаривания. #
# ================================================================== #
CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS=y
# interval: единица 1.25 мс.
# MIN=320, MAX=320 → 400 мс между connection events.
CONFIG_BT_PERIPHERAL_PREF_MIN_INT=320
CONFIG_BT_PERIPHERAL_PREF_MAX_INT=320
# slave latency: пропуск 9 events → радио спит ~4 сек (9*400 мс)
CONFIG_BT_PERIPHERAL_PREF_LATENCY=9
# supervision timeout: единица 10 мс. 600 = 6 сек.
# Требование BLE: timeout > (1+latency)*interval*2 → 6 > (1+9)*0.4*2=8 ❌
# Поэтому при latency=9 interval=400мс нужен timeout > 8 сек → ставим 100 (10с).
CONFIG_BT_PERIPHERAL_PREF_TIMEOUT=1000Ранее я никогда с BLE не работал и опыт с Zephyr показался мне весьма интуитивно понятным. Вероятно, я просто не понимаю, что упускаю из-за отсутсвия опыта, но внешне всё выглядит работающим. Вопросы были только с повторным переподключением к ПК из-за того, что при перепрошивке МК содержимое flash-памяти с ключами безопасности было пустым, но это поправилось простой проверкой.
Требования к прошивке CPU2.
Прошивка второго ядра должна поддерживать HCI-интерфейс (Host Controller Interface). Но на плате изначально установлена Full Stack прошивка от ST, которая несовместима с Zephyr.
Для работы с Zephyr необходимо заменить её на HCI Layer прошивку:
• Скачать файл stm32wb5x_BLE_HCILayer_extended_fw.binиз репозитория ST.
• Установить эту прошивку с помощью STM32CubeProgrammer через раздел работы с FUS по адресу 0x080DC000.
• Запустить эту прошивку (требуется только один раз).
Энергопотребление
Изначально замеренное энергопотребление с включенным BLE у меня составило примерно от 6 до 12 мА. Что для аккумуляторного устройства значит не более одного дня работы. На текущей версии прошивки у меня получилось достичь среднего тока потребления ~900 мкА на полностью рабочем устройстве, что уже немного лучше, но всё равно на два порядка больше желаемого.
Текущий средний ток потребления во время работы BleКлючевые меры, принятые для достижения указанной величины тока:
• CPU1 засыпает (CONFIG_PM=y, CONFIG_PM_DEVICE=y, CONFIG_TICKLESS_KERNEL=y)
• Дополнительно минимизируем активность радио CPU2 через большие connection interval + slave latency.
• Через несколько секунд бездействия клавиатура уходит в сон и по нажатии на клавишу снова подключается к ПК.
Сборка устройства
Преимущества кокосовой скорлупы для DIY-электроники очевидны:
• Крепко.
• Экологично.
• Эргономично.
• Передаёт дух vibe-кодинга.
• Создаёт рабочие места для молодёжи.Процесс сборки верхней половины корпусаПодбор сырьяУбираем лишнееДоработка напильникомСоздаём технологические отверстия для посадочных мест кнопокСоздаём технологические отверстия для посадочных мест кнопокОтверстие для свитчаУстановкаКастомизация кейкаповПреимущества сухих строительных смесей для DIY-электроники очевидны:
• Крепко.
• Экологично.
• Эргономично.
• Передаёт дух vibe-кодинга.
• Создаёт рабочие места для молодёжи.Процесс сборки верхней половины корпусаРазводим с водой 2:3Выходной контрольК сожалению на этапе лепки всё было в грязи и было не до фотографий.
Исходники
https://github.com/RomanBashmakov/coconut_vibe
Конечно, можно программно задать какие-то полезные комбинации по нажатии вроде ввода пароля от ПК или команды "git log --graph --oneline --all" и таким образом сделать девайс более "полезным", но зачем. В любом случае все исходники есть по ссылке и они будут постепенно дополняться, так как есть намерение и дальше разбираться с этой ОС.Теги:• клавиатура
• zephyr rtos
• stm32
• bleХабы:• Электроника для начинающих
• Операционные системы
• Гаджеты
• Программирование микроконтроллеров
• Прототипирование
Получайте больше инсайтов о систематизации бизнеса
Подписывайтесь на Telegram-канал Business Operations — ежедневные материалы о бизнес-процессах, операционном управлении и повышении эффективности
💬 Подписаться на канал→ Оригинальная статья