Bluetooth Smart Broadcaster на RSoC фирмы Cypress

Эта вводная статья по тематике является продолжением моей статьи [2]. Здесь я расскажу о разработке микромощного BLE (Bluetooth Low Energy) устройства, или как их сейчас принято называть, Bluetooth Smart. Устройство выполняет функцию маяка и построено на модуле CYBLE-022001-00 фирмы Cypress Semiconductor.

Модуль основан на PRoC (Programmable Radio on Chip) микросхеме CYBL10xxx, микроконтроллер (МК) которой принадлежит семейству PSoC-4. Помимо самого чипа на плате модуль содержит всю необходимую пассивную обвязку, включая кварц на 24 мгц, часовой кварц, и чип-антенну. Модуль имеет весьма малые размеры и толщину всего 1.3мм, определяемую антенной. Фирма выпускает несколько модификаций модуля с разными типами антенн и числом выводов, а также объёмом флеш и SRAM памяти встроенного МК до 256К и 32К, соответственно. МК выполнен по архитектуре Cortex-M0, может тактироваться на частотах до 48мгц, и обладает стандартной периферией. Помимо BLE стека фирмы, согласующегося с последней на настоящий момент спецификацией Bluetooth 4.2, в МК модуля также может быть загружена и программа пользователя. Сам стек занимает около 60К флеша и требует примерно 9.8К SRAM. Я использовал модуль семейства с минимальным объёмом флеша 128К, так что даже в нём остаётся достаточно места для многих проектов. Подробнее о вариантах модулей можно прочитать в документе [4], доступного с вебсайта фирмы cypress.com.

Тестовый проект маяка заключается в периодическом измерении температуры и влажности воздуха и передаче этих данных через канал BLE. Для начального ознакомления с миром BLE рекомендую почитать книгу [1]. Проект выполнен по следующей принципиальной схеме.

В качестве сенсора IC2 используется новая модель от Texas Instruments, которая является модификацией их первой модели подобного сенсора HDC1000. О работе с последним можно прочитать в моей статье [3]. Модификация коснулась прежде всего корпуса сенсора и делает его полностью совместимым по выводам с некоторыми сенсорами других производителей, такими как HDU21D, SHT21, или Si7021. Однако, система команд сенсора не совместима с последними и упрощена до предела. Измерение обоих параметров среды производится сенсором за рекордное время 13мсек и цена его самая низкая среди перечисленных. На схеме отсутствуют внешние подтягивающие резисторы на линиях интерфейса I2C, поскольку таковые, с сопротивлением около 5.6К, встроены в RSoC. Конденсатор C1 не является необходимым в нашем случае. Я его установил на макетную плату радио-модуля для работы с touch-sense приложениями.

Для разработки проектов под PSoC/RSoC фирма предлагает свою систему PSoC Creator. Интуитивный интерфейс системы позволяет без особого труда визуально сконфигурировать любой из более 120 поддерживаемых системой hardware и software модулей, в том числе и модуль BLE. После выбора и конфигурирования модулей проекта и генерации конфигурирующего их кода, весь проект по желанию можно портировать в другие IDE, такие как IAR Workbench или Keil µVision. Система, естественно, снабжена обширной документацией и на вебсайте фирмы имеется многосерийное видео, доходчиво показывающее как с ней работать. Вот пример того, как может выглядеть проект с цифровыми и аналоговыми модулями в окне PSoC Creator.

Пожалуй одним из первых вопросов, возникающих при работе с новым МК – это чем его запрограммировать. Отрадно, что наш МК поддерживает стандартный ARM-овский SWD интерфейс для программирования и отладки. Более того, после портирования проекта в Keil IDE, программирование и отладку можно будет производить через инструмент ULINK, снабжённый соответствующим плагином. Однако, из-за особенностей программирования PSoC, первый раз программирование их всё равно следует производить только эксклюзивными программаторами фирмы, учитывающими специфику её изделий. Об этом подробнее написано в документации на систему.

