© 2026 DiyTronic

iBeacon на Mynewt OS

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

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

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

$ 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.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"

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

newt build ibeacon

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

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

$ 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, что означает выключение логов.

...

# Settings this app overrides.

syscfg.vals:
  LOG_LEVEL: 255

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

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

pkg.deps:
    - "@apache-mynewt-core/sys/console/full"
    - "@apache-mynewt-core/sys/log/full"
    - "@apache-mynewt-core/sys/stats/full"

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

pkg.deps:
    - "@apache-mynewt-core/sys/console/minimal"
    - "@apache-mynewt-core/sys/log/stub"
    - "@apache-mynewt-core/sys/stats/stub"

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

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

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

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

# 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, отловив при этом потенциальные проблемы. Далее в планах проверить работу датчиков совместно с модулем и отловить результаты на мобильнике.

Комментарии