© 2023 DiyTronic

iBeacon на Mynewt OS

Воодушевившись первыми успехами с миганием светодиодами на Mynewt решил двинуть дальше и попробовать запустить BLE примеры с сайта. Простейший из них это конечно BLE iBeacon — его я и решил попробовать словив при этом несколько проблем.

Итак что меня есть: плата с nrf51822, программатор SEGGER Jlink, переходник UART -> USB.

Создаём проект — ну в общем тут никакой магии:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ mkdir ibeacon-test
$ cd ibeacon-test
$ newt new ibeakon  2.4.2  8.1.3
Downloading project skeleton from apache/mynewt-blinky...
Installing skeleton in ibeakon...
Project ibeakon successfully created.
$ cd ibeacon
$ newt install
apache-mynewt-core successfully installed version 1.3.0-none
$ newt pkg new apps/ibeacon-app -t app  2.4.2  8.1.3
Download package template for package type app.
Package successfuly installed into <skip>/mynewt-test/ibeacon-test/ibeacon/apps/ibeacon-app.
$ newt target create ibeacon
newt target create ble_tgt  2.4.2  8.1.3
Target targets/ibeacon successfully created
$ newt target set ibeacon \
app=apps/ibeacon-app \
bsp=@apache-mynewt-core/hw/bsp/nrf51dk-16kbram \
build_profile=debug
Target targets/ibeacon successfully set target.app to apps/ibeacon-app
Target targets/ibeacon successfully set target.bsp to @apache-mynewt-core/hw/bsp/nrf51dk-16kbram
Target targets/ibeacon successfully set target.build_profile to debug

Для поддержки BLE добавляем в pkg.yml нашего приложения пакеты, необходимые для работы BLE стэка

pkg.yml
1
2
3
4
5
6
7
8
9
10
pkg.deps:
- "@apache-mynewt-core/kernel/os"
- "@apache-mynewt-core/sys/console/full"
- "@apache-mynewt-core/sys/log/full"
- "@apache-mynewt-core/sys/stats/full"
# добавлены строки ниже
- "@apache-mynewt-core/net/nimble/controller"
- "@apache-mynewt-core/net/nimble/host"
- "@apache-mynewt-core/net/nimble/host/store/config"
- "@apache-mynewt-core/net/nimble/transport/ram"

Ну и пробуем собрать нашу цель:

1
$ newt build ibeacon

Грабля первая

И вот тут-то нас ждёт засада