Штатным программатором фирмы для PSoC/RSoC фирмы является MiniProg3, который, кстати, после установки плагина напрямую поддерживается и из Keil IDE. В начале моего знакомства с RSoC у меня такого не было и для работы я использовал встроенный программатор, имеющийся на отладочной плате CY8CKIT-042-BLE “Bluetooth Low Energy Pioneer Kit”. С помощью этого программатора можно отлаживать и PSoC/RSoC чипы вне платы, следует только распаять на ней разъём для кабеля, обведённый в зелёном кружке ниже. Весь Кит, кстати, чрезвычайно полезен для первоначальной отладки RSoC проектов. Проект для одной RSoC можно буквально за несколько кликов мышкой переконфигурировать для других моделей RSoC фирмы.

Позже, вместо того, чтобы платить 90 USD за Кит CY8CKIT-002 программатора MiniProg3, я получил его почти вдвое дешевле в составе набора CY5672 наряду с CySmart USB Dongle CY5670, который я использую для отладки BLE устройств посредством компьютера, и другими интересными и полезными «штуками» в наборе. На снимке ниже показана установка радио-модуля и сенсора на платках для безпаячной макетки.

Однако, вернёмся к нашему проекту и спроектируем простейшее BLE периферийное устройство, играющее роль Broadcaster. Устройство работает как маяк, периодически, примерно раз в секунду, посылая в эфир данные температуры и влажности воздуха, измеряемые сенсором с периодом около 60 секунд. Для этого нам потребуются два периферийных модуля: модуль BLE и модуль интерфейса I2C. Подтянем их мышкой из каталога выбора компонентов на панель устройства.

Модули эти между собой не связаны и управляются центральным процессором системы. Конфигурацию начнем с более простого модуля I2C, кликнув на него 2 раза мышкой. Всё, что в нём следует сконфигурировать в открывшемся окне – это режим Master и выбрать Data rate. Остальные параметры конфигурируются автоматически в зависимости от тактирующей процессор частоты (см. ниже).

Далее, нам нужно выбрать выводы корпуса под интерфейс I2C. Для этого нажимаем на закладку конфигуратора hardware и в ней внизу выбираем опцию Pins. В правой панели выбираем релевантные выводы корпуса (для линий I2C там имеется несколько возможностей). Отмечу, что выводы модуля показаны почему-то при виде на него снизу.

Наконец, в той-же панели внизу выбираем опцию Clock, затем Edit Clock, и в открывшемся окне устанавливаем частоту тактирования генератора IMO равной 12мгц. Как показали эксперименты, такой выбор частоты оказался оптимальным с точки зрения токопотребления.

Для завершения программирования интерфейса с сенсором следует написать драйвер, содержащий функции записи в сенсор команд для производства новых измерений и чтения из него данных параметров температуры и влажности. Я поместил их в отдельный файл hdc1050.c. Обе функции используют библиотечные API для записи и чтения по интерфейсу I2C. Окончание работы интерфейса определяется по установке соответствующего флага статуса I2C модуля, который проверяется в while-цикле. После приёма данных производится вычисление температуры и влажности по формулам из ДШ сенсора.

Обратимся теперь к конфигурации BLE модуля. Для этого кликаем на него 2 раза в панели проекта и в открывшемся окне в закладке General выбираем GAP роль Broadcaster, что соответствует работе нашего устройства в режиме маяка.

Далее, в закладке GAP Settings и опции General устанавливаем Device Name, которое будет видно сканером Bluetooth устройств, а также мощность маячка в режимах передачи извещений (advertisement) и ответов на запросы сканера. Естественно, чем больше мощность, тем больше токопотребление и радиус действия, так что нужен компромисс.

Далее, в опции Advertisement settings нам следует выбрать радио-каналы работы маяка. Как известно, извещения передаются на BLE каналах 37, 38, и 39. IDE предоставляет возможность выбрать любую их комбинацию. Чем больше каналов задействовано под извещения, тем больше токопотребление. Однако, тем быстрее маяк будет обнаружен BLE сканером, так что опять нужен компромисс. На токопотребление и скорость обнаружения маяка также влияет интервал передачи извещений. Можно установить одинаковые значения Minimum и Maximum интервала. В любом случае к интервалу трансляции извещений стеком BLE будут подмешиваться некоторые значения от генератора случайных чисел, что уменьшает вероятность одновременной передачи разных BLE устройств в радиусе действия. Максимальный период извещений не должен превосходить 10.2сек. В условиях постоянной работы маяка следует снять галку с Timeout. В противном случае, после истечения Timeout устройство изменит интервал извещений в соответствии с установками в Slow Advertising Interval, если это разрешено галкой. Если нет – то будет сгенерировано событие ADVERTISEMENT_START_STOP, которое передастся в пользовательский обработчик прерываний стека, где программа пользователя может решить что делать дальше. Например, прекратить посылку извещений или возобновить их с меньшим интервалом.

