Zigbee на базе cc2530 от TI

dtvims
Site Admin
Сообщения: 134
Зарегистрирован: Пн авг 02, 2010 2:43 pm

Zigbee на базе cc2530 от TI

Сообщение dtvims » Вт сен 19, 2023 3:40 pm

Цель данного писания разобраться с данной темой максимально. Сделать полнофункциональный проект и научится делать другие. Со мной можно легко связаться многими способами, чтобы задать свой вопрос или дополнить или поругать, что я все не так понял (мой ник уникален в РУ нете).

Развитие систем умного дома, заставляет смотреть какие еще есть системы и устройства и становятся важным аспектом такие параметры как автомность и беспроводная передача данных, в чем определенно лидируют устройства zigbee.
Поиск, что сейчас из чипов доступно, привел меня к чипам от TI CC2530 и библиотеке Z-Stack 3.0, поэтому далее будем разговаривать о них. Можно было бы посмотреть еще куда-то, но пока разумных предложений от предлагателей не услышал. Найти, документацию по теме оказалось не так просто. Модули необходимые делает, например, E-BYTE, как и аналогичные модули ESP8266 или ESP32, с которыми довольно легко работать, потому я не разумно решил, что и тут будет аналогично. Но нет. Модуль модулем, а чип чипом. Документация у TI есть, но разобраться там... Не то чтобы нельзя, но не понятно как с этим работать. Описание функции "Условное действие" содержит в себе только "Условное действие делает условное действие", а зачем оно это делает, для чего совершенно и когда, совершенно не понятно. Вроде есть описание методов API, но как их использовать? Нельзя просто в произвольном месте выполнить метод инициализации, например, группы, т.к. сперва должен прийти некий запрос на ее создание, надо запомнить, что мы в группе и затем отправлять групповые данные. А тут просто сухой перечень функций. И вроде бы ну и ладно, мы что не можем их правильно использовать? Можем конечно, но дублирование нам зачем? Какое дублирование? Так ведь данное API уже все умеет делать и бОльшую часть функционала можно включить, просто добавив нужный #define. После включения нужный функционал заработает почти полностью. Почти? Да, почти. Интересно, что есть функционал полностью сам в себе, а есть тот, для которого надо добавить еще некоторые телодвижения. И вот в этих мелочах самая засада.
Обычно есть статьи, где уже кто-то разобрался и описал, но это опять не наш случай. Информация, конечно, есть, но ее очень мало.
Как в этом разобраться? Будем разбираться и я надеюсь, что у меня это получилось.

dtvims
Site Admin
Сообщения: 134
Зарегистрирован: Пн авг 02, 2010 2:43 pm

С чего начать?

Сообщение dtvims » Вт сен 19, 2023 4:03 pm

Есть проект PTVO, который позволяет сделать прошивку без навыков программирования. Это не для тру экспериментаторов, но если вы пришли сюда чтобы сделать zigbee датчик или релюшечку или кнопочку, то идите туда, а там есть все, что надо. Правда, если захочется много всего в одном, то придется добавить денюжку, чтобы активировать полную версию. Там нельзя будет докидать своей мега логики, а ведь очень хочется, потому наш путь самурая далее!

Начнем вот с этого проекта: https://habr.com/ru/companies/iobroker/articles/495926/
Автор решил переделать беспроводной выключатель/реле, добавив туда датчик температуры. Цель проекта явно не озвучена (а может и озвучина, а я не внимательно читал, но Вы прочитайте внимательно!), но у меня есть аналогичная цель. Вернее я ничего переделывать не хочу, но хочу получить аналогичное устройство, но с блэкджеком и куртизанками.
Итак: Прочитали статью по ссылке? Внимательно? НЕТ? А надо внимательно! Дело в том, что там много важных моментов. Конечно остаются вопросы, на которые я далее попробую ответить.