1
2
3
4
5
6
7
$ newt build ibeacon
Building target targets/ibeacon
...
Linking /home/roman/.Projects/mynewt-test/ibeacon-test/ibeacon/bin/targets/ibeacon/app/apps/ibeacon-app/ibeacon-app.elf
Error: /usr/lib/gcc/arm-none-eabi/7.3.0/../../../../arm-none-eabi/bin/ld: /home/roman/.Projects/mynewt-test/ibeacon-test/ibeacon/bin/targets/ibeacon/app/apps/ibeacon-app/ibeacon-app.elf section `.text' will not fit in region `FLASH'
/usr/lib/gcc/arm-none-eabi/7.3.0/../../../../arm-none-eabi/bin/ld: region `FLASH' overflowed by 11224 bytes
collect2: error: ld returned 1 exit status

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

В общем я нашёл 2 варианта решения этой проблемы.

Решение первое — отключить логгирование.

Для этого можно настроить уровень логгирования, что выполняется указанием в файле syscfg.yml приложения значения переменной LOG_LEVEL равным 255. Думаю 255 уровней позволят подобрать оптимальный вариант, но мне уже просто хотелось поскорей запуститься, поэтому поставил 255, что означает выключение логов.

syscfg.yml
1
2
3
4
...
# Settings this app overrides.
syscfg.vals:
LOG_LEVEL: 255

Решение второе — выключение некоторых пакетов

По умолчанию при создании приложения у нас в pkg.yml добавляются следующие пакеты:

pkg.yml
1
2
3
4
pkg.deps:
- "@apache-mynewt-core/sys/console/full"
- "@apache-mynewt-core/sys/log/full"
- "@apache-mynewt-core/sys/stats/full"

Чтобы уменьшить объем кода нужно заменить их на

pkg.yml
1
2
3
4
pkg.deps:
- "@apache-mynewt-core/sys/console/minimal"
- "@apache-mynewt-core/sys/log/stub"
- "@apache-mynewt-core/sys/stats/stub"

После этих изменений сборка выполняется успешно.

1
2
3
4
$ newt build ibeacon
Building target targets/ibeacon
...
Target successfully built: targets/ibeacon

Грабля номер 2 — не работает UART на nrf51822

Теперь, после того как сборка в общем-то заработала стоит добавить в проект какой-нибудь осмысленный код. Для этого внимательно читаем статью BLE iBeacon — там всё подробно разжёвано. Берём готовый код в конце статьи и записываем его в наш главный файл src/main.c

main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include "sysinit/sysinit.h"
#include "os/os.h"
#include "console/console.h"
#include "host/ble_hs.h"

static void
ble_app_set_addr(void)
{
ble_addr_t addr;
int rc;

rc = ble_hs_id_gen_rnd(1, &addr);
assert(rc == 0);

rc = ble_hs_id_set_rnd(addr.val);
assert(rc == 0);
}

static void
ble_app_advertise(void)
{
struct ble_gap_adv_params adv_params;
uint8_t uuid128[16];
int rc;

/* Arbitrarily set the UUID to a string of 0x11 bytes. */
memset(uuid128, 0x11, sizeof uuid128);

/* Major version=2; minor version=10. */
rc = ble_ibeacon_set_adv_data(uuid128, 2, 10);
assert(rc == 0);

/* Begin advertising. */
adv_params = (struct ble_gap_adv_params){ 0 };
rc = ble_gap_adv_start(BLE_OWN_ADDR_RANDOM, NULL, BLE_HS_FOREVER,
&adv_params, NULL, NULL);
assert(rc == 0);
}

static void
ble_app_on_sync(void)
{
/* Generate a non-resolvable private address. */
ble_app_set_addr();

/* Advertise indefinitely. */
ble_app_advertise();
}

int
main(int argc, char **argv)
{
sysinit();

ble_hs_cfg.sync_cb = ble_app_on_sync;

/* As the last thing, process events from default event queue. */
while (1) {
os_eventq_run(os_eventq_dflt_get());
}
}

Изначально я воспользовался первым методом для уменьшения размера кода. В результате после запуска кода на устройстве обнаружил периодическое мигание светодиода на выходе TX UART-а. Попытка просканировать эфир на наличие каких-либо iBeacon-ов ни к чему не привела. В общем ничего не заработало — только TX издевательски подмигивал мне, намекая, что стоит к нему подключиться и посмотреть что-же там такого.

В итоге подключил к UART-у переходник UART-> USB и подцепившись терминалом к порту увидел, что за таинственные знаки подавал мне мигающий светодиод.

Видно, что периодически возникает assert и ошибка в обработке прерывания 2. Прерывание 2 это UART. Т.е. видимо что-то не так с UART-ом.

Собственно именно это сподвигло меня заняться отладкой и обнаружить проблему в коде UART-а. То, что при этом уменьшился размер кода это лишь побочный эффект. Т.е. решением проблемы будет замена пакетов log и stat с full на stub.

Теперь после запуска приложения на устройстве можно увидеть beacon с мобильника

Так-же устройство видно из родной нордиковской программы nrfConnect.

К сожалению нордиковское приложение nRF Beacon не смогло ничего обнаружить.

Итоги

В итоге получилось запустить рабочий код маяка на Mynewt, отловив при этом потенциальные проблемы. Далее в планах проверить работу датчиков совместно с модулем и отловить результаты на мобильнике.

Комментарии