Далее, в опции Advertisement packet нам следует определить что-же именно будет передаваться нашим маяком. Выберем передачу полного имени устройства и Manufacturer Specific Data. В качестве последнего, в поле Data поставим два 8-битных числа разделённых пробелом (или одно 16-битное), дав конфигуратору понять о намерении передачи двух байтов. Позже мы программно загрузим туда значения температуры и влажности (как целые числа). На этом этапе важно отметить, что индексы наших данных в передаваемом пакете равны 25 и 26 (см. правую колонку) и при выборе другого имени устройства индексы эти могут быть иными, что необходимо будет скорректировать в программе. В поле Company следует выбрать одну из предлагаемых опций. Двухбайтный код компаний регламентируется организацией SIG (Bluetooth Special Interest Group).

Наконец, в опции Scan response packet нам следует определить что будет передаваться нашим устройством на запрос сканера. Можно и оставить все поля там не выбранными.

На этом конфигурация модулей устройства закончена. Нажимаем на Build -> Generate Application и получим фактически пустой (пока) файл main.c, а в левом окне Workspace Explorer и папке Generated_Source тонны кода реализации того, что мы только что накликали мышкой.

Следующая часть работы в процессе проектирования устройства состоит в написании кода приложения с использованием техники разработки микромощных устройств. Об этом имеется замечательный документ [5], который я и взял за основу. Вообще, не могу не отметить, что фирма проделала огромную работу по упрощению разработки приложений на её продукции. В частности, это относится к написанию подробнейшей документации по любому поводу и многочисленным примерам программ, доступных как в момент создания проекта, так и на любой его стадии. Например, документация на BLE модуль занимает более 500 страниц текста и (как и документация на любой другой модуль) легко доступна из окна конфигурирования модуля. Помимо API работы с конкретными модулями имеется, в частности, отдельный 100-страничный документ по общим API cy_boot для hardware, доступным через папку установки PSoC Creator на компьютере. Если хотите ещё глубже вникнуть в работу чипа, читайте 270-страничный докумет Technical Reference Manual (TRM) на Ваш чип. Ну а если захотите стать экспертом и понять всё про RSoC до последнего бита – тогда Вам читать вторую часть TRM с описанием всех регистров, занимающую более 3900 страниц текста.

Однако, к счастью (или несчастью) для большинства проектов осваивать всю эту литературу досконально при наличии PSoC Creator не требуется. При разработке микромощных устройств следует понимать, что для погружения системы в режим глубокого сна (с потреблением 1.3мкА) необходимо согласие на это как приложения, так и BLE стека. Как минимум, полезно иметь в виду следующую диаграмму из [5].

В нижней части диаграммы показаны сигналы работающего постоянно WCO (Watch Crystal Oscillator), используемого для генерации временных интервалов пробуждения чипа из глубокого сна, и отключаемого на время сна ECO (External Crystal Oscillator) частоты 24мгц, используемого для синтеза частот приёма/передачи и генерации временных интервалов для Link Layer стека. Для большинства приложений тактирование стека достаточно производить на 1/8 частоте этого генератора. Помимо этих в RSoC ещё имеется внутренний RC-генератор IMO с управляемой частотой и низкочастотный 32-кгц генератор ILO, который в нашем случае можно просто выключить. Поскольку процессор обслуживает и BLE стек и приложение, необходимо, чтобы последнее не влияло на жёсткие временные характеристики обработки протокола. Проще всего этого можно достигнуть путём разрешения процессору работать на приложение в момент разгона ECO после сна до начала работы стека, и/или после окончания его работы, как только BLESS (BLE SubSystem) перейдёт в состояние EVENT_CLOSE. Я следую второй опции. В этом случае тактирование процессора, в зависимости от нужд приложения, можно производить как от ECO, так и от IMO. Поскольку ECO в этом состоянии работает, IMO в целях экономии энергии можно программно выключить и производить тактирование процессора от ECO (я этого, однако, для простоты не делаю).

