© 2023 DiyTronic

Пробую NRF51822

Есть у меня китайский BLE модуль на nRF51822. Давно собирался с ним поэкспериментировать и вот руки наконец дошли. К сожалению информации о работе с этими модулями не так много, поэтому решил поделиться своим опытом.

Железо

Модуль nRF51822

Собственно модуль представляет собой распаянный на плату чип nRF51822 с всей необходимой обвязкой и пинами выведенными на пару гребёнок. Ну и как любой микроконтроллер он может быть прошит неким кодом, который может управлять портами ввода/вывода. Ну и главным бонусом идёт встроенный Bluetooth LE модуль.

Хочу особо обратить внимание на тот факт, что существует несколько вариаций чипа с разными вариантам памяти. Это будет важно в дальнейшем. Поэтому советую посмотреть прямо на чипе маркировку.

Естественным желанием было воткнуть модуль в брэдборд и потестировать. Но не ту-то было. Модуль имеет 4 ряда выводов, что как бы уже обламывает всю идею, но к тому-же оказалось выводы имеют нестандартный шаг 2 мм, так что даже на макетку его не воткнуть. В поисках какого-нибудь переходника наткнулся на готовую отладочную плату для таки модулей BLE400.

Плата BLE400

Вариант с платой выглядел поинтереснее, поэтому данная плата немедленно была закуплена у китайских коммерсантов. Собственно эта плата представляет собой разъём для модуля, пины, выведенные на штырьки, некоторые пины выведены на светодиоды (через перемычки), 2 пина подключены к кнопкам (опять же через перемычки). Так-же есть несколько стандартных разъёмов опять же подключенных к пинам модуля и USB -> COM преобразователь, который позволяет во первых запитать модуль через USB, а во вторых позволяет использовать UART прямо через USB. В общем простая, но полезная штука.

Итак плата BLE400 в наличии, модуль воткнут в разъём.

Втыкаем плату и видим в логах, что она определилась как /dev/ttyUSB0

1
2
3
4
5
6
7
8
9
$ dmesg
...
[35577.734982] usbcore: registered new interface driver usbserial
[35577.734992] usbcore: registered new interface driver usbserial_generic
[35577.734999] usbserial: USB Serial support registered for generic
[35577.738586] usbcore: registered new interface driver cp210x
[35577.738596] usbserial: USB Serial support registered for cp210x
[35577.738619] cp210x 3-1:1.0: cp210x converter detected
[35577.740213] usb 3-1: cp210x converter now attached to ttyUSB0

Надо для неё проделать старый хитрый трюк с udev, чтобы получить стабильное неизменное имя. Ну что — поехали. Находим соответствующee USB устройство.

1
2
3
4
$ lsusb
...
Bus 003 Device 071: ID 10c4:ea60 Cygnal Integrated Products, Inc. CP2102/CP2109 UART Bridge Controller [CP210x family]
...

Смотрим udev аттрибуты

1
2
3
4
5
6
$ udevadm info --attribute-walk -n /dev/ttyUSB0
...
ATTRS{idProduct}=="ea60"
ATTRS{idVendor}=="10c4"
...
ATTRS{serial}=="0001"

И прописываем его в правило udev

/etc/udev/rules.d/99-ble400.rules
1
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{serial}=="0001" GROUP="users", MODE="0666", SYMLINK+="ble400"

Теперь перезагружаем правила

1
$ sudo udevadm control --reload-rules

И отсоединяем/подсоединяем кабель устройства и наблюдаем в папке /dev/ устройство ble400 которое является фактически ссылкой на реальный файл устройства. Ну, а нам того и надо.

Подключение и прошивка

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

USB serial

Итак втыкаем плату с модулем в USB разъём и пробуем подключиться к UART-у. В ответ на посылку ему команду «y» от должен ответить «Start …».

Не прокатило — не отзывается на команды вообще никак. Только загорается светодиод SPD. При отправке команды «y» моргает Rx. Возможно просто в чипе хрен знает какая прошивка или он вообще девственно чист. Т.е. вроде как соединения устанавливается, но ни на какие команды не реагирует. Возможно (и скорей всего) нужно просто подобрать правильную скорость соединения.

Ну как говорится — «не очень-то и хотелось». Будем пробовать дальше. Вопрос с работоспособностью по прежнему остаётся открытым.

Bluetooth

