РадиоКот :: Радиомодули для беспроводной передачи данных. Часть 4.
Например TDA7294

РадиоКот >Статьи >

Теги статьи: Добавить тег

Радиомодули для беспроводной передачи данных. Часть 4.

Автор: Сергей Безруков (aka Ser60)
Опубликовано 29.06.2021
Создано при помощи КотоРед.


После публикации частей 1, 2, и 3 этой серии в 2014 прошло уже более 6 лет. И хотя рассматриваемые там микросхемы трансиверов всё ещё выпускаются и никаких новых трансиверов суб-гигагерцового диапазона фирмой Silicon Labs не разработано, внимание разработчиков всё чаще концентрируется на изделиях, содержащих в одном корпусе радио-тракт и микроконтроллер, способный выполнять программу пользователя. Впрочем, такие микросхемы у фирмы Silicon Labs (также как и у других фирм, здесь пока не рассматриваемых) были на рынке и 6 лет назад, скажем серии Si10xx, основанные на МК архитектуры 8051. Эти беспроводные МК, наряду с разработанной в 2015–16 годах серией EZR32 с архитектурой ARM Cortex-M4, содержали хорошо себя зарекомендовавший радио-тракт трансиверов серии EZRadioPRO (модели Si446x), и управлялись встроенным МК по внутренней шине SPI. Почти в то же время начался выпуск микроконтроллеров новой серии EFR32 (Energy Friendly Radio), о которой пойдёт речь в этой статье. Радио-тракт этих микросхем отличается от серии EZRadioPRO и способен работать как в суб-гигагерцовом диапазоне, так и в диапазоне 2.4 ГГц, или даже в обоих в зависимости от модели. Здесь мы рассмотрим только модели МК серии EFR32, оснащённые радио-трактом для работы в диапазоне частот до 1 ГГц, и предназначенные для реализации проприетарных протоколов. Некоторые их характеристики приведены в следующей таблице.

Стрелочки в таблице означают, что соответствующий параметр такой-же, как и в самом левом от них столбце. Из этих семейств МК мы сконцентрируемся на первом и последнем. Модели семейства FG1 самые старые, а FG14 – самые новые (FG = Flex Gecko). Несмотря на более высокую цену этих моделей, в одном корпусе вы получаете МК, радио, а также понижающий DC/DC преобразователь, заметно повышающий энерго-эффективность систем. Кроме того, эти МК содержат встроенный балун на диапазон 2.4 ГГц и не требуют внешнего антенного переключателя. Микросхемы выпускаются в корпусах QFN32 и QFN48 и полностью совместимы по выводам.
Работу с беспроводными МК удобнее всего начать на отладочных платах фирмы. Для этого выпускается универсальная плата WSTK (BRD4001A), поверх которой можно установить модули расширения на основе всех беспроводных семейств фирмы. Помимо отладчика, ЖКИ, кнопок, светодиодов, и сенсора температуры и влажности Si7021 на плате WSTK имеется уникальный блок для измерения токопотребления. Плата WSTK с установленным на нём модулем расширения BRD4250A на основе МК серии EFR32FG1P133F256 показана ниже.

Помимо этой платы расширения для диапазона 915 МГц выпускаются ещё две платы: BRD4257A и BRD4262A на основе МК семейства FG14. Отличие их в том, что на последней вместо кристалла на 38.4МГц установлен TCХO. В комплект всех плат расширения входит полуволновая штыревая антенна на диапазон 915 МГц, а на плате модулей, способных работать в диапазоне 2.4 Ггц, интегрирована печатная антенна. Имеются платы расширения и на другие комбинации диапазонов (169/2.4, 434/2.4, 490/2.4, 868/2.4, и только 2.4 Ггц).

 

Касательно среды разработки, у фирмы имеется замечательная и бесплатная система Simplicity Studio v5 на основе платформы Eclipse, которую мы и будем использовать. Кроме собственно разработки ПО она предоставляет (помимо всего прочего) централизованный доступ к документации, схемам модулей, компоновке и списку компонентов отладочных плат, а также к различным руководствам и примерам программ, демонстрирующих различные функции соответствующей продукции.