Для эффективного использования энергии стеком, BLESS следует как можно чаще переводить в режим сна. Для этого служит вызов двух функций в начале основного цикла main() — CyBle_ProcessEvents() и CyBle_EnterLPM(CYBLE_BLESS_DEEPSLEEP). Первая из них обрабатывает события, генерируемые стеком (если таковые на момент вызова имеются), а вторая пытается ввести BLESS в режим наименее возможного токопотребления. Идеально это был-бы режим DEEPSLEEP, о чём говорит параметр функции. Функция эта достаточно интеллектуальна, чтобы автоматически проверить текущее состояние BLESS и в зависимости от этого выбрать режим наиболее близкий по токопотреблению к затребованному параметром. Далее в коде производится проверка в какое именно состояние перевела BLESS эта функция, и если оно придётся на момент разгона кварцевого генератора или окажется DEEPSLEEP, то можно и всю систему перевести в это состояние функцией CySysPmDeepSleep().

Работа остальной части приложения должна быть понятна из кода. Приложение активизируется каждый раз после отсылки всех пакетов маяком примерно раз в секунду. При этом уменьшается на единицу счетчик числа посланных пакетов, и как только он обнулится, то значит пора обновить payload пакетов результатом предыдущего измерения и сделать запрос на новое измерение. Отмечу, что подключение внутренних подтягивающих резисторов на линии I2C нельзя осуществить установкой где-то галки конфигуратором, а может быть выполнено только путём явного программного вызова соответствующих функций в начале main().

Чего-же мы добились в результате этих ухищрений в плане токопотребления? В таблице ниже приведены экспериментальные данные по режиму Broadcast из [5]. Важно отметить, что для получения низкого токопотребления выводы отладки SWDIO и SWDCLK модуля (P0.6 и P0.7) необходимо переконфигурировать под функцию GPIO.

В нашем случае к этому токопотреблению добавится некий эпсилон из-за коммуникации с сенсором и производства измерений примерно раз в минуту. Коммуникация эта занимает не более миллисекунды, в соответствии с осциллограммой ниже, в течении которой МК тактируемый на частоте 12 мгц потребляет порядка 4мА, так что добавка эта несущественная.

В заключении пара слов о приёмном конце. Для отладки BLE приложений удобно воспользоваться программой CySmart. Она доступна для Windows компьютеров, или как Android приложение. В первом случае, для компьютеров не поддерживающих BLE, для работы с ней потребуется CySmart USB Dongle CY5670, водящий в состав Китов, упомянутых выше. Во втором, ваш смартфон/планшет должен быть типа Bluetooth Smart или Smart Ready, иными словами он должен поддерживать Bluetooth 4.0 или выше. Вот, что мы увидим в окне CySmart:

Байты с индексами 25 и 26 передаваемого пакета извещения несут информацию о температуре (0х14 = 20°C) и влажности (0х29 = 41%). Ниже приложен код из файла main.c. Для дальнейших примеров рекомендую посетить блог [6] на вебсайте фирмы, содержаший на момент написания 48 примеров работы с BLE модулями, снабжённых исходниками и подробной документацией.