Попытка номер два. Предположил, что при подключении у нас должно быть видно какое-то Bluetooth устройство. Втыкаем опять плату с модулем в USB, чтоб подать питание. Для тестирования использовал смартфон Xiaomi mi4c, который имеет поддержку BLE. Для тестирования использовал софт от нордиков — nRF Toolbox и nRF Connect. Но всё тщетно — никаких признаков неизвестных BLE устройств обнаружено не было. Это как-то уже начинает напрягать.

Bus Pirate

Вот тут http://floe.butterbrot.org/matrix/hacking/nrf/ какие-то ребята экспериментируют с подключением через Bus Pirate. Попробовал данный вариант — к плате могу подконнектиться, прочитать память, записать туда что-то. Но возможности крайне скудные. Там какой-то самописный программатор собранный на коленке под конкретный девайс. Заглянул в код и закрыл от греха подальше. Всё, что можно узнать о подключенном устройстве это первые 1000 байт из памяти. Ну и записать в устройство можно все что угодно начиная с заданного адреса.

Однако это уже первый позитивный опыт — по крайней мере устройство отзывалось и давало записать в себя файлы прошивок. В остальном — никакого толку.

Ну что — пришлось расчехлить старый добрый J-Link, который уже давно пылился на полке. К этому моменту я уже изрядно подзае наковырялся с SDK и даже читал стандартную документацию из комплекта, поэтому в теме уже немножко шарил. Оказывается J-Link это как раз и есть самый прямой путь к счастью. Да и на плате BLE400 есть готовый разъём, поэтому она немедленно была вкорячена в J-Link-овский шлейфик и внимание! это важно подключена через USB к компьютеру. Как оказалось J-Link напрочь отказывается питать подключенное устройство.

В итоге получаем что-то эдакое:

Важно!!!

Владельцев китайских J-Link-ов предупреждаю — не пользоваться стандартной программой для прошивки из SDK nrfjprog. Она использует родную библиотеку от SEGGER, которая палит, что устройство является китайским клоном и убивает его (по счастью не намертво). Я на эти грабли наступил, но косяк этот для меня не в диковинку, поэтому быстро всё восстановил. Ну, а остальные — на свой риск и страх — я вас предупредил.

Собственно именно по этой причине на фото J-Link в разобранном состоянии — пришлось его заново перешивать, что невозможно без разбора.

Итак берём рабочий софт от J-Link и пробуем подключится J-Link Commander-ом. Собственно в командной строке указываем имя устройства (я был реально удивлён, что J-Link «знает» о nRF51822), скорость и тип подключения (swd)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ JLinkExe -device nrf51822 -speed 1000 -if swd
SEGGER J-Link Commander V4.84f ('?' for help)
Compiled May 9 2014 20:12:27
Info: Device "NRF51822_XXAA" selected (257 KB flash, 16 KB RAM).
DLL version V4.84f, compiled May 9 2014 20:12:24
Firmware: J-Link ARM V8 compiled Jul 17 2014 12:31:18
Hardware: V8.00
S/N: 158005115
Feature(s): RDI,FlashDL,FlashBP,JFlash,GDBFull
VTarget = 3.332V
Info: Found SWD-DP with ID 0x0BB11477
Info: Found Cortex-M0 r0p0, Little endian.
Info: FPUnit: 4 code (BP) slots and 0 literal slots
Found 1 JTAG device, Total IRLen = 4:
Cortex-M0 identified.
Target interface speed: 1000 kHz
J-Link>

Как мы видим произошло успешное подключение и даже определился тип чипа Device "NRF51822_XXAA", память (257 KB flash, 16 KB RAM) и процессор Found Cortex-M0 r0p0, что как бы намекает нам, что ура — всё работает.
Итак модуль подключен и подаёт признаки жизни — теперь осталось попробовать залить туда какой-то код и убедиться, что он заработает ну и что вообще мы можем в дальнейшем писать под него код.

Ну и остаётся нераскрыта тема SWD программаторов, коих у китайцев несть числа. Теоретически они должны работать, т. к. это урезанные JLink-и работающие только через SWD. Но у меня такого под рукой нет, поэтому сказать ничего не могу.

Софт

С софтом дело оказалось очень даже неплохо, хотя и немного запутано. Итак компания Nordic поставляет полный набор софта для разработки, кучу примеров и документации.

Качаем SDK с сайта https://developer.nordicsemi.com/nRF51_SDK/

