Разбираеися с CubeMonitor

July 23, 2021, 4:25 pm
blog-header-image

Сегодня я расскажу вам о таком прекрасном продекте как Cube Monitor от компании ST. Это приложение которое позволяет визуализировать и изменять переменные в процесе исполнения программы на микроконтроллере. Для визуализации данных можно создавать графические приложения доступные через баузер.

Для начала предлагаю разабратся в том что это такое и как это работает а потом перейти к практике. ST в своей презентации предлагает вот какую схему:

cubemon_shim

С левой частью схемы все понятно, подключаем STLink к своему устройству а программатор к ПК. А вот дальше интереснее. Gateway, пк к которому подключен STLink и на который установленно програмное обеспечение от ST разворячивает на себе сервер, к которому может подключится любое устройства с браузером и на нем станет доступен дашборд. С дашбордом все просто, его можно увидеть запустив просмоторщик из констроктора или из браузера на тойже самой машине обратившись к локалхосту, или с другой введа на ней в браузере ip адрес гетвея.

На гетвее я бы остановился по подробнее. На самом деле внутри данного програмгомного пакета находится Node-RED и компания ST по сути просто добавила туда несколько своих нод которые позволяют работать с STLink server а значит и с самим линком. К сожалению из этого следует, что никакой другой программатор кроме STLink использовать не получится. Однако нет поводов для печали потомучто компания ST далеко не единственная кто дадумался добавить свои компаненты в Node-RED и для работы с любыми конроллерами с помощью Jlink можно использовать програмный пакет FreeMASTER Lite (вообще он только для контроллеров NXP, но никто вам не мешает в меню выбора контроллера просто выбрать ядро Cortex Mx не привязанное к коткретному контроллеру). Вероятно я когданибудь тоже про него напишу.

На Node-RED я бы остановился более подробно. Суть этого приложения состоит в том что мы соединяем некотре ноды между собой которые общаются перетидыванием json обьектов, по какимто событием. Событием может быть приход новых данных в какойто интерфейс или изменения состояния кокогото обьекта в gui. Сами же ноды позволяют принимать или передовать данные по каким-то интерфейсам, а также принимать и передовать данные на дашборд. Также система позволяет постоить этот сымый дашборд. Но хватит рассуждений приступим к делу.

Для начала напишим простенькую программу под STM32 на которой будем тестировать функционал отладчика, просто мигалку светодиодом. Я возьму Nucleo-F411RE вы можете взять любую другую. Пишим дледующий код (в мейне):