Литература

  • K. Townsend and C. Cufi “Getting Started with Bluetooth Low Energy: Tools and Techniques for Low-Power Networking”, O’Reilly Media 2014.
  • Разработка BLE приложений в системе Anaren Atmosphere
  • О комбинированных сенсорах параметров среды MS8607 и HDC1000
  • Cypress AN96841: Getting Started with EZ-BLE Module.
  • Cypress AN92584: Designing for Low Power and Estimating Battery Life for BLE Applications.
  • 100 Projects in 100 Days with PSoC 4 BLE
  • //************************************************************************************************
    // File main.c
    #include <Project.h>

    /***************************************
    * Extern and constants required for
    * dynamic ADV payload update
    ***************************************/
    extern CYBLE_GAPP_DISC_MODE_INFO_T cyBle_discoveryModeInfo;
    extern int8 temp;
    extern uint8 humi;

    /* ADV payload dta structure */
    #define advPayload (cyBle_discoveryModeInfo.advData->advData) // shortcut
    #define TEMP_DATA_INDEX (25u) // index of temperature data in the ADV packet
    #define HUMI_DATA_INDEX (26u) // index of humidity data in the ADV packet
    #define CONVERSION_PERIOD (60u) // temp/humi measurement period (in ADV periods)

    /***************************************
    * Function Prototypes
    ***************************************/
    void StackEventHandler(uint32 event, void* eventParam);
    extern void requestConversion(); // sensor interface
    extern void getTempHumi(); // sensor interface

    /***************************************
    * Global variables
    ***************************************/
    CYBLE_API_RESULT_T apiResult;
    CYBLE_BLESS_STATE_T blessState;
    uint8 intrStatus, adCounter;

    /*******************************************************************************
    * Function Name: main
    ********************************************************************************/
    int main()
    {
    I2C_Start();
    I2C_scl_SetDriveMode(I2C_scl_DM_RES_UP); // use internal pull-up I2C resistors
    I2C_sda_SetDriveMode(I2C_sda_DM_RES_UP);
    I2C_Sleep();

    CyGlobalIntEnable;
    apiResult = CyBle_Start(StackEventHandler); // Init the BLE stack and register applicaiton callback
    if(apiResult != CYBLE_ERROR_OK)
    CYASSERT(0); // BLE stack initialization failed, check your configuration

    CySysClkWriteEcoDiv(CY_SYS_CLK_ECO_DIV8); // set XTAL divider to 3MHz mode
    CySysClkIloStop(); // shut down ILO

    while (CyBle_GetState() == CYBLE_STATE_INITIALIZING)
    CyBle_ProcessEvents(); // wait for BLE stack to initialize

    adCounter = 1; // init ADV counter
    while(1) // main application loop
    {
    CyBle_ProcessEvents(); // service BLE stack events
    CyBle_EnterLPM(CYBLE_BLESS_DEEPSLEEP); // put BLESS into lowest power mode

    intrStatus = CyEnterCriticalSection(); // disable interrupts
    blessState = CyBle_GetBleSsState(); // get current BLESS state
    if(blessState == CYBLE_BLESS_STATE_ECO_ON || blessState == CYBLE_BLESS_STATE_DEEPSLEEP)
    {
    CySysPmDeepSleep(); // 1.3uA current consumption
    }
    else if (blessState != CYBLE_BLESS_STATE_EVENT_CLOSE) // BLESS is active
    {
    CySysClkWriteHfclkDirect(CY_SYS_CLK_HFCLK_ECO);
    CySysClkImoStop();
    CySysPmSleep(); // ~1.6mA current consumption
    CySysClkImoStart();
    CySysClkWriteHfclkDirect(CY_SYS_CLK_HFCLK_IMO);
    }
    CyExitCriticalSection(intrStatus); // re-enable interrupts

    if (CyBle_GetBleSsState() == CYBLE_BLESS_STATE_EVENT_CLOSE) // BLESS event is over
    {
    adCounter—; // update ADV counter
    if (adCounter == 0) // time for a new measurement?
    {
    adCounter = CONVERSION_PERIOD; // reset ADV counter
    I2C_Wakeup();
    getTempHumi(); // request new conversion
    requestConversion(); // read TEMP and HUMI from sensor
    I2C_Sleep();
    advPayload[TEMP_DATA_INDEX] = temp; // update ADV payload
    advPayload[HUMI_DATA_INDEX] = humi;
    CyBle_GapUpdateAdvData(cyBle_discoveryModeInfo.advData, cyBle_discoveryModeInfo.scanRspData);
    }
    }
    }
    }

    /*******************************************************************************
    * Function Name: StackEventHandler
    ********************************************************************************/
    void StackEventHandler(uint32 event, void *eventParam)
    {
    (void)eventParam; // avoid warning about unused eventParam
    switch(event)
    {
    case CYBLE_EVT_STACK_ON:
    case CYBLE_EVT_GAP_DEVICE_DISCONNECTED: // start BLE advertisement
    CyBle_GappStartAdvertisement(CYBLE_ADVERTISING_FAST);
    break;

    default:
    break;
    }
    }

    Источник

    Оставить комментарий

    Вы можете использовать следующие теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>