Казалось бы вполне логично взять распоследнюю версию SDK. На сегодняшний день (январь 2018) это v14. Но не тут-то было. В принципе оно как бы должно работать, но SDK версии 14 полностью ориентирован на чипы серии nRF52 и все примеры по умолчанию используют библиотеки именно для этих чипов.

Я конечно вызов принял и было даже попробовал заменить ссылки на библиотеки для nRF51, но не особо преуспел в этом. Код успешно собирается, но залитый в устройство не работает. Пока притормозил эту тему — думаю можно заставить его работать, но я пока решил взять SDK более старой версии, а именно v10. Просто наугад: ) Ну и обнаружил, что там как раз всё вертится вокруг nRF51 семейства, что мне и нужно.

Итого для чипов семейства nRF51 стоит начать обучение с SDK v10. Просто будет чуть проще начать.

Итак качаем и распаковываем nRF51_SDK_10.0.0

Немного теории

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

В принципе можно использовать этот чип не задействовав Bluetooth — просто как микроконтроллер. Но зачем, Ватсон?! Ну в общем это очевидный бред и нелепость.

Простым же смертным людям, которым от этого модуля нужен всё-таки Bluetooth нужен какой-то способ этот Bluetooth использовать прямо здесь и сейчас. И вот для этого случая компания Nordic поставляет некоторый код, называемый softdevice. Фактически это некая мини операционная система которая прошивается в устройство, а свой код мы пишем уже используя API этого softdevice-а.

Softdevice

Именно поэтому в примерах SDK как правило есть примеры в подпапке blank т. е. запускаемые на голом контроллере и примеры для конкретных версий softdevice-ов (с префиксом «s»). Как я понял softdevice-ы отличаются набором функций и размещением в памяти. Конкретно для nRF51822 есть sofdevice-ы версий s110, s120 и s130. Sofdevice-ы поставляются в виде закрытого кода и исходники их недоступны.

Вот по этой ссылке https://www.nordicsemi.com/eng/Products/Bluetooth-low-energy/nRF51822 в разделе «Downloads» можно скачать softdevice-ы для nRF51822. Я не стал мудрить — выкачал последний. Внутри просто hex файл прошивки. Кстати чуть позже нашёл в SDK папку softdevice где лежат те-же файлы.

Ну и чтоб не откладывать дела в долгий ящик зальём что-ли softdevice в наше устройство. Запускаем JLink, цепляем к нему ble400 c модулем и не забываем ble400 подключить к источнику питания (просто воткнем в USB компьютера). Ниже привожу последовательность команд JLink для заливки softdevice-а:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
J-Link>r
Reset delay: 0 ms
Reset type NORMAL: Resets core & peripherals via SYSRESETREQ & VECTRESET bit.
J-Link>w4 4001e504 2
Writing 00000002 -> 4001E504
J-Link>w4 4001e50c 1
Writing 00000001 -> 4001E50C
J-Link>w4 4001e514 1
Writing 00000001 -> 4001E514
J-Link>w4 4001e504 0
Writing 00000000 -> 4001E504
J-Link>r
Reset delay: 0 ms
Reset type NORMAL: Resets core & peripherals via SYSRESETREQ & VECTRESET bit.
J-Link>loadfile /home/roman/.Projects/nrf51/softdevice/s130_nrf51_2.0.1_softdevice.hex
Info: J-Link: Flash download: Flash programming performed for 2 ranges (108544 bytes)
Info: J-Link: Flash download: Total time needed: 2.012s (Prepare: 0.126s, Compare: 0.041s, Erase: 0.000s, Program: 1.827s, Verify: 0.010s, Restore: 0.007s)
J-Link>r
Reset delay: 0 ms
Reset type NORMAL: Resets core & peripherals via SYSRESETREQ & VECTRESET bit.

Команды типа w4 это запись 4-х байтового значения по заданному адресу. Конкретно эти я нашёл где-то в сети. Не очень чётко понимаю что там делается. Заявлено было, что это стирание каких-то областей. В общем надо будет подразобраться с этим шаманством. Но тем не менее это работает. Как видно из команды loadfile заливаю туда прямо hex файл.

Подсмотрел тут

На этом считаю заливку softdevice-а законченной. Теперь нам нужно сварить и залить в модуль какой-нибудь интересный код, чтоб убедиться, что мы можем таки им управлять. По традиции это будет мигающий светодиод — благо их на плате аж 5 штук и ничего дополнительно делать не надо. Но для начала некоторые нюансы SDK.