Особое внимание в суб-гигагерцовом диапазоне уделяется разработке проприетарных протоколов. Это была Ахиллесова пята во всех моих прежних проектах на отдельных трансиверах, поскольку помимо использования управляющих ими МК разных семейств приходилось изобретать что-то своё в плане протокола связи для реализации требуемого функционала устройства. После десятка проектов я уже плохо помнил, что и как реализовано в каждом из них, если требовалось повторить что-то подобное в очередном новом проекте или что-то изменить в старом. С переходом работы под Studio этому был сразу и безоговорочно положен конец, поскольку фирма предлагает два удобных и унифицированных подхода к реализации проприетарных беспроводных протоколов. Один из них основан на программной библиотеке RAIL (Radio Abstraction Interface Layer), а другой - на системе Connect. Здесь мы рассмотрим первую опцию, для которой в Studio необходимо установить модуль Flex SDK (Software Development Kit). RAIL включает внушительное количество функций API взаимодействия с радио и высокоуровневой реализации многих основных компонентов проприетарных протоколов связи. Он также позволяет легко переходить от одной модели беспроводного МК к другой буквально за несколько кликов мышкой. В прежних статьях цикла я писал про огромное число регистров конфигурации трансиверов (более 150), ориентироваться в которых непросто, даже при наличии конфигуратора WDS3. В МК серий EFR32 регистры радио-тракта даже не описаны в Reference Manual на семейство, так что приходится полностью (и без сожаления) полагаться на RAIL API. Несмотря на наличие некоторых примеров в Studio, я опишу здесь несколько других примеров беспроводной коммуникации между двумя устройствами. Начнём с самого простого случая и постепенно добавим в проект больше функций. Полные коды проектов представлены в приложенном к статье архиве.

 

Простая односторонняя передача данных

В моих проектах, пожалуй, самая распространённая ситуация — это когда требуется передать данные в одну сторону от передатчика к приёмнику. Приёмник предполагается всё время быть включённым и готовым к приёму информации в любое время, даже если передача данных ожидается довольно редко. Передатчик-же желательно сделать как можно более экономичным и потребляющим не более 2–3 мкА в паузах между передачами. Во время передач токопотребление будет, конечно, значительным, но только на очень короткое время. Создадим проект с нуля на основе демо-проекта Flex (RAIL) - Empty Example, содержащий необходимые начальные установки. Проект передатчика начнём с конфигурации радио в графическом конфигураторе, который очень напоминает WDS3. Вся конфигурация производится в таблицах, некоторые из которых показаны ниже. Синим цветом отмечены значения параметров, установленные пользователем, которые отличны от дефолтных. Мы будем использовать такие-же параметры радио-тракта, как и в предыдущих статьях цикла (bitrate = 1.2 kbps, GFSK, deviation = 5.17 kHz).

Далее, сконфигурируем радио на отсылку пакетов переменной длины от 1 до 127 байт. Такую конфигурацию радио мы будем использовать во всех проектах этой статьи. Ниже показана структура пакета в EFR32.

Структура функции main() унифицирована в Studio для приложений всех типов – будь то Bluetooth, беспроводное, или просто микроконтроллерное приложение. Эта функция автоматически генерируется при создании проекта и менять её мы не будем. Как видно, функция одноразово вызывает сгенерированную инициализацию системных ресурсов в строке 60 и ресурсов, конфигурируемых пользователем (строка 61). Далее, в основном цикле строкой 64 вызываются всякие системные процессы (может даже их пустое множество) с последующей функцией (строка 65), реализующей всю логику работы устройства.

Таким образом, пользователю следует позаботиться лишь о реализации функций app_init() и app_process_action(), располагаемых в соответствующе названных файлах проекта. Рассмотрим их отдельно. В проекте передатчика следует начать с конфигурации FIFO. Главное при этом обеспечить необходимое выравнивание массива FIFO по адресам (строка 11), поскольку при несоблюдении этого условия работать ничего не будет.

В функции app_init() мы сначала получаем ссылку на PHY (в мульти-диапазонных проектах их может быть несколько), которая требуется для многих RAIL API, конфигурируем FIFO и параметры режима сна RAIL (строки 22 – 24). В следующих трёх строках конфигурируется генерация прерываний при нажатии кнопки на плате WSTK, при котором будет производиться отсылка пакета. При каждом запросе прерывания вызывается callback функция Button_ISR, которая у нас устанавливает флаг tx_requested.

Функция app_process_action(), вызываемая в цикле main() по нажатию кнопки, загружает передаваемый пакет в FIFO передатчика и переводит его из режима IDLE в режим передачи Tх (строки 20 – 21). По завершении передачи пакета и установки обработчиком прерываний RAIL флага packet_sent, устанавливается флаг sleep_enabled для погружения системы в глубокий сон до следующего нажатия кнопки.