End Point - определяет устройство. Самое непонятное сперва, а зачем оно надо? У нас одно устройство и зачем несколько EP как несколько разных устройств? А все потому, что есть Кластеры! Кластер одного типа может быть только один на одно устройство. Т.о. если мы используем кластер температуры для одного датчика, то как добавить второй? В этот же кластер нельзя! Добавить новый такой тоже нельзя! Добавить еще одну EP можно и поместить туда второй датчик. А что такое атрибуты? это просто перечень параметров, собранных в кластер. Например, у датчика температуры есть атрибут в котором его значение будет, есть минимальное значение, максимальное и версия кластера. Зачем столько атрибутов? Надо обращаться в первоисточник стандарта zigbee, но мне лень.
Только ли датчиками и кнопками мы сыты?
Есть в стандарте куча моментов, про которые необходимо знать, чтобы понимать, какое устройство должно получить в итоге. Зачем реализовывать функционал, если он уже есть в стандарте и реализован за нас?
Touchlink - интересная тема, но как использовать не очень понятно и тем более, а надо ли вообще, но почему она есть в целом понятно. Механизм позволяет взаимодействовать двум устройств напрямую без координатора и образования сети. Устройства обмениваются сертами и живут сами между собой. Т.е. если мы не хотим заморачиваться с координатором, покупаем умную лампочку и выключатель, связываем их между собой по этой технологии и все! Выключатель теперь связан с лампочкой и будет ее вкл и выкл. Удобно? И да и нет. На мой взгляд, если так заморачиваться, то необходимо иметь более полный контроль с удаленным доступом и возможно с доп. автоматизацией, что не возможно без организации полноценной сети, а значит не вижу смысла рассматривать эту технологию. Ну, в смысле, я лично не хочу этим заморачиваться.
OTA - интересная технологи обновления прошивки по воздуху. Возможно далее мы к этому придем. Не сказать, что прям так нужно, т.к. устройства zigbee обычно довольно простые и просто обновлять там нечего, но опять же меня лично совсем простые устройства не интересуют, потому эта функция может оказаться актуальной.
Groups и scenes. Группы и сцены. Последнее, наверное как сценарии. Объединяем несколько устройств в группы и работаем со всем одновременно. Сцены что-то вроде аналогичного. Пока детально не разбирался, т.к. в текущую задачу не очень входит. Смысл сего, например, объединить несколько лампочек в группу и включать не по одной лампочке, а сразу группу. Не буду пока на этом останавливаться.
Binds - связывание (потом будет точнее). Под этим сперва мы видим связывание нашего устройства с координатором, но нет. Вернее да, но нет. Связывать с координатором необходимо устройство, чтобы оно вошло в сеть, но есть возможность связать устройство не только с координатором, но и с любым другим устройством. Что происходит обычно? Мы нажали кнопку, она оправила репорт по кластеру OnOff координатору, а он ... А он ничего. Если это устройство от какого либо производителя группы устройств, то он определяет дальнейшую логику, имеет на борту некую ОС, подключается через интернет к облаку, через которое мы можем задать правила, по которым этот координатор будет действовать. Или координатор - это наш свисток, включенный в комп, или распбери или еще в какой аналог компа, на котором есть ОС с сервисом умного дома, в котором мы настраиваем правила и согласно этим правилам даем команду координатору, что-то сделать. А что будет, если координатор отключится? А ничего не будет, от слова совсем... Не будет никакой дальнейшей логики, а иногда надо. Например, у меня на системе работает приложение Термостат. Термостат получает данные от датчика температуры и дает команду на реле включить или выключить обогреватель. Если не будет координатора, то кто будет руководить этим процессом? Никто, процесс остановится в том состоянии, которое было последним. Если вы дома, то все ок, а если нет, то кто выключит обогрев, если он остался включен? Правильно - никто. И тут нам приходит на помощь Связывание! Мы можем напрямую, поверх организованной сети, связать 2 устройства, т.о. команда на включение будет отправляться не только на адрес координатора, но и на адрес самого конечного управляемого устройства. Нам не надо чтобы ОС умного дома включала устройство, если оно может включиться само, а координатор тут нужен только чтобы сообщить ОС как там все работает, и если захотим, вмешаться в процесс. Кто-то заметит, что это все можно реализовать в одном устройстве и не париться! Правильно, что я и собираюсь сделать в итоге, но сама тема мне показалась очень интересной, потому продолжим! Связать между собой можно только однотипные кластера, т.е. OnOff только с OnOff. Получается, что включить реле просто датчик температуры не сможет, а вот устройство термостат уже сможет, потому как в нем есть и кластер термостата и кластер OnOff и кластер температуры, хотя реле он может в себе не содержать. Мы можем такой термостат повесить на стенке, а реле будет на обогревателе. Конечно, если само реле будет иметь в себе все что необходимо, то сможет работать вообще автономно, даже без сети, но ведь сама возможность... Я уже молчу, что измерять температуру надо не на обогревателе, а в комнате.