BLE400 и SDK

Как оказалось все примеры рассчитаны на стандартные платы от Nordic. Но в то-же время нордики благородно оставили возможность добавить свою плату. Фактически нужно создать файл где нужно пробить соответствия физических пинов устройства внутренним константам SDK.

С другой стороны все эти платы в SDK не более чем некие наборы констант (тупо сишные define-ы) и можно вполне обойтись без всего этого геморроя с поддержкой плат. Тем не менее раз уж разобрался — поделюсь опытом.

Для SDK v10 все определения плат лежат в папке examples/bsp. Создаём там файл платы custom_board.h. И в дальнейшем будем использовать именно его.

Запускаем тестовый пример

Как уже писал выше для теста будем использовать простейший пример — моргающие светодиоды. Такой пример есть SDK. расположен он в папке examples/peripheral/blinky. Как мы видим в ней есть как уже скомпилированные варианты прошивок под различные платы, так и исходники под конкретные платы. Нашей платы BLE400 там очевидно нет, поэтому просто скопируем какую-нибудь из существующих и потом подправим её под свои нужды:

1
$ cp -R pca10028 ble400

Вот так вот незатейливо. Внутри у нас 2 папки blink и s110. Первая нам не нужна и её можно смело удалить, а вторая это как раз вариант под softdevice. В данном случае под s110, хотя мы только что залили в модуль s130, но для такого примитивного примера это не беда.

Итак входим в папку s110. Внутри подпапки для различных компиляторов. Нас интересует armgcc. Ура — мы наконец видим Makefile и какой-то ld файл. Ну и к слову исходный код лежит в examples/peripheral/blinky — это файл main.c. Собственно эти 3 файла нам и нужны.

Makefile

Итак для начала правим Makefile. Заменяем везде CFLAGS = -DBOARD_PCA10028 на CFLAGS = -DBOARD_CUSTOM. Так-же меняем
везде по тексту xxac на xxaa. Причина смотри выше про типы чипов. Пример сделан под другой тип чипа. Ну и нужно заменить имя softdevice-а — S110 на S130.

Я ещё поменял PROJECT_NAME на PROJECT_NAME := blinky_s110_ble400.

ld файл

Далее нам надо подправить ld файл blinky_gcc_nrf51.ld — в этом файле описаны области памяти устройства и по умолчанию там данные для xxac чипов, а у нас xxaa. Поэтому нужно его поправить. Чтобы найти правильные значения для нашего чипа посмотрим папку components/softdevice/s130/toolchain/armgcc

1
2
3
4
5
6
7
$ ls -l components/toolchain/gcc
...
-rw-r--r-- 1 roman roman 391 ноя 9 2015 armgcc_s130_nrf51422_xxaa.ld
-rw-r--r-- 1 roman roman 391 ноя 9 2015 armgcc_s130_nrf51422_xxac.ld
-rw-r--r-- 1 roman roman 391 ноя 9 2015 armgcc_s130_nrf51822_xxaa.ld
-rw-r--r-- 1 roman roman 390 ноя 9 2015 armgcc_s130_nrf51822_xxab.ld
...

Вот они родимые. Смотрим что там у нас для xxaa.

Нас в этом файле интересует блок MEMORY — берём значения для полей ORIGIN и переносим в наш файл blinky_gcc_nrf51.ld. Далее нам надо посчитать значения полей LENGTH. Для FLASH это будет размер флеш-памяти устройства (для xxaa 256k) минус размер, который занимает softdevice (для S130 это 112k). Для MEM соответственно LENGTH будет равен размеру ОЗУ (16k для xxaa) минус размер ОЗУ зарезервированный softdevice-ом (для S130 — 10k).

Итого получаем следующий блок MEMORY, который мы и запишем в ld файл.

1
2
3
4
5
MEMORY
{
FLASH (rx) : ORIGIN = 0x1c000, LENGTH = 256k - 112k
RAM (rwx) : ORIGIN = 0x20002800, LENGTH = 16k - 10k
}

На этом с ld файлом мы закончили.

Компиляция

Да — совсем забыл — для сборки все этой истории в системе должны быть установлен компилятор для ARM процессоров. Это пакет gcc-arm-none-eabi. Для успешной сборки нам надо прописать путь к бинарнику компилятора в components/toolchain/gcc/Makefile.posix. Там по умолчанию какой-то хитрый путь, но в моём случае этот файл сейчас выглядит вот так

