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 и подключиться снова).

Вот он, первый успех в покорении Bluetooth!
Вот он, первый успех в покорении 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. Задавайте вопросы в комментариях и ждите следующих публикаций.

Сергей Авдонин, схемотехник.

Комментарии (10)


  1. LeshiyUrban
    19.11.2022 06:50

    Можно, пожалуйста, для непрофильных специалистов дать краткий обзор преимуществ и недостатков этого модуля?


    1. fk0
      19.11.2022 13:20
      +5

      Можно построить на одном чипе решение в котором комбинируется BLE и микроконтроллер. Что при массовом производстве может быть выгодней отдельного контроллера и отдельного BLE трансивера (от того же Nordic Semiconductor). Может быть меньше сложностей с микропотреблением и с тактовым генератором (с отдельным контроллером -- у каждого свой и порядочно потребляет).

      Область применения: брелоки для сигнализаций, смарт-тэг метки, автономные логгеры температуры, да тьма их. Везде где нужен микроконтроллер и bluetooth. Наличие именно ARM вместо слабенького x51 позволяет именно что отказаться от второго контроллера (раньше Nordic что-то делал с x51).


    1. atd
      20.11.2022 00:20

      К вышесказанному добавлю ещё и габариты, китайцы на этом же контроллере делают платы 9×9мм (это вместе с чип-антенной, сам контроллер 3×3 мм в WLCSP)


  1. fk0
    19.11.2022 13:22
    +2

    Совершенно не описано, ни как в чем компилируется программа (в IDE -- это не ответ), ни чем программируется. Насколько я понимаю, там где-то в IDE спрятан clang или gcc и можно использовать свой, а программируется только через нордиковский кит, или возможно через J-link.


    1. Paultino
      19.11.2022 14:07
      +5

      Через J-link. GCC.

      В статье "старый" подход. Они переключились на другой sdk - Zephyr rtos .

      И в статье указано что Segger Embedded Studio бесплатно для Nordic, это не так. Nordic edition был, теперь нет. Рекомендованная среда разработки от Nordic Semi теперь VS Code + плагины от Nordic Semi.


      1. Kudriavyi Автор
        19.11.2022 16:35
        +1

        https://www.nordicsemi.com/Products/Development-tools/segger-embedded-studio

        FREE for Nordic customers
        Так что до сих пор бесплатно. Про Zephyr rtos я слышал, но информацию нормальную не находил.


        1. Paultino
          19.11.2022 16:45
          +2

          Как не находили?

          Два основных ресурса.

          Infocenter.nordic*

          И

          https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/index.html

          Там всё. И не нужен YouTube.


    1. zurabob
      20.11.2022 03:11

      Имеется SDK под Keil, GCC, IAR и куча примеров с makefile(под GCC). Для программирования есть своя утилита, но можно и через обычный J-LINK или OpenOCD+CMSIS-DAP для линуксоидов. И, как обычно, предлагается использовать это SDK в составе монстрообразной IDE, но это совершенно необязательно.

      SDK очень неудобно и непривычно, не очень хорошо документировано и построено на многоуровневых макросах, что сильно затрудняет понимание его потрохов. Кроме того вся работа с BLE идет через отдельную прослойку SoftDefice, при работе через которую есть ряд ограничений и отдельных функций для работы с задействованными в нем ресурсами и критичными по времени действиями, например запись во флеш.

      Периферия тоже отличается от привычной и поначалу кажется неудобной, все построено на Signal - Event, которые могут цепляться друг за друга.


  1. sav13
    20.11.2022 07:29

    О чем написать далее

    Напишите о NRF52833 и работе в Zigbee


  1. Whitech
    21.11.2022 08:40

    "информации по нему на русском совсем немного, да и в зарубежных интернетах не до жиру."

    Вы это серьезно? У Nordic шикарная документация, огромнейшее комьюнити и очень толковый форум. Жаль вот только описываемый Вами старый nRF5 SDK они списывают на свалку и переходят на nRF Connect SDK основный на Zephyr RTOS даже для мелких и таких старых как nRF52832 микроконтроллеров. О чем на Хабре есть статьи. Так что осваивать сейчас nRF5 SDK уже несколько поздно и не актуально.