Введение
Итак, приступим. Сразу хочу рассказать о двух русскоязычных площадках на которых мы с коллегами уже активно обсуждаем эти чипы. Вот первая, а здесь вторая площадка, которую я и создал :-) Как я обещал, выражаю большую благодарность участнику sed_alex с форума easyelectronics.ru за первоначальную помощь в освоении этого чипа. В этой статье я постараюсь систематизировать наработанные данные и, по возможности, не дублировать материал из форумов. Для ознакомления с семейством, я приобрел на Алиэкспрессе отладочную плату и программатор. Здесь я указал много ссылок, которые помогут вам в выборе. Да вы и сами найдете много интересного на АлиЭкспрессе по запросу СH582. Лично я купил вот эти изделия. На отладочной плате, по центру, есть отдельные отверстия под программатор и UART1, который используется при отладке.
Затем я скачал SDK с примерами со страницы производителя на GitHub а после занялся установкой среды разработки MounRiver Studio. Так как я работаю на платформе Windows, я её и выбрал. На текущий момент можно скачать файл MounRiver_Studio_Setup_V185.zip. Обновления среды появляются регулярно. Среда построена на основе Eclipse, поэтому всё достаточно привычно. Вот как она выглядит
Чтобы загрузить в среду проект надо сделать всего несколько шагов. Выбрать пункт меню File->Import, затем выбрать тип проекта и путь к нужной папке. Нажимаем Finish и новый проект добавляется слева в окне Project Explorer.
Теперь научимся загружать проект в чип под отладчиком. Для этого выбираем пункт меню Run ->Debug Configurations и два раза слева в окне нажимаем на поле GDB OpenOCD MRS Debugging. Слева появится новое поле с названием проекта, а справа - его настройки.
Иногда окошко С/С++ Application оказывается пустым. Тогда нужно, используя кнопку Browse, найти и выбрать *elf файл своего проекта. Получится что то похожее, как на картинке. Затем открываем закладку SVD Patch и указываем путь до .svd файла нашего микроконтроллера. Без этого отладка работать не будет. Если вы устанавливали MounRiver Studio по умолчанию тогда и путь у вас окажется таким же самым как на картинке: C:\MounRiver\MounRiver_Studio\template\wizard\WCH\RISC-V\CH58X\NoneOS\CH58Xxx.svd
Если теперь нажать кнопки Apply а затем Debug, в контроллер начнет прошиваться hex файл вашего проекта. У меня на программаторе начинает мигать синий светодиод. Если этого не происходит. Во-первых проверьте, что проект был предварительно откомпилирован и собран. Во-вторых убедитесь, что на контроллере включен Debug режим. С завода он идет отключенным. Для включения, надо выбрать пункт меню Tools->WCH In-System Programmer. Появится следующее окно программатора.
Теперь, при отключенном питании, на отладочной плате зажмите кнопку BOOT и подключите её через USB Data кабель к компьютеру. В окне Download Record должна появиться запись о том, что устройство найдено, так как на картинке. Из этого окна мы можем программировать микроконтроллеры напрямую через USB порт. Так же отсюда мы можем включить Debug порт на контроллере. Для этого нажмите синюю кнопку En-Simulat. На предупреждающем транспаранте нажмите кнопочку "Да". После этого в окошке Download Record появится надпись: "Succ to Enable Debug Interface!" Всё, вы подключили Debug режим. Теперь снова попытайтесь загрузить ваш *.hex в микроконтроллер. Должно всё получится и секунд через 30 через вы увидите такую картинку. Время от времени у меня на контроллере режим Debug отваливается, поэтому иногда приходится повторять эту процедуру.
Режим Peripheral
Изучение этого режима я бы начал с WCH\ch583-main\EVT\EXAM\BLE\Peripheral. Все проекты построены сходным образом, поэтому разобравшись с ним, вы легко поймете остальные. В папке APP находятся основные файлы проекта. Файл peripheral_main.с служит для запуска приложения. В нем желательно ничего не менять. Другой файл peripheral.с содержит основную логику проекта, который мы можем модифицировать. Кроме того, есть ещё папка Profile, в которой лежат файлы различных профилей. В нашем проекте находятся файлы devinfoservice.с и gattprofile.с в которых реализованы соответствующие сервисы. В начале каждого из этих файлов находится таблица Profile Attributes. В ней конфигурируются атрибуты данных профилей. Проще говоря, мы задаем элементы таблицы атрибутов, которую мы рассматривали в статьях ATTы GATTы... и ATTы GATTы Продолжение. Разобравшись с этой таблицей, вы поймете как вообще работает GATT механизм. Это будет не совсем просто, но без этого далеко не уехать. В своей предыдущей статья я подробно касался вопроса таблицы атрибутов. В эфире прошивка выглядит следующим образом.
Профили devinfoservice и gattprofile содержат по несколько характеристик. Я не буду подробно их описывать. Это проще и нагляднее сделать самим, используя программу nRF Connect. Если вы хотите создавать свои собственные проекты, вам будет необходимо от чего то отталкиваться. Данные сервисы очень хорошо подходят для этой цели.
Режим OTA
У всех современных BLE контроллеров есть режим OTA - «Over-The-Air», то есть обновление по воздуху. Имеется он так же у WCH. Более того, фирма представила даже целых два способа обновления для контроллеров с разным объемом памяти. Рассмотрим их.
OnlyUpdateApp
Этот способ используется для контроллеров с малым объемом внутреннего FLASH. Это CH581F с памятью в 192 кБайтов. Вся память делится на 4 части. В первой располагается вектор перехода (JumpIAP) на бутлоадер IAP. Во второй части (Peripheral) располагается приложение пользователя, которое и надо обновлять. В третьей части памяти находится сам бутлоадер IAP (In-Application Programming). Ну и наконец, в последней части находится библиотека стека BLE.
При подаче питания на контроллер, управление передается по нулевому адресу программы, где лежит команда (JumpIAP) перехода на IAP. После этого перехода, внутри IAP анализируется нужно производить обновление или нет. Если обновление не нужно, тогда управление передается в сегмент Peripheral и дальше исполняется программа пользователя. Если же обновлять прошивку нужно, управление остается в сегменте IAP и используя стек BLE из части LIB, контроллер обновляет прошивку пользователя в сегменте Peripheral. Во время обновления, функции самой прошивки Peripheral не доступны.
Для создания обобщенной прошивки, используются 3 отдельных проекта из папки WCH\ch583-main\EVT\EXAM\BLE с общим названием OnlyUpdateApp. Четвертым файлом является файл стека CH58xBLE_ROM. Объединяются 4 HEX файла при помощи приложения AssemblingFileTool, находящегося в папке WCH\ch583-main\Android Tool. На андроиде, для обновления прошивки «по-воздуху», используется приложение CH583 OTA Tool, находящегося в WCH\ch583-main\Android Tool\OTA Tool. По адресу WCH\ch583-main\Android Tool лежат pdf документы с описанием режима OTA. Они на китайском, но по картинкам и с помощью переводчика вполне можно понять что и как делать. Выглядит приложение так.
BackupUpgrade
Для процессоров с большим объемом памяти, таким как CH582/583, используется другой способ обновления. В этом, втором способе, обновляется не только приложение пользователя, но также сама BLE библиотека. Кроме того, при этом способе сохраняется работоспособность пользовательского кода. Здесь FLASH память так же делится на 4 части. В первой (JumpIAP) так же лежит команда перехода на IAP. Во второй части лежат приложение пользователя и библиотека BLE. Третья часть памяти остается пустой. Сюда будет записываться новая прошивка. Ну и в последней части памяти находится сам IAP.
При подаче питания на контроллер, также как и в первом случае, управление передается по нулевому адресу программы, где лежит команда (JumpIAP) перехода на IAP. Далее бутлоадер IAP анализирует надо ли ему включаться в работу или нет. Если нет, тогда управление передается приложению пользователя. Одной из задач этого приложения является заполнение пустого пространства FLASH памяти новой прошивкой. Если загрузка новой прошивки прошла успешно, выставляется флаг события и подается команда перезагрузки. В этом случае IAP копирует новое приложение пользователя и BLE библиотеку из третьего в второй сегмент FLASH памяти, снимает флаг события и перезагружает процессор.
Немного забегая вперед, хочу уточнить один момент. Основная прошивка с которой мы работаем ( BackupUpgrade_OTA ), по-умолчанию размещается в памяти микроконтроллера по адресу 0х00001000. Это нужно для работы режима OTA, но для тестирования это крайне неудобно. На этапе отладки нужно перенести её по нулевому адресу. Делается это в файле линкера Link.ld. После изменений надо пересобрать весь проект заново, нажав сверху кнопку с двумя стрелками Rebuild (Shift +F7). После всех доработок, верните всё обратно, иначе обобщенную прошивку для обновления "по воздуху" собрать не получится.
Для создания обобщенной прошивки, используются 3 отдельных проекта из папки WCH\ch583-main\EVT\EXAM\BLE с общим названием BackupUpgrade. Объединяются 3 HEX файла при помощи того же приложения AssemblingFileTool. Для обновления прошивки «по-воздуху», используется приложение CH583 OTA Tool, как и в первом случае. Для меня интересен второй способ обновления, который позволяет не терять связь с функциями прошивки пользователя. Рассмотрим команды, которые в нем применяются.
Команды bootloader-a
При работе со стеком, обновление прошивки происходит также как и при любой другой задаче, через команды стека. Мы не можем напрямую прочитать или записать участок FLASH памяти напрямую. Для этого применяются 5 команд. Рассмотрим их.
IAP_INFO – команда запроса конфигурации устройства, где 0х84 – ID команды, 0х12 – длина посылки после текущего байта. Вот как выглядит полная команда. 84 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 В ответ контроллер отправляет посылку со своей конфигурацией. Например такую: 02 00 60 03 00 00 10 83 00 44 00 20 B8 44 00 20 34 0B 00 20 0х02-второй вариант обновления (с BLE стеком), 0х00036000 = 216к размер памяти под новую прошивку, 0х1000 – размер сегмента памяти, 0х0083 – процессор ch583
IAP_ERASE – команда стеку на стирание сегментов памяти, где 0х81 – ID команды, 0х1000 – начальный адрес сегментов, 0х0025=37 сегментов памяти надо стереть. 81 00 00 01 25 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 В ответ стек отправляет нулевой байт, в случае успеха или ненулевой байт ошибки.
IAP_PROM – команда записи данных во FLASH. Она состоит из заголовка и данных. 0х80 – ID команды, 0хF0 = 240 длина блока данных, 0х1000 – адрес блока памяти. 80 F0 00 01 После этой команды передается блок данных длиной 240 байт.
IAP_VERIFY – команда верификации. Она очень похожа на команду IAP_PROM, отличается только ID заголовком, который равен 0х82.
IAP_END – команда успешного окончания заливки новой прошивки. Вот она: 83 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Она похожа на команду IAP_INFO. После её получения выставляется флаг новой прошивки и дается команда перезагрузки процессора.
Со стороны андроида, при обновление прошивки "по воздуху", мы наблюдаем как сначала программа прошивается в контроллер, затем верифицируется и только после этого мы получаем надпись update success! На этом обновление прошивки закончено.
Режим Central
Среди примеров использования контроллера в BLE режиме, есть такие, когда чип будет играть роль центрального устройства. Т.е. будет работать как телефон сканируя эфир и присоединяя к себе периферийные устройства. Самым простым примером является проект Central. При сканировании, программа заполняет внутренний буфер из 10 ячеек МАС адресами найденных устройств. Потом ищет среди них устройство с заданным адресом. Если такое устройство нашлось, контроллер присоединяет к себе периферическое устройство и начинает запрашивать у него сервисы, характеристики и дескрипторы.
По умолчанию он ищет такие атрибуты: сервис Simple Profile Service UUID = 0xFFE0, а среди характеристик Key Pressed UUID = 0xFFE1, и затем уже CCCD = 0x2902. Это очень удачный пример. Дело в том, что у антипотеряшки iTag, которую я упоминал в прошлой статье, имеются сервисы и характеристики с такими номерами. Вот они в программе nRF Connect.
Поэтому, если мы попытаемся присоединить к контроллеру iTag, мы, увидим следующее сообщение в логе. Конечно для этого надо подключить преобразователь к нашей платке и открыть терминальную программу на компьютере.
Connected...
Found Profile Service handle : 10 ~ 26
Found Characteristic 1 handle : 12
Found client characteristic configuration handle : 13
Мы видим, что все три атрибута найдены. И тут в пору кричать "Ура!!!", но как говорит один мой хороший знакомый - "Да, но нет" :-) Дело в том, что функция запроса атрибутов в стеке WCH сделана откровенно плохо. Возможно я в чем то не разобрался, но у меня она ведет себя не предсказуемо. Может на каких то устройствах выдать всё что положено, а на других не показывает ничего. Тут надо уточнить, что в стеке имеется целый набор команд для устройства Central. Мы можем запрашивать периферийное устройство на наличие у него конкретного сервиса или характеристики (по номеру UUID), так и запрашивать все сервисы или характеристики из диапазона адресов. В приведенном выше примере запрашиваются конкретные UUID атрибутов. Из ответа видно, что сервис занимает диапазон адресов от 0х0010 до 0х0026, а характеристика имеет адрес 0х0012. Следом за ней с адресом 0х0013 идет дескриптор. Именно по этим адресам мы будем обращаться, когда захотим что то прочитать или записать в периферийное устройство. Сервисы запрашиваются так:
GATT_DiscAllPrimaryServices() обнаружение всех сервисов устройства GATT_DiscPrimaryServiceByUUID() обнаружение конкретного сервиса по UUID
Если же мы теперь запросим у устройства iTag все сервисы, то получим следующее:
Connected...
Found Profile Service handle : 1 ~ 4
Found Profile Service handle : c ~ f
Found Profile Service handle : 2d ~ ffff
Found Profile Service handle : 206f ~ 7c0
Что смущает в ответе. Во-первых, всегда в списке сервисов, в самом конце, присутствует невалидный сервис. У нас он имеет диапазон адресов 206f ~ 7c0. Я так и не понял что это. Во-вторых, кроме него, найдено всего три сервиса. А на рисунке 14, в центре, мы видим что имеется целых 6 сервисов. Кроме того, если запросить наличие характеристик из всего диапазона адресов, стек не выдаст нам вообще ничего. И это совсем не понятно. Команды для запросов характеристик следующие:
GATT_DiscAllChars() обнаружение всех характеристик из диапазона GATT_DiscCharsByUUID() обнаружение характеристик по UUID
Но есть и хорошие новости. Если вам известны адреса характеристик, то при обращении к ним стек отрабатывает чтение или запись вполне стабильно. В моем случае устройство с функцией Central, ищет в эфире другое моё устройство с функцией Peripheral. Ну а так как я на периферическом устройстве сам формирую таблицу атрибутов, то адреса всех характеристик мне известны. Команды для чтения и записи характеристик следующие:
GATT_ReadCharValue() чтение значения характеристики по указателю GATT_WriteCharValue() запись значения характеристики по указателю
Ну и напоследок несколько строк о флагах стека. При любом изменении своего состояния стек генерируется событие Central_ProcessEvent(). Разбор производится внутри программы пользователя. Основными событиями являются:
старт задачи пользователя (tmos_start_task)
старт устройства, потеря связи и обновление параметров
чтение уровня RSSI присоединенного устройства
-
передача сообщения *pMsg из стека в приложение
Сообщения *pMsg в свою очередь бывают следующими:
получение запроса о сервисах и характеристиках
подтверждение записи данных в характеристику
получение запрошенных данных из характеристики
получение данных нотификации
Что бы правильно отрабатывать события и сообщения, необходимо научится их правильно читать. В файле CH58xBLE_LIB.H описаны команды обращения к стеку. Там же описано какие флаги выставляются при соответствующих событиях и сообщениях.
Заключение
Всего несколько строк в конце статьи. На мой взгляд контроллер CH582 довольно неплохое устройство. У его BLE стека есть ряд недостатков, которые можно обойти. Надеюсь в будущем они будут исправлены. Возможно что я сам в чем то не разобрался. Тогда пишите свои замечания в комментариях. Совместно мы сможем быстрее его освоить. А на данный момент это всё.
Печерских Владимир
Сотрудник Группы Компаний «Цезарь Сателлит»