dtvims
Site Admin
Сообщения: 134
Зарегистрирован: Пн авг 02, 2010 2:43 pm

Что будем делать?

Сообщение dtvims » Вт сен 19, 2023 4:10 pm

Что лично я для себя вижу в конечном устройстве? Несколько реле. Зачем? Ну, пока это проба, я могу на одном устройстве сразу и свет включать и обогреватель. Датчик(и) температуры. Зачем их много? Ну, один может быть в одной комнате, другой в другой. Разные датчики в разных комнатах, конечно лучше делать без проводов, но если есть физическая возможность оставить провод, то можно оставить провод :).

Вообще, что-то из описанного выше можно реализовать иначе и нам в пример идет проект https://github.com/formtapez/ZigUP. И вроде бы да, но снова нет... не надо так делать, но если очень хочется, то можно :) Что не так? В проекте ZigUP реализованы несколько реле и датчиков, но для всех были заведены собственные Кластеры. А что так можно? Ну да! Стандарт не запрещает. Есть огромный диапазон значений для идентификации пользовательских кластеров, которые можно идентифицировать по аналогии с существующими в стандарте. Главный недостаток, что координатор должен уметь понимать эти кластера. Для личной автоматизации это может сгодиться или для автоматизации внутри одного производителя. А вот универсальность уже страдает, т.к. мы выходим за рамки стандарта (хотя ведь стандарт это позволяет... Ну в общем). Все сказанное не в обиду автору ZigUP, проект хороший!
Проект ZigUP тоже интересен для общего образования, но он закрывает некоторую локальную цель, и стоит его рассматривать на предмет как сделать быстро, что надо чтобы работало и сойдет. Я же не хочу отходить от стандарта. Например, в Home Assistant недавно была добавлена интеграция zigbee (не путать с плагином zigbee2mqtt), которая сразу видит стандартные кластеры устройств и определяет, их предназначения, все за рамками стандарта будет вызывать проблемы. Конкретно в интеграции HA пока не очень понятно как работать с кастомными нестандартизированными устройствами. В zigbee2mqtt есть возможность описать любое устройство в понятный вид, но эта задача может оказаться также довольно сложной. Вот мы и делаем выбор между "оно само" и "ща мы тут допилим".

Я считаю очень хорошим проектом для обучения https://github.com/grafalex82/hellozigbee. Автор проделал огромную исследовательскую работу, но для чипов NXP. Тут у всего свое начало. В проекте diyruz_rt цель была модернизировать готовое устройство на cc2530, а проект hellozigbee для модернизации устройств от xiaomi, что используют чипы NXP. Общее в этих проектах - это zigbee. Zigbee - это стандарт и значит, если что-то должно быть по стандарту, то для всех оно будет одинаково работать, разве что API отличается. Из того что я понял при изучении проекта hellozigbee, что API от TI проще (хотя многие утверждают обратное), а документации у всех не очень подробная. Доки из hellozigbee рекомендую к обязательному прочтению! Полезно. Жалко статьи на хабре удалили, но интернет их помнит, можно найти их копии, но и в Гите есть почти тоже самое (переводчик в помощь, тем более, что браузер это может сделать одной кнопкой).

