Например TDA7294

РадиоКот >Статьи >

Теги статьи: BluetoothДобавить тег

Разработка Bluetooth приложений на модулях фирмы Silicon Labs. Часть III.

Автор: Сергей Безруков (aka Ser60)
Опубликовано 20.06.2020
Создано при помощи КотоРед.

В этой части статьи будет рассказано как разработать Bluetooth приложение под управлением Micriµm OS и портировать проект на отдельный внешний Bluetooth модуль. Для первичного ознакомления с Micriµm OS рекомендую прочитать статью [1].

Разработка приложения на демо-плате

Первоначальную разработку будем производить на такой-же отладочной плате, что и в первой части статьи [2], именно Wireless Starter Kit Mainboard (BRD4001A) с установленной на ней платой BRD4306A с модулем BGM13P22. В качестве среды разработки используем Simplicity Studio и версию SDK 6.2.4.

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

Прежде всего отмечу, что использование RTOS для такого приложения не является самоцелью. В случаях, когда функционал Bluetooth желательно добавить в уже разработанное приложение для МК, могут возникнуть определённые сложности. Проблема состоит в синхронизации работы приложения и стека Bluetooth, особенно при условии работы обоих в жёстких временных рамках. Несколько способов интеграции стека Bluetooth в имеющееся приложениe путём объединения их главных циклов описаны в статье [3]. Возможными решениями являются вызов функционала приложения из главного цикла обработки событий Bluetooth или наоборот – проверка наличия необходимости обработки событий Bluetooth в главном цикле приложения. Для простых приложений типа нашего этого может быть достаточно. Однако, в более сложных случаях современная тенденция разработки ПО подразумевает проектирование приложений под управлением RTOS. Вот тогда и возникнет вопрос как перевести работу стека Bluetooth под контроль RTOS.

Поставленной проблеме посвящена статья [4], где работа стека Bluetooth разбита на 3 потока. Поток Link Layer (LL task) предназначен для реакции на события, генерируемых радио-трактом. Поток Bluetooth Host Task непосредственно взаимодействует со стеком Bluetooth, посылая в него надлежащие команды. Этот-же поток отвечает за генерацию событий Bluetooth, обработка которых возложена на поток Application Task. В код первых двух потоков можно не вникать и мы его изменять не будем.

Название последнего потока Application Task, на мой взгляд, не совсем удачное, т.к. может создастся впечатление, что этот поток занимается сторонними для Bluetooth вычислениями, связанными с остальной логикой приложения пользователя. На самом деле, основной функцией этого потока является реакция на события стека Bluetooth, которая, в свою очередь, находится в сильной зависимости от нужд остальной части приложения. В прилагаемом коде я назвал этот поток BluetoothAppTask. Взаимодействие показанных потоков управляется семафорами и флагами RTOS, подробнее об этом написано в [4]. Наряду с этими потоками для функционирования Bluetooth у приложения могут быть и свои собственные другие потоки.

С практической точки зрения, в списке примеров в Studio имеется демонстрационный проект SOC-Thermometer-RTOS, который я и взял за основу и адаптировал для нашего случая. Для модификации приложения достаточно лишь изменить код в файле main.c прилагаемого в архиве проекта Server_RTOS. Прежде всего следует настроить RTOS и определить какие служебные потоки разрешить. Это производится в дефайнах потоков в файле main.h, объединяемых в конце концов в один общий #define в строках 90-98, который, в свою очередь, служит для определения переменной OS_InitCfg в файле main.c. Эта переменная должна быть именно так названа для надлежащего восприятия настроек системой Micriµm OS.

Подчеркну, что для компиляции этого кода существенно использование версии SDK 6.x (той-же, что и в предыдущих статьях цикла), посколько в последней на настоящий момент версии 7 произведены некоторые изменения и адаптирование моих статей на эту версию SDK заслуживает отдельного рассмотрения.

Для начала работы RTOS следует создать как минимум один поток App_Task. Это производится в строках 138 – 151 файла main.c в полном соответствии с [1].

Этот поток является главным для нашего приложения, рассмотрим его подробнее. Работа потока начинается с конфигурации тиков OS (строка 164) и callback функции для нужд динамического тактирования и погружения МК в глубокий сон в строке 165, подробнее про это см. в [1]. Далее производится создание специфичных для Bluetooth потоков LL_Task и Bluetooth_Host_Task в соответствии с вышеизложенным. Код этих потоков вынесен в отдельный файл rtos_bluetooth.c, находящийся в папке protocol проекта, и мы его трогать не будем.

