Пишем прошивку Bluetooth Low Energy на Zephyr OS: полное руководство для разработчиков
Zephyr OS даёт открытый BLE-стек, прошедший сертификацию Bluetooth SIG. Разбираем, как написать прошивку для периферийного устройства, настроить сервисы и управлять им со смартфона.
Ваши беспроводные наушники только что подключились к телефону, смарт-часы синхронизировали пульс, а датчик температуры в соседней комнате отправил показания на шлюз. Всё это работает через Bluetooth Low Energy, и всё чаще прошивку под капотом таких устройств пишут на Zephyr OS.
Если вы разрабатываете встраиваемые системы или хотите войти в IoT, этот материал — практическое руководство по созданию BLE-периферии с нуля. Мы разберём, как устроен стек, как настроить окружение и как написать код, который управляет железом со смартфона.
Что такое Zephyr OS и зачем она для BLE
Zephyr OS — открытая операционная система реального времени под управлением Linux Foundation. Лицензия Apache 2.0, поддержка более 600 плат на ARM, RISC-V, x86 и других архитектурах. Главное для нас: внутри неё живёт полноценный BLE-стек, прошедший официальную сертификацию Bluetooth SIG. Рекомендуем также обзор «Первый RISC-V RVA23 чип входит в mainline Linux».
Ключевые выводы
Zephyr OS включает сертифицированный BLE-стек с открытым кодом — от приложения до радиоконтроллера.
GAP управляет обнаружением и соединениями, GATT — структурой данных (сервисы и характеристики).
Для старта понадобятся плата nRF52840 DK (~40 USD) и смартфон с приложением nRF Connect.
Прошивка собирается через west — единый инструмент для клонирования, сборки и прошивки.
Оптимизация энергопотребления: интервал advertising, peripheral latency, System OFF и отключение неиспользуемых периферий.
Это означает, что вы работаете не с хобби-реализацией, а со стеком, который прошёл conformance-тестирование. От прикладного кода до радиорегистров — всё открыто. Никаких бинарных блобов. Nordic Semiconductor, чьи чипы доминируют на рынке BLE, построила свой nRF Connect SDK поверх Zephyr. Когда инженеры Nordic пишут прошивку, они используют Zephyr.
Стек поддерживает Bluetooth 5.x (2M PHY, Coded PHY для дальней связи, Extended Advertising), Bluetooth Mesh, LE Audio с кодеком LC3, Direction Finding и все стандартные профили. Если вы делаете BLE-продукт в 2025–2026 годах — Zephyr входит в тройку лучших платформ.
Как работает BLE: два слоя, которые нужно знать
Прежде чем писать код, нужна ментальная модель. BLE — это не «классический» Bluetooth для аудио. Он создан для коротких, редких сеансов связи: датчик проснулся, отправил 20 байт, уснул. Такое устройство может работать от таблеточной батарейки годами.
Разработчик взаимодействует с двумя слоями:
- GAP (Generic Access Profile) — отвечает за обнаружение и соединения. Периферия широковещательно рассылает пакеты (advertising), а central (обычно телефон) их слушает и инициирует подключение.
- GATT (Generic Attribute Profile) — отвечает за обмен данными после соединения. Данные организованы в иерархии: устройство предоставляет сервисы, внутри которых находятся характеристики — единицы данных со свойствами Read, Write, Notify, Indicate.
Каждый сервис и характеристика идентифицируются UUID. Стандартные (от Bluetooth SIG) — 16-битные, пользовательские — 128-битные. Хорошо спроектированный набор сервисов — это API вашего устройства.
Ключевые выводы
Настройка окружения
Для работы понадобится Linux (Ubuntu 22.04+), macOS или Windows с WSL2. Идеальная плата для старта — Nordic nRF52840 DK. Она недорогая, широко доступна и имеет встроенный отладчик J-Link. А ещё посмотрите, как создать самодельные устройства на Raspberry Pi, ESP32 и Node-RED.
Установка зависимостей
На Ubuntu устанавливаем toolchain и утилиты:
Устанавливаем west — CLI для управления многорепозиторным workspace:
Инициализируем workspace и скачиваем модули (HAL-ы, криптобиблиотеки, Bluetooth controller):
Устанавливаем Python-зависимости и SDK с кросс-компиляторами:
Добавляем в ~/.bashrc:
Первое приложение: простой beacon
Начнём с минимального примера: устройство, которое только объявляет о себе по радио и не принимает соединений. Это база для iBeacon, Eddystone и отслеживание активов.
Создаём структуру проекта:
Файл CMakeLists.txt:
Конфигурация prj.conf:
Код src/main.c:
Что происходит: bt_enable(NULL) инициализирует стек синхронно. bt_le_adv_start с параметром BT_LE_ADV_NCONN запускает неконнективный advertising. Массив ad содержит флаги (general discoverable, no BR/EDR) и имя устройства.
Собираем и прошиваем:
Открываем nRF Connect на смартфоне, сканируем и видим «MyBeacon» в списке устройств. Прошивка работает.
Кастомный сервис: управляем LED со смартфона
Beacon полезен, но скучен. Настоящая магия начинается, когда телефон подключается к устройству и управляет им. Сделаем сервис, который позволяет включать LED на плате и читать состояние кнопки.
Конфигурация prj.conf:
Основной код. Здесь определяем пользовательские 128-битные UUID для сервиса и двух характеристик:
Ключевые моменты: BT_GATT_SERVICE_DEFINE собирает GATT базу данных на этапе компиляции. Характеристика LED доступна для чтения и записи, а кнопка — только для чтения. UUID сервиса вынесен в scan response, чтобы не перегружать 31-байтовый advertising-пакет.
После прошивки подключаемся через nRF Connect, находим кастомный сервис (UUID начинается с 00001234), записываем 0x01 в LED-характеристику — светодиод загорается. Только что вы управляли железом со смартфона по Bluetooth.
Notifications: отправляем данные без запроса
Чтение и запись — это pull-модель. Но датчики обычно работают по push: термометр сам шлёт температуру, пульсомер — BPM. В BLE для этого есть notifications.
Чтобы добавить notification в характеристику, нужно:
- Указать свойство
BT_GATT_CHRC_NOTIFYв характеристике. - Добавить CCCD (Client Characteristic Configuration Descriptor) через
BT_GATT_CCC— телефон пишет в него0x0001, чтобы включить уведомления. - Вызвать
bt_gatt_notifyпри изменении данных.
Типовой паттерн — периодическая отправка через delayable work item:
Work item выполняется в системном потоке, а не в контексте прерывания, поэтому вызовы Bluetooth API безопасны.
Полный sensor node в одном файле
Соберём всё вместе: датчик температуры (симулированный), который читается по запросу и пушится через notifications с настраиваемым интервалом. Добавим обработку соединений и LED-индикацию статуса.
Здесь важны две детали. Во-первых, температура хранится в формате fixed-point (сотые доли градуса в int16_t) — это позволяет избежать дорогих операций с плавающей точкой на микроконтроллерах без FPU. Во-вторых, проверка в функции записи: если телефон шлёт некорректный интервал, стек возвращает ошибку BT_ATT_ERR_VALUE_NOT_ALLOWED.
При разрыве соединения обработчики отменяют work item, гасят LED и перезапускают advertising — устройство снова доступно для обнаружения.
Безопасность: pairing и шифрование
В рабочей среде BLE без защиты — это устройство, которое любой прохожий может переключить или прочитать. Pairing создаёт зашифрованный канал и, опционально, аутентифицирует стороны.
Методы pairing в BLE:
- Just Works — шифрование без аутентификации. Защищает от пассивного прослушивания, но не от MITM.
- Passkey Entry — пользователь вводит 6-значный код. Аутентификация есть.
- Numeric Comparison — оба устройства показывают число, пользователь подтверждает совпадение.
- Out of Band (OOB) — обмен ключами через внешний канал, например NFC.
Включаем SMP (Security Manager Protocol) и persistent storage для bonding:
Данные сопряжения (ключи, обменянные при pairing) сохраняются во флеш-памяти и переживают перезагрузку. Без этого пользователю придётся проходить pairing после каждого включения устройства — ужасный пользовательский опыт.
Чтобы требовать шифрования для чтения характеристики, меняем permission:
BT_GATT_PERM_READ_ENCRYPT означает, что чтение возможно только по зашифрованному соединению. Если телефон пытается прочитать без pairing, стек автоматически инициирует процедуру сопряжения.
Роль central: сканируем и подключаемся
Все примеры выше — периферия (peripheral): устройство, которое рассылает advertising и ждёт подключения. Другая сторона — central: шлюз, хаб, сборщик данных. Для полной картины нужно понимать обе роли.
Конфигурация central:
Запуск сканирования и подключение к первому найденному устройству с RSSI выше -70 dBm:
После подключения выполняется обнаружение сервисов через bt_gatt_discover, затем — чтение характеристик и подписка на notifications через bt_gatt_subscribe.
Оптимизация: MTU, PHY и энергопотребление
По умолчанию BLE ATT MTU — 23 байта. Минус 3 байта заголовка ATT, получаем 20 байт полезной нагрузки на операцию. Для передачи прошивки или больших буферов этого мало.
Включаем MTU 247 байт и Data Length Extension:
Zephyr автоматически инициирует MTU exchange при соединении. С 247-байтным MTU, интервалом 7,5 мс и 2M PHY пропускная способность достигает ~800–1000 кбит/с на практике.
Выбор PHY — ещё один рычаг:
- 1M PHY — дефолт, стандартная дальность и скорость.
- 2M PHY (Bluetooth 5.0) — удваивает скорость, сокращает время работы радио и экономит энергию. Дальность чуть меньше.
- Coded PHY — увеличивает дальность в 2–4 раза за счёт помехоустойчивого кодирования, но скорость падает до 125 кбит/с.
Энергосбережение — ключ к автономным устройствам. Главные приёмы:
- Увеличить advertising interval: 1000 мс потребляет в 5 раз меньше, чем 200 мс.
- Использовать peripheral latency: пропускать connection events, когда нечего передавать.
- Включить System OFF: ток nRF52840 падает с ~3 мА до ~1,5 мкА.
- Отключить неиспользуемые периферии в devicetree overlay — UART, SPI, I2C жрут ток даже в простое.
Цель для BLE-датчика — средний ток в единицы микроампер. При таком потреблении таблеточная батарейка CR2032 (225 мА·ч) проработает годы.
Что ещё умеет стек: Mesh, DFU и LE Audio
Помимо классической point-to-point связи, Zephyr поддерживает три продвинутые технологии:
Bluetooth Mesh
Bluetooth Mesh — многие-ко-многим сеть поверх BLE. Узлы пересылают сообщения друг другу, расширяя радиус действия за пределы одного соединения. Используется в умных домах и офисах: десятки лампочек, выключателей и датчиков общаются без единого центрального хаба.
DFU over BLE
DFU over BLE — обновление прошивки по воздуху. Интеграция с MCUboot даёт два слота: активный и резервный. Новая прошивка загружается через BLE SMP сервис, устройство перезагружается, MCUboot проверяет подпись и, в случае неудачи, автоматически откатывается к предыдущей версии.
LE Audio
LE Audio — новый аудиостандарт на базе BLE. Кодек LC3 даёт более высокое качество, чем классический SBC, при вдвое меньшем битрейте. Режим BIS (broadcast) позволяет одному источнику транслировать звук на неограниченное число приёмников — технология, лежащая в основе Auracast.
Отладка: что делать, когда не работает
BLE сложно отлаживать, потому что радио невидимо. Начинайте с логов:
Это выдаст подробную трассировку каждой HCI-команды, advertising event и GATT-операции. Вывод идёт в UART — не оставляйте UART включённым в рабочей среде, он жрёт ток.
Интерактивный Zephyr shell позволяет вручную запускать bt advertise on, bt gatt discover и bt gatt read через последовательный порт. Это бесценно для быстрой проверки гипотез без перепрошивки.
Для анализа радиоэфира используйте nRF Sniffer для Bluetooth LE — прошивка для nRF52840 DK, которая вместе с Wireshark показывает каждый пакет в эфире: advertising PDU, connection events, pairing exchange. Это окончательный инструмент, когда подозреваете проблему на уровне протокола.
Часто задаваемые вопросы
Часто задаваемые вопросы
Нужен ли опыт в embedded, чтобы начать с Zephyr BLE?
Базовое знание C (указатели, структуры, обратные вызовы) обязательно. Опыт в Bluetooth не требуется — концепции GAP и GATT разбираются с нуля. Понадобятся плата nRF52840 DK (~40 USD) и смартфон с nRF Connect.
Почему Zephyr, а не Arduino или ESP-IDF?
Arduino упрощает старт, но скрывает детали BLE-стека и плохо масштабируется на сложные проекты. ESP-IDF хорош для ESP32, но привязывает к одному производителю. Zephyr даёт переносимость между 600+ платами, открытый код всего стека и сертификацию Bluetooth SIG — критично для коммерческих продуктов.
Какой реальный радиус действия BLE на Zephyr?
На 1M PHY в помещении — 10–30 метров. Coded PHY (Bluetooth 5.0) увеличивает дальность до 100+ метров за счёт помехоустойчивого кодирования, но снижает скорость до 125 кбит/с. Для Mesh-сетей радиус теоретически неограничен: каждый узел ретранслирует сообщение.
Можно ли использовать Zephyr в коммерческом продукте?
Да, лицензия Apache 2.0 разрешает коммерческое использование без открытия исходников вашего продукта. BLE-стек прошёл квалификацию Bluetooth SIG, что упрощает сертификацию конечного устройства.
Как уменьшить энергопотребление BLE-устройства?
Три главных рычага: увеличить интервал advertising или connection events, использовать peripheral latency для пропуска пустых слотов, и включать глубокий сон (System OFF) между активностями. Также отключайте в devicetree все периферии, которые не нужны в рабочей среде.
Выводы
Zephyr OS превращает разработку BLE-устройств из работы с чёрными ящиками в инженерную дисциплину. Полный открытый стек, сертификация Bluetooth SIG, поддержка 600+ плат и активное сообщество делают его одной из сильнейших платформ для IoT.
Мы прошли путь от простого beacon до полноценного sensor node с notifications, управлением соединениями и проверкой входных данных. Этих паттернов — advertising, GATT-обработчики, CCCD, подсчёт ссылок на соединение — достаточно, чтобы построить практически любое BLE-периферийное устройство.
Следующий шаг — взять реальное железо, реальный датчик и собрать устройство, которое решает вашу задачу. Термометр для теплицы, беспроводная кнопка для умного дома, трекер для велосипеда — всё это становится доступным после освоения базовых паттернов.
Главный способ понять BLE — не читать спецификацию, а заставить мигать LED со смартфона. Когда это получится, остальное пойдёт быстро.
Источники:
How to Build Bluetooth Applications with Zephyr OS: A Handbook for Devs — freeCodeCamp.
Zephyr Bluetooth Stack Documentation — официальная документация.
Bluetooth SIG Specifications — спецификации протоколов и профилей.