Собственно погружение в сон производится в строках 46 или 51. До этого радио переводится в режим IDLE (строка 41), что можно сконфигурировать и на аппаратном уровне, и в строке 44 определяется может-ли RAIL поместить всю систему в глубокий сон, после пробуждения из которого выполняется код в строке 48. Цикл в строке 42 нужен для завершения работы printf до входа МК в сон, при котором тактирование UART прекращается. Это можно организовать гораздо более грамотно, используя таймер RAIL, и на аппаратном уровне, но для первого тестового проекта вполне приемлемо. Код, обслуживающий работу UART, генерируется автоматически установкой в проект компоненты Retarget STDIO и находится вне области кода пользователя.

Как видно из кода, всё достаточно прозрачно, я-бы сказал тривиально. В результате среднее токопотребление в режиме покоя получается около 2.5 мкА. Частые пики на графике ниже соответствуют работе DC-DC конвертера, а широкий пик – моменту передачи пакета.

Обратимся теперь к проекту приёмника, который также создадим из базового проекта Flex (RAIL) - Empty Example. Прежде всего следует сконфигурировать радио-тракт модуля также, как в проекте передатчика. Поскольку модуль будет работать только на приём, для него не нужно инициализировать Tx_FIFO. Однако, следует указать какие события RAIL будет посылать нашему приложению. Это можно сконфигурировать в графическом редакторе, открыв из slcp файла конфигурации проекта вкладку Platform → Radio → RAIL Utility Initialization. Однако, проще это сделать в коде, оставив из нескольких десятков событий лишь те, которые нам нужны для приложения (строки 11–12 в файле app_init.c). После этого строкой 13 модуль переводится в режим приёма.

Как только будет принят пакет, стеком RAIL генерируется событие, в обработчике которого в случае успешного приёма мы путём вызова функции RAIL_HoldRxPacket() (файл app_process.c) временно сохраняем принятый пакет в системной области RAIL. Обработчик прерываний следует сделать как можно более коротким, по возможности лишь ограничиться установкой какого-либо флага без чтения пакета и его разбора. В нашем случае это флаги packet_received и rail_error.

Копирование принятого пакета из системной области RAIL и его анализ (в нашем случае просто выдача его содержимого на терминал) производится в теле функции app_process_action(). Для этого сначала получаем указатель на проект (строка 30) и сопутствующие пакету метаданные в переменной packet_info, и после копирования пакета в массив rx_buffer (строка 34) предлагаем стеку аннулировать его копию в системной области (строка 36). После печати пакета возвращаем радио в режим приёма, что можно сделать автоматически, см. ниже.

Отмечу, что для работы МК в режиме приёма необходима работа тактирующего генератора. Поэтому, лучшее что мы сейчас можем сделать в плане ограничения токопотребления, это перевести МК в режим сна EM1 (строка 45). На этом этапе потребление приёмника будет порядка 9 мА и практически постоянным, но позже мы покажем, как с этим бороться.

В окне терминала после приёма каждого пакета появится его содержимое, а также уровень принятого сигнала в dBm.

 

Передача данных с автоматическим подтверждением приёма

Здесь мы приведём лишь отличия в коде от предыдущего проекта. Понятно, что на стороне передатчика после отсылки пакета следует перейти в режим приёма и ожидать подтверждения в течение какого-то времени. По приёму пакета следует проанализировать его содержимое, и согласиться с подтверждением или рапортовать об ошибке. Замечательно, что все временные интервалы можно установить, заполнив всего 2 структуры и передав их в соответствующие RAIL API в функции app_init(). В первой из них таймеру событий RAIL указываются задержки перехода в соответствующие состояния в микросекундах. Во второй – время ожидания подтверждения и переходы из состояния передачи в случае отсутствия ошибок и при их наличии. Если значение поля enable второй структуры установить false, то после передачи пакета не будет производиться ожидание подтверждения. Это удобно при необходимости получения лишь одного подтверждения после передачи группы пакетов. Разрешение таймера RAIL равно 1 мкс.

К коду предыдущего пакета в файле app_process.c следует добавить обработку события приёма пакета, аналогичное проекту приёмника (строки 100–108), а также установку флага таймаута (строки 110-112). При приёме пакета подтверждения в функции app_process_action() мы просто выдаём на терминал его содержимое (или рапортуем о таймауте). Соответствующий код также полностью аналогичен проекту приёмника выше, и здесь не приводится.