После этого потоком производится инициализация hardware на плате и создание третьего, специфичного для Bluetooth, потока BluetoothAppTask, с помощью которого будет производиться управление нашим главным потоком приложения посредством флагов OS (см. [1]), созданных в строке 182.

По завершении описанной инициализации главный поток входит в основной цикл. Работа цилка блокируется OS флагами в строке 201, которые устанавливаются потоком BluetoothAppTask в соответствии с управлением работой сервера со смартфона (об этом ниже). Всего имеется 3 флага, соответствующих битам 0 – 2 флаговой переменной flags. Если не один из флагов не выставлен, планировщик ОС производит переключение на другой поток или Idle_Task, который в свою очередь, переводит МК в глубокий сон посредством своей callback функции. Если бит 1 или 2 флага выставлен, производится измерение параметров среды в строках 203 – 204, сохранение соответствующего параметра в базе данных сервера, и отсылка его пользователю в ответ на запрос клиента (строки 206 – 211 и 212 – 217). Соответствующие биты флага обнуляются в строках 208 и 214, реализуя единичное измерение параметра при каждом запросе клиента. Если-же выставлен бит 0 флага, то производится сохранение обоих параметров в базе данных (строки 220 – 221) и отсылка нотификации клиенту в строке 222. При этом бит флага не стирается и производится задержка на 1 сек (строка 224) для производства периодических измерений. Управление битом 0 флага производится путём модификации CCCD дескриптора характеристики air_temp_humi. При периодическом измерении параметров среды также возможен запрос на производство единичных измерений температуры и влажности. Обработка запросов пользователя индицируется светодиодом LED1, включаемым и выключаемым в строках 202 и 226.

Рассмотрим теперь работу потока BluetoothAppTask в файле main.c. Этот поток является связующим звеном между главным потоком (потоками) приложения, рассмотренном выше, и потоками Bluetooth стека в файле rtos_bluetooth.c. В коде этого потока производится обработка событий стека, описанных в первой части статьи [2]. Большинство событий такие-же как и в приложении сервера в [2], поэтому на них я здесь останавливаться не буду, а опишу лишь 2 новых события. Первым из них является событие gatt_server_user_write_request, генерируемое при записи клентом значений в базу данных сервера. В нашем случае это происходит только при модификации клиентом дескриптора CCCD характеристики air_temp_humi при разрешении и запрещении отсылки нотификаций. Этот дескриптор добавляется графическим конфигуратором профиля Bluetooth автоматически для каждой характеристики, у которой разрешена её нотификация. При автоматическом добавлении дескриптора CCCD стек не информирует приложение об его изменении клиентом и, соответственно, не генерирует событие gatt_server_user_write_request. В нашем случае информирование приложения необходимо для выставления бита 0 флага, управляющего главным потоком пользователя. Для достижения этого я добавил явно CCCD дескриптор в профиль проекта и изменил его Value type с дефолтного значения на user, как показано ниже:

Благодаря описанным изменениям профиля, необходимое событие при изменении CCCD пользователем теперь генерируется стеком, и в его обработчике мы читаем установленное значение из базы данных Bluetooth (строка 277) и устанавливаем (или сбрасываем) бит 0 флаговой переменной (строки 279 – 282). Это приводит к продолжению планировщиком вычисления главного потока нашего приложения и производству периодических измерений. Запись значения CCCD в базу данных сервера обеспечивается стеком автоматически. Напомню, что значение CCCD имеет длину 2 байта, из которых один используется для разрешения/запрещения нотификаций, а другой – для индикаций. Для разрешения передачи нотификаций параметров среды клиенту следует записать в CCCD значение 01:00 (little-endian), где первый байт отвечает за нотификации.