uint32_t i,x = 0;
uint32_t delay = 10;
...
  while (1)
  {
      HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
      if (++i == 100) i = 0;
      x = sqrt(i);

      HAL_Delay(delay);
 ...

При сборке выдаст 2 варнинга, это связанно с тем что мы не подключили math.h, но умная ide и так ее подключит. Тут нужно обратить внимание не то что все переменные за которыми мы хотим следить должны быть глобальные, тоесть иметь постоянные фиксированные адреса в памяти, иначе отладчик не сможет их найти. Также код обязательно нужно собирать с debag информацией, иначе опять-же мы не сможем найти адреса переменных по их названиям.

Далее прошиваем контроллер и запускаем CubeMonitor и видим следущее:

cubemon_default

Компания ST позаботилась о нас и сделала простельнький пример который позволит строить графики переменных в реальном времени. Для его запуска необходимо настроить 2 ноды. В первой (под номером 1) необходимо выбрать наш STLink, для этого делаем двойной шелчек по ноде и открывается меню настроек. Там нам предложат добавить новый probe, нажимаем не карандаш справа (везде в этом ПО карандаш значит создание нового элемента) и выбираем там наш программатор. После чего можно будет выбрать протокол связи и частоту работы (у STLink V3, кстати, она в 19 раз выше). После подтверждения над изменяемой нодой проподет красный квадрат, что значит отсутствие ошибок в настройках нашей ноды.

Вообще у меня нет желания также подробно писывать каждый шаг, если по какойто причине это вам необходимо то это можно посмотреть тут и тут, я же буду более краток. Далее необходимо настоить ноду под номером 2. Для начала нужно выбрать elf файл в меню Executable а так-же переменные за которыми мы хотим следить. После чего на данной нодой тоже пропадет красный треугольник. После этого нужно еще выбрать программатор в ноде myProbe_In (которую я к сожалению забыл пронумеровать).

После этого над всеми нодами появются синии кружки, а значит ошибок негде нет. Нажимаем DEPLOY (3) (это нужно делать после каждого изменения) и DASHBOARD (4) после чего увидим приложение которое будет строить нам графики. На нем опображается все переменные за которыми мы хотели следить - i и корень из i.

defoult_ploter

Далее опишу несколько интересных моментов:

  • При нажатии на название переменной график данной переменной перестанет отображатся, а окно автомасштабикуется по высоте под оставшиеся графики. Однако оно подстроится не под видимую часть, а под весь график как бы давно он не строился.
  • Если остановить чтение (надать на STOP ACQUISITION) то график можно будет масштабировать.
  • Если вы хотите перепрошить контроллер и что-то поменять в коде, то обязательно освободить прогрпмматор (остановить чтение), а также после пересборки измененного кода обязательно в ноде с выбором переменных обновить их адреса (для этого достаточно просто открыть ее настройки и согласится на апдейт). Это нужно потому-что адреса переменных могут менятся от сборке к сборке.
  • Числа с плавающей точкой тоже хорошо отображаются.
  • На графике можно отобразить сохраненные данные если нажать IMPORT DATA.
  • В ноде Processing которая на скриншоте выше называется myVariables можно создавать дополнительные переменные которые будут вычислятся по определенной формуле от текущих.
  • Для доступа к дашборду из браузера используйте URL: http://localhost:1880/ui/, кстати сам редактор тоде можно открыть из браузера по адресу: http://localhost:1880/.

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

Для начала было-бы не плохо разобратся с тем как впринцепи работать с Node-RED. Этот можно постотреть тут, или в официальной документации, я же изложу самое важное для понимая.

Любая нода отправляет сообщение по какому-то событию. Это может быть нажатие на кнопку на дашборде или приход пакета по tcp. Важно то, что эти сообщения могут иметь 2 свойства (мне очень не нравится этот термин, но он используется в интерфейсе программы) payload и topic. Мы конечно можем создать любое их количество, но по умолчанию используются только эти. Первый из них - payload содержит в себе полезную нагруску сообщения, и может быть любым типом. Второй же - topic чаще всего строка. Топик может передать собщение с одним из этих свойств.

Для минимальной работы системы, просто отрисовки графика, нужно построить следующий поток:

min_flow

Наш поток состоит из 2х веток, верхней и нихней. Первая нужна для отправки данных на STLink server, а вторая на прием. Для того чтобы нода STLink in начала принимать данные с контроллера, сначала нужно передать данные для работы STLink server через ноду STLink out. Она ждет payload содержащий настройки, которые генерируется в блоке variables, которые мы задаем через настройку данного блока, а также topic который может содержать строку read, start и stop. Они нужны для того чтобы считать один набор значений из отладчика, включить непрерывное чтение и прекратить это чтение. Таки образом вместо кнопок мы можем использовать любой стандартный элемент который сможет записать строку в topic (в примере ниже используются кнопки), но настройки для программатора можно создать только в ноде Variables.

Нижний же блок устрон по проще, нода STLink in передает сырые данные (через свойство payload) в ноду Variables, по сути ноду процессинга, в которой по адресам считанных переменных им присваиваются имена. Далее после процессинга json с данными и значениями попадает в ноду Chart, которая отрисовывает график на дашборде, интересные момент заключается в том что если использовать стандартный топик Chart вместо фирменного, то приложение упадет из-за слишком большого количества данных.

Впринципи нам может потребоватся еще ровно 2 функции чтобы полноценно взаимодействовать со стандартными нодами, это чтение произвольной переменной и запсь. С первым все проще компания ST позоботилась о нас и сделала специальный подпоток Single value который позвояет выделить одну перменную после процессинга. Но иногда бывает такое что необходимо преобразовать тип данных, например пременная может иметь значения от 1 до 100, и мы хотим чтобы на дашборде загоралась кнопка если значение больше 80ти. Для этого нужно будет использовать ноду function которая позволит выполнить произвольный код Js при приходе сообющения. В итоге поток будет выглядить так:

cubemon_fun

А код функции:

if (msg.payload < 80) 
    return { payload: true };
else 
    return { payload: false };

С записью же переменных дела обстаяю хуже. ST дает нам ноду (write panel) которая позволит нам писать заначения в переменные, но представяет из себя панель, в которую мы можем руками забивать значения. Вглядит это так:

write_panel

А подключить никакие сдандатные элементы интерфейса мы не можем. Но есть выход, мы можем с помощью ноды debug узнать что шлет нода write panel в STLink out и сформировать такое-же собщение. Выглядить это будет так:

cubemon_slider1

Слайдер отправляет значения из определенного диапазона в свойство payload, после чего нода Write обарачивет его в шаблон который мы подсматрели в write panel, а нода set пишет в свойство topic строку wrire т.к. без этого значение не отправится в дебагер. Шаблон внутри ноды Write должен выглядеть так:

{
    "variablelist": [
        {
            "address": "0x20000000",
            "name": "PWM",
            "type": 6,
            "value": "{{payload}}"
        }
        ],
        "accesspoint": 0
}

Вместо {{payload}} будет подставленно знвчение со слайдера. Однако в этом методе есть проблема. Каждый раз когда адреса переменных будет менятся при пересборке кода, придется снова их смотреть с помощью дебагера, и праписать их руками в шаблон (а так-же тип). Вот если бы это можно было автоматизировать, и у нас есть для этого средства - функции и подпотоки. Создадим подпоток который решит все наши проблемы, в параметрах которого мы запишим название переменной и он сам сможет определять адрес двнной переменной.

mem_writer

Внутри же подпотока создадим всего одну ноду с функцией Js. На самом деле можно было бы обойтись без оддельного подпотока, только фукцией, но тогда мы не смогли бы указать название переменной точно так-же как это работает в подпотокe Single value.

function

Самое интересное присходит внутри ноды функции:

let message_send = {
    "variablelist": [
        {
            "address": "",
            "name": "",
            "type": 0,
            "value": ""
        }
    ],
    "accesspoint": 0
};

if (msg.topic == "start" || msg.topic == "stop" || msg.topic == "read") 
{
    context.set("save_payload", msg.payload);
}

else 
{
    var save_payload = context.get("save_payload");

    if (!save_payload){
        node.error("Not data for wariable !!!");
        return;
    }

    for (var i = 0; i < save_payload.variablelist.length; i++){
        if (save_payload.variablelist[i].name == env.get("variable")) {
            message_send.variablelist[0].address = save_payload.variablelist[i].address;
            message_send.variablelist[0].name = env.get("variable");
            message_send.variablelist[0].type = save_payload.variablelist[i].type;
            message_send.variablelist[0].value = String(msg.payload);
            message_send.accesspoint = save_payload.accesspoint;
            return { payload: message_send, topic: "write" };
        }
    }

    node.error("Wariable \"" + env.get("variable") + "\" not found !!!");
}

В самом начале мы создаем обьект - сообшение которое будем отправлять в ноду дебагера. Далее смотрим, если сообщение которое приняла наша функция имеет строку в свойстве топик, то значит это сообщение для дебагера с командой стартовать или остановится. Мы сохраним это сообщение в локальном контексте ноды (почитать про это можно тут), что-бы потом вытаскивать из него адреса переменных по названиям.

Если поле контекста пустое это значит что пришло число которое нам нужно записать в переменную, указанную в конфиге ноды.

Данная функция имеет ряд ограничений, например нельза писать значение до такго как включится плоттер (это свойственно и подпотоку Single value), так-же в наш подпоток Mem writer можно писать только числа. И обязательно должено быть указанно название перменной. Впрочем никто не запрещает вам его улучшать.

Пример проекта для CubeIDE и потока CubeMonitor можно найти тут.

Интересные ссылки:

Next Post Previous Post