Еще мне попался вот такой ресурс www.kancloud.cn/aiot/zigbee. Если получится скачать материалы, то добавлю вложение или ссылку на простое скачивание. Опять перевод в браузере очень выручает. Неплохой набор статей.

dtvims
Site Admin
Сообщения: 134
Зарегистрирован: Пн авг 02, 2010 2:43 pm

Начнем?

Сообщение dtvims » Вт сен 19, 2023 4:29 pm

Сперва возьмем проект diyruz_rt. Надо для него обзавестись всем необходимым.
Usb zigbee Dongle - свисток координатор. Донгл можно использовать и как снифер, но я его подключил к Home Assistant (далее просто HA). В HA правда оказалось есть нюансы. Есть интеграции zigbee, но там не все можно, а может и все, но мы не знаем как, а если бы знали, но не знаем. Есть плагин zigbee2mqtt собственно и плагин mqtt сервера, но чтобы плагины можно было подключать через специальный для того раздел, нужна версия HA со встроенным супервизардом, т.е. версия supervised. Нужную версию можно установить только на Debian, на распбери как самостоятельную ОС или как виртуалку, где тоже будет самостоятельная ОС (если правильно понимаю, то самостоятельная ОС - это Дебиан только купированный, чтобы там оставить только самое необходимое).
Отладочная плата с программатором, см. инструкции по diyruz_rt (https://habr.com/ru/companies/iobroker/articles/495926/), там есть картинки, купить можно алиэкспрес или уже на агрегаторах типа Озона попадаются нужные устройства, правда по цене несколько выше.
Z-Stack 3.0 - качаем данное API с сайта TI или откуда еще, если неохото мучаться :)
Устанавливаем IAR 8051. Если версия будет последней, то придется немного поплясать с бубном, ну совсем чуток, так что не страшно, все будет работать. Да система платная, но все решается.
В папке, где Z-Stack ищем папку проектов и там же в эту папку, рядом с другими проектами кладем проект diyruz_rt. Структура папок должна быть аналогичной, чтобы пути подтянулись и не пришлось много менять в настройках.
Открываем IAR и из него открываем проект из папки DIYRuZRT/CC2530DB/. Он предложит обновить версию проекта, что ни к чему особо не обязывает, потому пускай.
Если версия новая, то придется еще найти файл $PROJ_DIR$\..\..\..\Tools\CC2530DB\f8w2530.xcl (ну это все там же где Ваш проект, куда мы Z-Stack распаковали) и в конец надо добавить строчки:

Код: Выделить всё

//
//  Device specific symbol definitions
//  ==================================
-D?B=F0                       // B register location
-D?IE=A8                      // Interrupt Enable register location
-D?IP=A9                      // Interrupt Priority register location


Вот... просто если этого не сделать, то будет ошибка типа "Undefined external "?B" referred in BindingTable" и другие.