На стороне приёмника помимо конфигурации таймера RAIL двумя структурами, как описано выше, следует определить содержимое пакета подтверждения приёма. В нашем примере оно статическое, но может быть и динамическим в зависимости от принятого пакета. Первый байт в массиве ackData как обычно указывает длину пакета.

Код в файле app_process.c остаётся без изменений, поскольку передача подтверждения будет производиться полностью автоматически. На графике ниже всплески потребления соответствуют моментам передачи подтверждений приёмником (верхний граф) и пакетов передатчиком (нижний граф).

 

Минимизация токопотребления приёмника

Для снижения токопотребления в режиме приёма радиотракту не следует находиться в режиме RX постоянно. Если его периодически включать лишь на короткое время приёма байтов преамбулы (последовательность 1010…, передаваемая в начале каждого пакета и служащая для синхронизации приёмника и передатчика) и выключать до окончания периода если приём не состоялся, токопотребление можно существенно уменьшить. Для надёжного приёма преамбулы следует находиться в режиме RX несколько дольше времени передачи преамбулы на установленной скорости передачи (bitrate), что определяется параметром PREAMBLE_OVERSAMPLING, который в нашем случае принят равным 10. Таким образом, при скорости передачи 1.2 Kbps минимальное время приёма преамбулы получается около 33мс. Соответственно, время приёма выбрано 40мс, а период пробуждения приёмника – 1с.

Управление режимом приёмника осуществляется внутренним таймером RAIL, для конфигурации которого следует заполнить структуру с 4 параметрами:

Первый и последний параметры этой структуры определяют, соответственно, время пребывания радио-тракта в состоянии IDLE и RX в микросекундах. На стороне передатчика преамбулу следует передавать в течение времени равном сумме времён нахождения приёмника в режиме IDLE и (в худшем случае) удвоенному времени RX. В действительности дело обстоит чуточку сложнее. Именно, длина преамбулы в битах в конфигурации передатчика не должна превышать 216 и для достижения этого условия при выбранных параметрах передачи длительность периода IDLE может оказаться меньше значения, определённого в строке 8 кода выше. Окончательное значение временных параметров приёмника вычисляется функцией calculate_preamble_bit_length(), которая должна присутствовать в файле app_init.c в проектах приёмника и передатчика. Таким образом, уменьшение токопотребления приёмника при нашем подходе приводит к более продолжительному времени работы передатчика перед посылкой пакета за счёт передачи более длинной преамбулы. Осциллограмма ниже показывает снижение среднего потребления приёмника с 9.5мА до 357мкА. Высокие пики соответствуют режиму RX приёмника, их период равен 1 сек.

На осциллограмме ниже верхний график соответствует режиму RХ на одной из демо-плат, а нижний – режиму TX на другой демо-плате при передаче одного и того-же пакета. Из них следует, что передатчик честно посылает преамбулу постоянной длительности, а время нахождения приёмника в режиме RX зависит от момента времени посылки пакета передатчиком относительно начала приёмного цикла. В этом проекте в передатчикe использована платa BRD4257A на основе МК семейства FG14, а в приёмникe, как и раньше, – BRD4250A.

Программа приёмника в файле app_process.c разработана на основе конечного автомата. В режиме ожидания передачи производятся переходы между состояниями IDLE их RX_WAITING. При приёме пакета последовательность переходов, следующая: IDLE → PREAMBLE_RECEIVED → SYNC_RECEIVED → PACKET_RECEIVED → IDLE. Время нахождения в каждом из состояний контролируется таймером Rail путём вызова функций manage_xxxx_timer().

По истечению всех таймаутов генерируется прерывание и вызывается callback функция RAILCb_timer_expired(), в которой и запрограммированы все переходы из состояния в состояние.

На стороне передатчика все изменения по сравнению с первым проектом содержатся лишь в файле acc_init.c. Новые строки 40–41 кода вычисляют и устанавливают битовую длину преамбулы.

 

Устройство на печатной плате