1
2
3
GNU_INSTALL_ROOT := /usr/
GNU_VERSION := 4.9.3
GNU_PREFIX := arm-none-eabi

Ну собственно вроде всё. Теперь возвращаемся в папку с Makefile-ом нашего тестового проекта с мигающим светодиодом. Ну и собственно т. к. у нас всё уже готово просто запускаем сборку.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ make
rm -rf _build
echo Makefile
Makefile
mkdir _build
Compiling file: system_nrf51.c
Compiling file: main.c
Compiling file: nrf_delay.c
Compiling file: gcc_startup_nrf51.s
Linking target: nrf51422_xxaa_s110.out
make[1]: вход в каталог «/home/roman/.Projects/nrf51/nRF51_SDK_10.0.0_dc26b5e/examples/peripheral/blinky/ble400/s110/armgcc»
Preparing: nrf51422_xxaa_s110.bin
Preparing: nrf51422_xxaa_s110.hex

text data bss dec hex filename
1432 104 172 1708 6ac _build/nrf51422_xxaa_s110.out

make[1]: выход из каталога «/home/roman/.Projects/nrf51/nRF51_SDK_10.0.0_dc26b5e/examples/peripheral/blinky/ble400/s110/armgcc

Как видим всё прошло успешно, правда в выводе мелькает nrf51422 (где-то я не немножко недопилил), но пока оставим это в покое. В данном случае на работу это не повлияет, хотя конечно надо будет разобраться.

Теперь у нас должна появиться папка _build в которой будет готовый hex файл прошивки.

1
2
3
4
5
6
7
8
9
$ ls -l _build
-rw-r--r-- 1 roman roman 7300 янв 7 13:23 gcc_startup_nrf51.o
-rw-r--r-- 1 roman roman 1136 янв 7 13:23 main.o
-rwxr-xr-x 1 roman roman 1536 янв 7 13:23 nrf51422_xxaa_s110.bin
-rw-r--r-- 1 roman roman 4367 янв 7 13:23 nrf51422_xxaa_s110.hex <- вот он
-rw-r--r-- 1 roman roman 26325 янв 7 13:23 nrf51422_xxaa_s110.map
-rwxr-xr-x 1 roman roman 140640 янв 7 13:23 nrf51422_xxaa_s110.out
-rw-r--r-- 1 roman roman 888 янв 7 13:23 nrf_delay.o
-rw-r--r-- 1 roman roman 1328 янв 7 13:23 system_nrf51.o

Заливаем прошивку в устройство

Запускаем JLink и BLE400 так-же как мы это делали в случае с прошивкой softdevice. Не забываем подавать питание на BLE400! Ну и выполняем следующий набор команд: loadfile, r, g — смотри ниже.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ JLinkExe -device nrf51822 -speed 1000 -if swd
SEGGER J-Link Commander V4.84f ('?' for help)
Compiled May 9 2014 20:12:27
Info: Device "NRF51822_XXAA" selected (257 KB flash, 16 KB RAM).
DLL version V4.84f, compiled May 9 2014 20:12:24
Firmware: J-Link ARM V8 compiled Jul 17 2014 12:31:18
Hardware: V8.00
S/N: 158005115
Feature(s): RDI,FlashDL,FlashBP,JFlash,GDBFull
VTarget = 3.332V
Info: Found SWD-DP with ID 0x0BB11477
Info: Found Cortex-M0 r0p0, Little endian.
Info: FPUnit: 4 code (BP) slots and 0 literal slots
Found 1 JTAG device, Total IRLen = 4:
Cortex-M0 identified.
Target interface speed: 1000 kHz
J-Link>loadfile ./_build/nrf51422_xxaa_s110.hex
Info: J-Link: Flash download: Flash programming performed for 1 range (2048 bytes)
Info: J-Link: Flash download: Total time needed: 0.182s (Prepare: 0.090s, Compare: 0.002s, Erase: 0.043s, Program: 0.036s, Verify: 0.000s, Restore: 0.007s)
J-Link>r
Reset delay: 0 ms
Reset type NORMAL: Resets core & peripherals via SYSRESETREQ & VECTRESET bit.
J-Link>g

После этого наблюдаем плату с мигающими светодиодами.

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

Продолжение

Источники

Комментарии