Слева у вас список файлов проекта, а над ними выпадающий список из 3-х пунктов: CoordinatorEB, RouterEB и EndDeviceEB. Возможно будет еще RouterZLight - не знаю, что он там делает :).
Так вот это сгруппированные настройки компилятора и линкера нацеленные на определенный вид устройств. Координатор у нас есть и еще один нам не нужен. Конечное устройство - это обычно устройство на батарейках, которое бОльшую часть своей жизни спит, чтобы не тратить энергию, т.е. какой-нибудь датчик. Датчик он что? Он просыпается иногда, отправляет показания и дальше спать. Что еще от него надо? А ничего. По наблюдениям за датчиком от xiaomi, да и sonoff вроде также работает, он просыпает, получает данные от датчика и если они изменились, то только тогда он их передает координатору. Разумно? Зачем тратить энергию на обновление данных, если они не менялись. Мне не очень нравится этот подход, т.к. графики становятся не красивыми и не точными, зато батарейка экономится. А для выключателей, где есть реле, обычно не требуется экономить энергию. Да и сами реле могут требовать постоянного запита, потому такие устройства могут быть постоянно в работе, т.е. в сети, а значит делать дополнительную полезную функцию как в колхозе! Наше устройство может быть роутером. Автор diyruz_rt задается вопросом, работает ли его прошивка как роутер, вроде подключения принимает, а далее все... Судя по всему, если выбрать конфигурацию RouterEB, то работает и ничего дополнительно делать не надо. У меня устройство подключенное через него вполне передавало данные координатору, делаем вывод, что уже все работает.
Выбираем пункт RouterEB, далее я буду говорить только про него, если кому нужны другие виды, то в них необходимо проделать те же действия. Выбираем свойства проекта, идем в настройки линкера, там видим предопределенные #define`ы, которые мы убираем и в поле выше, надо прописать файлик Source/preinclude.h с полным или относительным путем. Автор именно туда перенес все дефайны, ну и мы их будем откидывать туда.
Пробуем компилировать проект. Если сделать полный ребилд, то будут попытки откомпилировать все версии проекта, а если мы их не настраивали, то будет куча ошибок. Будут созданы соответствующие папки, куда будут помещены откомпилированные сущности. Нас интересует только RouterEB.
Совсем забыл!!! https://habr.com/ru/companies/iobroker/articles/495926/ - тут описаны еще несколько настроек компилятора, и если вы их не сделали, то плохо читали. В общем идите и читайте заного.
Получили мы наконец файлик с расширением .hex. Вот наша прошивочка и мы будем ее тестить.
Нам теперь нужен прошивальщик (прога): SmartRF Flash programmer v1. Именно первой версии. Можно, конечно, и взять вторую версию, но она не увидит cc2530, а потому не понимаю, зачем он вам сейчас :)
Если вы правильно соединили отладочную плату и программатор, а также подключили все это к компу, то SmartRF увидит наше устройство, хотя называться он будет не как сс2530, но увидит в общем. Выбираем нашу прошивку .hex и нажимаем кнопочку в самом низу, такую большую длинненькую. Там поскачут всякие полосочки, заморгают надписи, а в итоге получим что-то типа success. Поздравляю, мы закончили начало.
Если у Вас тоже HA или zigbee2mqtt, то открываем последнюю, разрешаем спаринги, держим кнопочку на плате долго (только не надо жать на reset и говорить, что не работает), пока не загорится светодиодик. zigbee2mqtt сообщит, что с ним кто-то спарился и определит его как проект diyruz_rt. Да его туда внесли официально. И можно понажимать кнопочки, как в HA, так и на плате и смотреть как положение выключателя меняется и там и там. Если вы еще и датчик температуры подключите, то у вас будет и температура отображаться. У меня ds18b20 под рукой не нашлось, зато есть DHT22, где температура и влажность. Далее продолжим модернизацию и заменим один датчик на другой, добавим влажность и многое другое...

dtvims
Site Admin
Сообщения: 134
Зарегистрирован: Пн авг 02, 2010 2:43 pm

Подключаем UART и printf к cc2530

Сообщение dtvims » Ср сен 20, 2023 9:25 pm

Я думаю, что в данном случае это будет простое упражнение.
Вообще в API уже все есть.
В preinclude добавим:

Код: Выделить всё

#define HAL_UART TRUE
//#define HAL_UART_ISR 1
#define HAL_UART_DMA 1