Для проверки концепции был собран передатчик по следующей схеме. Разъём SV1 служит для программирования микроконтроллера и отладки. В качестве отладчика использован стандартный J-Link. Схема передатчика построена на основе схемы модуля BRD4250A. Основное отличие её в том, что использован МК в корпусе QFN32 вместо QFN48 и работоспособный только в суб-гигагерцовом диапазоне. Это, в частности, повлияло на выводы подключения часового кварца Q3. Во многих приложениях можно обойтись и без него, но не будем экономить на мелочах. В схеме использован стандартный балун Q1, производимый фирмой Johanson Technology. Все пассивные элементы в схеме типоразмера 0402 за исключением C18 (0805). Кварцевые резонаторы Q2 и Q3 имеют размер 2.0×1.6мм и 2.0×1.2мм и нагрузочную ёмкость 10 и 12.5pf, соответственно. Эти ёмкости интегрированы в корпус МК, и их величина может варьироваться в некоторых пределах программно. Дроссель DC/DC конвертера L6 типа LQH3NPN4R7MM0L с током насыщения 880мА. Питание производится от двух батареек типоразмера AAA. Передача тестового пакета производится по нажатии кнопки. Отмечу, что кнопка подключена к другому порту, чем на отладочной плате.

Схема собрана на самодельной 2-слойной печатной плате, изготовленной по технологии ЛУТ, нижняя сторона которой используется исключительно в качестве общей шины. Несколько неразведённых соединений выполнены проволочными перемычками. В качестве антенны использован отрезок одножильного провода длиной в ¼ длины волны. Правильнее было-бы поставить на плату SMA коннектор и использовать более эффективную антенну. Файл печатной платы для Eagle приложен в архиве.

Схема показала полную работоспособность после устранения проблемы, связанной с невыходом МК из режима глубокого сна EM2. Для этого следует удалить строку 759 в файле em_cmu.c проекта, которая вызывает функцию dcdcHsFixLnBlock(). Не знаю точно, с чем это связано, но виною того оказалась конфигурация DC/DC конвертера и полагаю, что причина кроется в ревизии чипа. Я использовал чип ревизии C, в то время как на отладочной плате установлен МК ревизии B, для которой эту строку кода удалять не следует. Измеренное токопотребление в режиме покоя оказалось в точности 2.5 мкА, что полностью соответствует вышеприведённой таблице характеристик.

Тест на дальность связи

Тест проводился на двух демо-платах расширения BRD4262A на основе МК семейства EFR32FG14 с TCХO в качестве задающего генератора частоты 915Мгц и при выходной мощности +19 dBm со штатными антеннами комплекта.

Плата передатчика была установлена на террасе дома на высоте порядка 2м над землёй, как и в предыдущих статьях цикла. Плата приёмника находилась в машине на уровне бокового окна водителя (со спущенным стеклом). Прямая видимость между приёмником и передатчиком отсутствовала, между ними находилось довольно много жилых домов и лесопарковая зона с высокими деревьями. Уровень RSSI в точке приёма варьировался вокруг -117 dBm при устойчивом приёме пакетов. Согласно Google Maps расстояние между платами оказалось 1.28 км. Далее я не пробовал, т.к. дальность сильно зависит от условий местности и приведённая цифра пределом не является.

Ради интереса я попробовал те-же коды приёмника и передатчика на платах BRD4257А, на которых вместо TCXO на 38.4Мгц установлен просто кварцевый кристалл. Без подстройки ёмкости нагрузочных конденсаторов кварцев внутри МК при той-же мощности передатчика, что и выше, не удалось достичь и половинной дальности связи. Отсюда делаем выводы: либо следует производить скрупулёзную подгонку частот генераторов приёмника и передатчика, либо заплатить немного дороже за TCXO. Однако, в первом случае не получим автоматическую термокомпенсацию частоты, а во втором – придётся смириться с дополнительным потреблением самого TCXO в районе пары миллиампер в активном режиме.

Как всегда, в одной статье невозможно описать все возможности библиотеки RAIL. Надеюсь, приведённых примеров будет достаточно для многих любительских проектов. Для более подробного ознакомления с возможностями RAIL рекомендую просмотреть запись обзорного вебинара [4], а также документы [5], [6], [7]. Следующая статья цикла будет посвящена стеку сетевых протоколов Connect, для которых библиотека RAIL служит базовым фундаментом.

Литература

1. Радиомодули для беспроводной передачи данных. Часть I.
2. Радиомодули для беспроводной передачи данных. Часть II.
3. Радиомодули для беспроводной передачи данных. Часть III.
4. Silicon Labs Tech Talk: Sub-GHz Proprietary and Connect Software Stack.
5. Silicon Labs Rail Tutorial Series.
6. Rail Fundamentals (UG103.13).
7. Rail API documentation.

 


Файлы:
Архив ZIP


Все вопросы в Форум.




Как вам эта статья?

Заработало ли это устройство у вас?

14 2 2