© 2023 DiyTronic

Исследую Mynewt OS

Давно хотел попробовать поиграться с какой-нибудь микроконтроллерной операционной системой. Наконец в контексте моего увлечения BLE модулями, где довольно много ресурсов, решил таки попробовать. В закладках уже давно болталась ссылка на Mynewt ну и наконец её время пришло. Итак пробую запустить на модуле nrf51822 Mynewt.

ОС на микроконтроллере — что за бред?

Неоднократно слышал такое мнение в интернет, равно как и мнение, что писать надо только на ASM-е, и что С++ использовать нельзя и ещё много чего. В определённой степени оно верно, в особенности для маломощных контроллеров, для которых на счету каждый байт. В общем-то да — там это будет явный перебор. Но чорт побери — на дворе уже 2018 год и контроллеры уже мощнее, чем мой первый компьютер. Лишние пара килобайт за удобство разработки и обслуживания давно уже не проблема, а накладные расходы практически незаметны. Поэтому вполне себе вариант.

Почему именно Mynewt?

Самое главное — наличие BLE стэка и поддержка чипа nrf51822. Хотелось попробовать альтернативный и свободный BLE стэк.

Установка

По счастью для ArchLinux есть готовый пакет, поэтому просто ставлю. Но для остальных случаев вроде как там много вариантов установки, включая Windows и MacOS.

1
$ yaourt -S mynewt-newt --noconfirm

На самый край есть Docker образ

Терминология

Меня лично сходу немного сбила используемая терминология, поэтому остановлюсь на этом поподробнее.

Проект

Итак у нас есть проект (project)  — в общем проект это не набор настроек приложения как я ожидал, а некая папка где содержится набор приложений, настроек, зависимостей, библиотек (или в терминах Mynewt — пакетов (packages) ).

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

Настройки проекта указываются в YAML файле project.yml.

Пакет

Пакет это основная фундаментальная единица проекта.

Пакетами (packages) являются:

  • приложения (applications)
  • библиотеки (libraries)
  • цели (targets)
  • возможно что-то ещё

Каждый пакет это фактически папка с конфигурационным файлом pkg.yml, в котором указываются все настройки (описание, автор, тип и т. п.) пакета, а так-же его зависимости — другие пакеты.

Тут тоже всё логично — дерево пакетов. По необходимости оно подтягивает все зависимости, что весьма удобно.

BSP

Board Support Package — это пакет с набором настроек для конкретной железной платформы. Он содержит описание используемого микроконтроллера, соответствия пинов периферии и возможно что-то ещё. В общем случае при наличии правильного BSP нам не надо возиться с пинами, вместо этого мы будем пользоваться более высокоуровневыми объектами типа UART, SPI и т. п., а на какие пины это будет выведено за это уже отвечает BSP.

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

Mynewt уже «из коробки» имеет ряд сконфигурированных BSP для наиболее популярных плат и контроллеров.

Цели

Цель (target) это набор настроек для генерации кода под конкретную платформу. Каждая цель состоит из:

  • приложения

  • BSP

  • типа сборки (build profile)  — фактически это флаг debug или optimized

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

Операционная система

Теперь немного о самой OS. Собственно как и любая операционная система Mynewt имеет ядро и приложения. Загружаться они могут 3-мя различными способами.

Загрузка

Столкнулся с тем, что в примерах загрузка кода в устройство выполняется по разному — некоторые примеры просто заливают в устройство, а в некоторых предварительно заливается некоторый boot образ. Ну в команде прошивки указываются какие-то магические цифры 1 и 0, назначение которых непонятно.

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

Оригинал описания процесса загрузки можно посмотреть тут

Single

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

Unified

В этом случае у нас есть бутлодер, который размещается по нулевому адресу. Соответственно управление при старте передаётся ему, а он в свою очередь организует загрузку нужного образа системы и передаёт ему управление. Образы системы хранятся в так называемых слотах. Есть 2 слота для загрузки образов — 0 и 1.

Очевидным достоинством способа является возможность обновлять код приложения «на лету», не используя специальных устройств для прошивки, например заливкой образа через UART.

Split

Этот способ отличается от предыдущих тем, что код разделён между 2-мя образами — загрузчиком и приложением, которые заливаютс соответственно в слоты 0 и 1.

Загрузчик содержит непосредственно ядро Mynewt, сетевой стэк, возможно что-то ещё, необходимое для загрузки образа. По сути он выполняет те-же функции, что и бутлодер из Unified варианта загрузки, но дополнительно содержит сервер обновления, которые позволяет выполнить обновление кода по сети (включая BLE).

Приложение содержит части Mynewt которые не нужны на этапе загрузки и код непосредственно самого приложения.

Этот способ чем-то похож на SoftDevice, используемый в nRF SDK.

Создаём проект

Изначально я хотел потестировать BLE стэк, но по неопытности и по не знанию базовых концепций Mynewt немного начудил с конфигурацией и не смог прошить устройство, поэтому откатился на более простой вариант — мигание светодиодом. Поэтому в примерах в названии проекта будет присутствовать слово ble.

1
2
3
4
$ newt new test_project
Downloading project skeleton from apache/mynewt-blinky...
Installing skeleton in test_project...
Project test_project successfully created.

Теперь надо скачать зависимости проекта. Для этого переходим в папку только что созданного проекта и запускаем нужную команду newt install

1
2
3
$ cd test_project
$ newt install
apache-mynewt-core successfully installed version 1.3.0-none

Выполняется довольно долго — видимо выкачивает что-то, но никаких при этом визуальных эффектов. Нехорошо.

Теперь нужно создать приложение, но как оказалось новый проект автоматически создаёт приложение для мигания светодиодом (apps/blinky), поэтому шаг создания приложения пропущу.

Теперь нам надо создать цели (target) для бутлодера и для приложения. Для nrf51822 есть 2 BSP — для моего AC чипа c 16Кбайт памяти нашёл отдельный специальный BSP, что несомненно порадовало.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ newt target create nrf51_boot                                                                        2.4.2  8.1.3
Target targets/nrf51_boot successfully created

$ newt target set nrf51_boot app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/nrf51dk-16kbram build_profile=optimized
Target targets/nrf51_boot successfully set target.app to @apache-mynewt-core/apps/boot
Target targets/nrf51_boot successfully set target.bsp to @apache-mynewt-core/hw/bsp/nrf51dk-16kbram
Target targets/nrf51_boot successfully set target.build_profile to optimized

$ newt target create blinky  2.4.2  8.1.3
Target targets/blinky successfully created

$ newt target set blinky app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/nrf51dk-16kbram build_profile=debug
Target targets/blinky successfully set target.app to apps/blinky
Target targets/blinky successfully set target.bsp to @apache-mynewt-core/hw/bsp/nrf51dk-16kbram
Target targets/blinky successfully set target.build_profile to debug

И запускаем сборку

1
2
3
4
5
6
7
8
$ newt build blinky
...
Target successfully built: targets/blinky

$ newt build nrf51_boot
Building target targets/nrf51_boot
...
Target successfully built: targets/nrf51_boot

Заливаем бутлодер в устройство, предварительно подключив программатор (SEGGER JLink) к плате.

1
2
$ newt load nrf51_boot
Loading bootloader

Пробую запустить приложение — не забываем указать слот 1 … хотя попробовал залить в нулевой слот и оно тоже заработало.

1
$ newt run blinky 1

В результате видим окно дебаггера — вводим команду c и плата начинает активно мигать светодиодом.

Итоги

В итоге всё получилось — код собирается, заливается в устройство и работает. Следующим шагом будет безусловно запуск BLE стэка, что лично для меня представляет наибольший интерес. Ну и можно будет уже поиграться с кодом т. к. в этом проекте в код можно даже не заглядывать (хотя я конечно уже посмотрел).

Источник

Комментарии