Аналогично, для информирования приложения о запросе клиентом чтения характеристики температуры или влажности, следует разрешить стеку генерирование события gatt_server_user_read_request. Это также достигается изменением значения Value type этих характеристик в профиле с дефолтного значения на user. В обработчике этого события мы устанавливаем биты 1 или 2 флаговой переменной, управляющей while-циклом главного потока (строки 290 – 295. Так как тип CCCD также установлен как user, необходимо добавить строку 288 на случай чтения клиентом этого дескриптора (строки 287 – 289), иначе приложению клиента на смартфоне это, мягко говоря, не понравится и при неполучении ответа в течении 30 секунд оно может разорвать соединение с сервером. Отсылка ответов на запрос клиента чтения остальных характеристик профиля производится в главном потоке в строках 210 и 216.

Итак, чего-же мы добились? Прежде всего, мы переложили всю головную боль временной синхронизации нашего приложения с работой стека Bluetooth на плечи Micriµm OS, и одно это уже совсем даже немало. Сравним теперь токопотребление нашего сервера с RTOS с аналогичным приложением без RTOS, описанном в первой части статьи [2]. Как показано в осциллограммах из [2], измеренное среднее токопотребление в режиме передачи оповещений было 23.33 мкА. После установки соединения с клиентом оно было около 81.19 мкА за период коммуникации (100мс). Ниже представлен график измеренного токопотребления сервера с RTOS из этой статьи в режиме передачи оповещений.

Главные пики с периодом 1 сек соответствуют моментам передачи оповещений, а второстепенные, видимо, как и ранее связаны с работой DC/DC конвертера на борту модуля. После установки соединения с клиентом с периодом сеансов связи 100мс токопотребление выглядит следующим образом:

Оба графика приведены с выключенными светодиодами LED0 и LED1 на плате. Из них вытекает, что среднее токопотребление в обоих режимах возросло незначительно - (26.15 мкА вместо 23.33) и (87.82 мкА вместо 81.19), соответственно.

При отладке RTOS приложений полезно знать об использовании областей стека потоками, чтобы предотвратить их переполнение. Это можно сделать с помошью инструмента µC/Probe, как рассказано в [2]. Для этого следует разрешить служебные потоки таймера и сбора статистики RTOS, что достигается установкой значения переменной RTOS_DEBUG_MODE в 1. При этом блокированные этой переменной области дефайнов в файле main.h войдут в общий дефайн настроки RTOS. Установка значения этой переменной производится в настройках проекта как показано ниже.

Проект затем следует перекомпилировать и загрузить в МК. Данные, снятые инструментом µC/Probe для нашего проекта в режиме соединения с клиентом, показаны ниже, откуда следует, что области стеков процессов установлены с достаточным запасом и могут быть при необходимости уменьшены.

В заключении несколько слов о модификациях в драйвере сенсора Si7021 в файле si7021.c. Он также основан на драйвере интерфейса I2C библиотеки Emlib. Однако, с целью уменьшения токопотребления введена возможность погружения МК в сон на время I2C транзакций. Это достигается установкой дефайна USE_I2C_INT в 1, что приводит к погружению МК в сон в строке 56. Дефолтный режим сна приложения – это EM2 (Deep Sleep), однако на время транзакций нужен режим сна EM1, в котором работа генератора, тактирующего модуль I2C в МК, не прекращается. Для этого служит вызов API функций в строках 52 и 61, определяющих область кода, где запрещён режим глубокого сна EM2. При этом в код также добавляется обработчик прерываний I2C (строки 64 – 69), который, как мы уже знаем из [1], оформлен как NKA (Non-Kernel Aware).

В кодe функции SI7021_getTempHumi() имеется цикл ожидания подтверждения сенсором своего адреса, что является сигналом окончания измерения. Хотя измерение занимает всего около 15мс, лучшим решением было-бы применить сенсор с выводом INT (например, HDC2010) для этой цели. Тогда можно было-бы дольше находиться в режиме глубокого сна и разблокировать соответствующий процесс семафором из KA (Kernel Aware) обработчика прерываний вывода МК, соединённого с указанным выводом сенсора.

Портирование проекта на модуль

Аппаратная часть нашего сервера собрана по следующей схеме на безпаячной монтажке.

5-штырьковый коннектор в схеме используется для загрузки прошивки в модуль через интерфейс SWD. Сигналы SWCLK и SWDIO интерфейса дефолтно доступны через выводы PF0 и PF1 модуля, соответственно.

Прежде всего, настоятельно рекомендую загрузить в модуль новый бутлоадер, соответствующий текущей версии SDK. Это, в частности, необходимо для функционирования апдейтов ПО по воздуху (OTA). Для загрузки бутлоадера следует сначала создать специальный проект в Simplicity Studio. Если используется демо-плата, такой проект можно выбрать в списке Software Examples, который сформируется автоматически при подключении её к компьютеру. При отсутствии платы можно использовать поле My Products в Simplicity IDE, добавив в него BGM13P22F512GA в качестве Part. При этом также сформируется список Gecko Bootloader Examples в секции Software Example. В этом списке имеется несколько проектов бутлоадера для разных ситуаций. Если в устройстве не предполагается задействовать внешнюю Flash память для OTA и устройство будет работать только с одним протоколом (например, Bluetooth), для указанного модуля подойдёт проект, соответствующий объёму Flash памяти в модуле, показанный ниже.

После создания проекта открываем .isc файл в его дереве и, не меняя дефолтных настроек, кликаем на кнопку Generate. Это приведёт к автогенерации кода бутлоадера, по окончании которой проект следует скомпилировать.

Вне зависимости от того, решили-ли Вы обновить бутлоадер или нет, следующим шагом является загрузка кода в модуль. Для этого можно использовать как отдельный J-Link программатор, так и встроенный в демо-плату. В последнем случае удобно воспользоваться платой адаптера SLSDA001A (MINI Simplicity Adapter) и 10-жильным кабелем, входящим в его комплект. Вставим его в основную плату, как показано ниже.

На другом конце кабеля также имеется 10-штырьковый разъём с шагом выводов 1.27 мм. Я использую самодельный адаптер для соединения другого конца кабеля программатора с платой модуля.

При использовании программатора на демо-плате его следует перевести в режим OUT для программирования внешних устройств. При этом светодиод справа от платы адаптера загорается.

Определившись с выбором программатора, следует настроить его на работу с Bluetooth модулем в Studio. Для этого переходим в режим Launcher, кликаем правой кнопкой мыши на наш программатор в окне Debug Adapters, и выбираем опцию Device Configuration. При использовании отладочных плат всего этого делать не нужно, потому что на каждой из них установлен Flash чип с идентификатором модуля. Поскольку в нашем устройстве ничего подобного нет, следует в поле Target part ввести номенклатуру модуля, которая затем появится под ID адаптера, как показано выше. Отмечу, что не нужно знать какой чип семейства EFR32 установлен в модуле, поскольку Studio трактует имя модуля как отдельную деталь.

При успешной компиляции бутлоадера в его дереве проекта появится папка Binaries. Откроем её и кликнем правой кнопкой мыши на .hex файл в ней. В открывшемся окне выберем опцию Flash to Device с дефолтными настройками.

Наконец, бутлоадер загружен и среда настроена на программирование модуля. Теперь самое время произвести минимальные изменения в проекте, согласно принципиальной схеме. Так, в файле main.c закомментируем строку 136 с высовом функции initApp(), а в конце файла init_board.c закомментируем все строки, начинающиеся с MX25. Они не нужны, т.к. в нашем устройстве нет отдельной flash памяти для организации ОТА. Осталось переназначить выводы модуля под светодиоды в файле hal-config-board.h и установить HAL_PTI_ENABLE в 0 в файле hal-config-app-common.h. Все указанные изменения сделаны в прилагаемом архиве проекта Server_RTOS_MOD.

Следует отметить, что демо-плату можно использовать также для измерения потребляемого тока нашим устройством инструментом Energy Profiler через MINI Simplicity адаптер в режиме OUT. Как показывает осциллограмма ниже, среднее потребление нашего сервера полностью соответствует ожидаемому, и находится в районе 25 мкА.

Литература

1. О разработке приложений для ARM микроконтроллеров фирмы Silicon Labs под управлением Micriµm OS.
2. Разработка Bluetooth приложений на модулях фирмы Silicon Labs. Часть I.
3. KBA_BT_0909: Scheduling application tasks while running BLE stack.
4. AN1114: Integrating Silicon Labs Bluetooth ® Applications with the Micrium RTOS.
5. Kernel 201: Configuring Micrium OS.


Файлы:
Архив ZIP


Все вопросы в Форум.




Как вам эта статья?

Заработало ли это устройство у вас?

6 2 2

Эти статьи вам тоже могут пригодиться: