nRF52832 популярный и доступный микроконтроллер, однако информации по нему на русском совсем немного, да и в зарубежных интернетах не до жиру. Спасает Nordic DevZone и Google. В Ардуино есть поддержка данного МК, но для взрослых проектов обычно используют поддержку производителя.
В данной статье я хочу рассказать свой подход к работе с данным МК. Небольшое предупреждение: я бы не советовал брать nRF52832 как первый в своей жизни МК, если вы неплохо знаете STM32 (или другой ARM МК) то вам будет проще работать с nRF52832. Я бы даже советовал для перехода с восьмибитных МК на nRF52832 освоить STM32 как первый в своей жизни ARM МК.
Первый раз я столкнулся с nRF52832 около 4 лет назад, имея опыт разработки только на платформе AVR, и дальше мигания светодиодом не смог продвинуться.
Вступление
Не стану подробно рассматривать установку SEGGER Embedded Studio. Скачивается с официального сайта и устанавливается (в пути к корневой папке не должно быть кириллицы в названиях папок!), для некоммерческого использования с МК фирмы Nordic бесплатна, сейчас даже не требует регистрации и получения лицензии. Так же скачиваем SDK для nRF52832, я использую версию 17.1.0. Автоматически выбраны для скачивания несколько SoftDevice. Создаем папку в которой будем работать с SDK. Важно, чтобы путь к папке и название папки не содержали кириллицы, иначе проект не будет компилироваться. В рабочую папку помещаем скаченный архив и "распаковываем здесь". В папке появляется несколько архивов, из них "распаковываем здесь" архив nRF5_SDK_17.1.0_ddde560. С этого момента можно приступать к работе.
Аппаратная часть
Мы будем работать с примерами для отладочных плат, поэтому можно использовать готовую плату (например pca10040) или сделать свою как это сделал я на базе модуля с AliExpress
. В таком случае потребуется подключить 4 светодиода и 5 кнопок, SWD интерфейс и UART для отладки.
// LEDs definitions for PCA10040
#define LEDS_NUMBER 4
#define LED_START 17
#define LED_1 17
#define LED_2 18
#define LED_3 19
#define LED_4 20
#define LED_STOP 20
#define BUTTONS_NUMBER 4
#define BUTTON_START 13
#define BUTTON_1 13
#define BUTTON_2 14
#define BUTTON_3 15
#define BUTTON_4 16
#define BUTTON_STOP 16
#define RX_PIN_NUMBER 8
#define TX_PIN_NUMBER 6
Кнопки подтянуты к "+" питания и при нажатии замыкаются на землю. Пятая кнопка - RESET подключается к ноге P0.21. Примеры с Bluetooth не будут работать без кнопок, а если ошибиться и после запуска МК будет переходить в сон, то прошить его без кнопки RESET будет невозможно. Для исключения зависания при работе с UART лучше подтянуть RX к "+" питания.
В качестве программатора применяю J-Link, сделанный из BluePill. Инструкцию по сборке можно найти в Google.
Проверяем
Задумывал статью как короткую и интересную заметку, а уже получилась скучная инструкция о том, как подключить кнопки и светодиоды. Надеюсь что следующая будет компактнее и интереснее.
Для проверки собираем и запускаем пример мигалки светодиодом. Надо открыть файл проекта по очень сложному пути в папках SDK. (Эту тайну я познал благодаря видео на YouTube)
Желтая стрелка указывает на папки с проектом, красная - на тип отладочной платы, зеленая - на тип используемого SoftDevice. Синяя стрелка указывает на файл проекта, который необходимо открыть. Запустится SEGGER. Нажимаем Build -> Build Solution, затем Debug -> Go. После записи программы в МК запускаем пример и светодиоды должны весело замигать
Начинаем начинать!
Хоть некоторые считают, что проекты надо собирать самому, но в данном случае количество библиотек в SDK огромно, и те из них, которые работают с BLE для меня представляют черный ящик, да и исходники SoftDevice закрыты. После очень долгих переделок проекта главной парадигмой программирования nRF52832 для меня стало выбрать наиболее подходящий пример и делать из него. Я хочу рассказать как сделать BLE UART устройство.
В среде радиолюбителей широко распространены Bluetooth UART модули вроде HC-05, HM-10 и другой зоопарк китайских поделок. Для этих модулей уже созданы Android приложения, да и работа в терминале удобна и проста. Поэтому я приведу пример мигалки светодиодом, управляемой через Serial Bluetooth Terminal.
Откроем папку ble_peripherial, и скопируем папку с примером ble_app_uart в созданную ранее папку (показана стрелкой). Это все необходимо чтобы уровень корня проекта не менялся и не терялась связь с библиотеками. Открываем и запускаем наш подопытный проект. Можно убедиться в работоспособности и подключить USB-UART преобразователь и соединиться с устройством в программе Serial Bluetooth Terminal с телефона.
А вот при попытке соединиться с устройством в меню Bluetooth телефона вас постигнет первое серьезное разочарование. Данный пример не поддерживает соединение.
Решение этой проблемы достойно отдельной статьи. Я не стану описывать как я в данный проект добавлял поддержку соединения, потому что простым и верным решением будет добавление поддержки ble_nus в пример, поддерживающий подключение.
Начнем с мигалки светодиодом на аппаратном таймере. В файле main (в котором очень много строк и можно заблудиться), добавляем макрос для создания таймера:
APP_TIMER_DEF (m_led_timer_id);
Находим функцию static void timers_init(void) и добавляем в нее создание таймера, функция будет выглядеть так:
static void timers_init(void)
{
ret_code_t err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
err_code = app_timer_create(&m_led_timer_id, APP_TIMER_MODE_REPEATED, timer_led_event_handler);
APP_ERROR_CHECK(err_code);
}
И создадим две функции, одна запускает таймер, вторая является обработчиком прерывания:
/**@brief Function for initializing the timer module.
*/
static void timers_start(void)
{
ret_code_t err_code;
err_code = app_timer_start(m_led_timer_id, APP_TIMER_TICKS(500), NULL);
APP_ERROR_CHECK(err_code);
}
void timer_led_event_handler(void* p_context)
{
bsp_board_led_invert(3);
}
Остается вызвать функцию timers_start();
перед переходом МК в бесконечный цикл, в котором МК уходит в сон и просыпается по прерываниям. Запускаем и четвертый светодиод начинает мигать с периодом 1 секунда.
Теперь добавим работу с BLE. Заставим при мигании светодиодом еще и отправлять данные в BLE терминал. Для этого немного доработаем функцию обработчика прерывания:
void timer_led_event_handler(void* p_context)
{
ret_code_t err_code;
uint8_t buff [20];
static uint8_t count;
bsp_board_led_invert(3);
sprintf (buff, "led_invert %d\n", count);
uint16_t length = strlen (buff);
err_code = ble_nus_data_send(&m_nus, buff, &length, m_conn_handle);
if ((err_code != NRF_ERROR_INVALID_STATE) &&
(err_code != NRF_ERROR_RESOURCES) &&
(err_code != NRF_ERROR_NOT_FOUND))
{
APP_ERROR_CHECK(err_code);
}
count ++;
}
Подключаемся через терминал и видим, что имя устройства изменено и телефон принимает данные. (При изменении имени устройства могут возникнуть проблемы с подключением, если такое случается, то надо удалить данные о соединении Bluetooth и подключиться снова).
Осталось сделать управление. Находим функцию обработки прерывания от ble_nus и вандалим ее! Заменим отправку данных по UART на управление аппаратным таймером:
static void nus_data_handler(ble_nus_evt_t * p_evt)
{
if (p_evt->type == BLE_NUS_EVT_RX_DATA)
{
uint32_t err_code;
NRF_LOG_DEBUG("Received data from BLE NUS. Setting App_Timer.");
NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
if (p_evt->params.rx_data.p_data[0] == '0')
{
bsp_board_led_invert(2);
err_code = app_timer_stop(m_led_timer_id);
APP_ERROR_CHECK(err_code);
}
else if (p_evt->params.rx_data.p_data[0] == '1')
{
err_code = app_timer_start(m_led_timer_id, APP_TIMER_TICKS(500), NULL);
APP_ERROR_CHECK(err_code);
}
}
}
Теперь если отправить 0 через терминал, то таймер остановится, а если отправить 1, то снова запустится.
Я делал устройство для работы с готовым приложением LK8000, и тут меня ждало второе разочарование: даже сделав устройство подключаемым, не удалось получить данные, потому что LK8000 сделан для работы с BLE UART модулями и у них другие сервисы и характеристики BLE, про это напишу позже.
Послесловие
На данный момент это самый сложный МК для меня и я потратил очень много времени даже на освоение того, что описал в этой статье. Надеюсь что этой информацией облегчу задачу освоения nRF52832. Задавайте вопросы в комментариях и ждите следующих публикаций.
Сергей Авдонин, схемотехник.