Тут просто разрешаем/активируем работу UART, для чего будут инициализированы в соответствующее состояние соответствующие регистры.
Также активируем режим DMA. На самом деле, конечно, это все делается в библиотеке hal_uart, но данные директивы это разрешают :)
DMA тут нам помогает, в том, чтобы меньше тратить время CPU на перекладку данных в UART. Это правда в теории, т.к. DMA помогает в больших объемах данных. А что там у нас? Ну что-то есть.
Есть еще вариант ISR, что работает на основе прерываний, но этот механизм уже вешается на CPU. Правда это относится только в приему данных, в то время как DMA может данные перекладывать за нас в обе стороны. Но это в теории. Опять так? Надо просто копаться как это в реальности реализовано, а мне лень. Работает: и так, и так. Мне нравится DMA. Там борту 2 UART`а, потому на оба нельзя будет использовать DMA (скорее всего, а может и можно, кто знает расскажите всем), но можно использовать для одного DMA, а для другого ISR. В общем HAL_UART_ISR я оставил, чтобы помнить, что оно там есть.

в основном файле добавим:

Код: Выделить всё


...

#include "hal_uart.h"
#include <stdio.h>

...

void initUart0(halUARTCBack_t pf);
void uart0RxCb( uint8 port, uint8 event );

...

__near_func int putchar(int c)
{
  HalUARTWrite( HAL_UART_PORT_0, (uint8 *)&c, 1);
  return(c);
}

void initUart0(halUARTCBack_t pf)
{
  halUARTCfg_t uartConfig;
  uartConfig.configured           = TRUE;
  uartConfig.baudRate             = HAL_UART_BR_115200;
  uartConfig.flowControl          = FALSE;
  uartConfig.flowControlThreshold = 48;
  uartConfig.rx.maxBufSize        = 128;
  uartConfig.tx.maxBufSize        = 128;
  uartConfig.idleTimeout          = 6;
  uartConfig.intEnable            = TRUE;           
  uartConfig.callBackFunc         = pf;
  HalUARTOpen (HAL_UART_PORT_0, &uartConfig);
}

void uart0RxCb( uint8 port, uint8 event )
{
  uint8  ch;
  while (Hal_UART_RxBufLen(port))
  {
    // Read one byte from UART to ch
    HalUARTRead (port, &ch, 1);
  }
}


"..." - надеюсь, что все понимают, что на этом месте просто какой-то другой код? Просто все ставится в разные уголки и не хочется на этом слишком заострять внимание. Все будет в готовом проекте, где-нибудь в конце, если, конечно он заработает как надо :) Да ладно, данные куски уже работают :).

Тут объявим 2 функции initUart0 и uart0RxCb - они необходимы как пользовательская инициализация порта. Вообще объявлять их правильно будет в файле ".h", но я человек не правильный и считаю, что там они не нужны никому, пусть будут в основном файле.

Если мы хотим использовать printf, то необходимо создать и вот такую функцию: putchar. Собственно она тянется в stdio.h, в которой и определяется работа printf.
Функция HalUARTWrite записывает в буфер на отправку массив данных для указанного UART порта. Тут используется отправка одного байта. Честно говоря не очень понимаю, зачем в putchar используется тип int, если речь идет только об одном байте. Возможно это тянется из 8-ми биток, но для этого есть однозначный тип uint8. В общем ...
Сделали и прием и отправку данных. Я буду только отправлять, потому про прием данных тут пока ничего не будет.

А в функцию zclDIYRuZRT_Init того же файла добавим:

Код: Выделить всё

  HalUARTInit();
  initUart0(uart0RxCb);
  printf("UART0 Init Done\r\n");


Тут инициализируем HAL, инициализируем порт на нужных нам скоростях и тестируем printf. После заливки прошивки в МК, подключаемс я к COM порту, на котором висит наша отладочная плата (не отладчик) и видим, что он нас приветствует при старте или рестарте фразой "UART0 Init Done".
Я наставил еще принтов на разные события, чтобы понимать что происходит и когда. Не рекомендую просто ставить в loop, т.к. он будет принтовать не просто все события, а даже их отсутствие, потому лучше принтовать только что-то более конкретное, т.е. именно когда есть события. Хотя это право каждого, где и зачем ставить принты.


Вернуться в «Микроконтроллеры и автоматизация»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 24 гостя