Как отлаживают программы микроконтроллеров? Берется JTAG, осциллограф – пара дней/недель и программа отлажена. Таким будет типичный ответ, и в большинстве случаев он будет правильным… Но не всегда. Микроконтроллеры решают очень разные задачи, и в этой статье мы рассмотрим, что делать, если нужно разработать громоздкое ПО низкоуровневого управления каким-либо силовым электрооборудованием, например, преобразователями частоты для электродвигателей, DC/DC преобразователями заряда АКБ для поезда, корректорами мощности, сервоприводами и т.п. Оборудованием, где протекают килоамперы и ШИМят киловольты, где на счету каждая коммутация IGBT ключей инвертора, где время реакции микроконтроллера на нештатную ситуацию измеряется в микросекундах, а само оборудование в герметичных корпусах устанавливается и эксплуатируется где-нибудь на заводах Якутии. Если вы хотите узнать, какие особенности это накладывает на способы отладки – добро пожаловать под кат.
Особенности отладки систем управления
В чем же особенности отладки микроконтроллеров (МК), выполняющих такие задачи? Во-первых, когда МК работает с силовым оборудованием, его нельзя останавливать. МК при помощи ШИМ управляет силовыми ключами, регулирует множество величин в своих коридорах – токи фаз двигателя, напряжение звена постоянного тока, частоту вращения, положение рабочего органа и т.п. Если остановить МК во время работы на точке останова, то в лучшем случае оборудование отключится по аппаратной защите, а в худшем всё просто взорвется (если силовые ключи останутся включенными в «одном» положении или с одним заданием скважности). Поэтому классический способ отладки – «пройти по шагам отладчиком» в таких задачах не работает. Так можно только обкатать «на столе» совсем сырые программные модули перед их первым включением на реальном оборудовании.
Во-вторых, это сложность низкоуровневого ПО. Размер секции программного кода .text 50-200 Кбайт для программного кода, управляющего исключительно аппаратной частью (без высокоуровневых коммуникационных драйверов и т.п.) – это типичная ситуация для микроконтроллера какого-нибудь промышленного сервопривода. Поэтому для таких задач используют микроконтроллеры серии motorcontrol, которые сочетают в себе одновременно и очень развитую периферию, и высокую производительность, и относительно большой (для МК) объем памяти. В качестве примера из импортных МК можно привести 32х разрядные МК Texas Instruments серии C2000, из отечественных чип К1921ВК01Т ОАО «НИИЭТ». ПО для таких МК обычно содержит десятки или сотни тысяч строк отборного оптимизированного Си/Си++ кода, которые просто невозможно отладить «миганием светодиодиком», «printf’ом в UART» или наблюдением работы ножек МК внешним осциллографом.
В-третьих, контроллер системы управления электроприводом чаще всего стоит внутри силового преобразователя, корпус которого закрыт, а иногда даже загерметизирован. Поэтому доступ по JTAG – уже большая проблема хотя бы только для прошивки (с выключенным силовым питанием). И еще более серьезная проблема – отладка по JTAG с включенным силовым питанием. Здесь должен использоваться обязательно гальванически-развязанный и помехозащищенный JTAG (мы используем для МК TI JTAG SAURIS со встроенной гальванической развязкой – дорого, но работает).
В-четвертых, никаких операционных систем! Можно предвидеть, как у некоторых в голове крутится мысль «ну раз у вас такая сложная задача, поставьте нормальный микроконтроллер с Linux и пишите под него обычные приложения, обновляя ПО с флешки». Системы управления силовым оборудованием – системы очень жесткого реального времени. Не то что Linux, даже не все специализированные ОС реального времени подходят для таких задач. Например, прерывание АЦП по считыванию и усреднению аналоговых данных может вызываться с частотой до 100кГц. При этом оно будет содержать всего десяток-другой строк кода – сбор данных аналоговых каналов, пара проверок быстродействующих защит и выход – всё, больше ничего не успеть. Если поручить такое прерывание какому-нибудь планировщику задач ОС, то просто его собственное выполнение будет занимать больше ресурсов. Не говоря уже о том, что, в частности, для Linux вместо одной микросхемы МК на плату надо поставить еще две – внешнюю оперативную и флеш-память, отведя на них кучу драгоценных ножек кристалла, использовать шестислойную плату для правильной разводки, получить огромное время загрузки МК (иногда при сбое питания или срабатывании сторожевого таймера надо начать работу раньше, чем двигатель успел остановиться!), иметь проблемы с целостностью файловой системы и прочее.
Ну и пятая особенность – системы низкоуровневого управления электроприводом и другим силовым оборудованием (в отличие от задач коммуникации по разным интерфейсам, ПЛК, контроллеров всяких сигнализаций, пультов и прочего) реализуют в основном алгоритмы систем автоматического регулирования. А именно: софт наполовину состоит из различного рода замкнутых структур с ПИД-регуляторами, блоками насыщения, мертвой зоны, таблиц зависимости одного от другого, фильтрами, наблюдателями, задатчиками интенсивности, планировщиками движения и прочим. Вычисления в таком ПО выполняются с определенной частотой – скажем, на частоте 10кГц вызывается прерывание и обсчитывает все перечисленные блоки, которые вместе образуют нужную структуру управления оборудованием. В таких алгоритмах пошаговая отладка не помогает – чаще всего на каждом шаге каждый модуль выдает то, что от него ждут – собственно, все эти фильтры, регуляторы и прочее уже отлажено годами и сюрпризов там мало. Проблемы возникают при работе всей структуры в целом – каждый блок по отдельности работает, а желаемый процесс регулирования происходит не так, как ожидается. И проблемы оказываются как в настройке сотен параметров и коэффициентов этих блоков, так и в самой собранной из них структуре – может статься, что нужно добавить новый контур стабилизации чего-то где-то, добавить блок предсказания, ограничения и т.п. Поэтому это очередной «камень в огород» пошаговой отладки и отладочных сообщений printf: отлаживать нужно чаще всего не сам программный код, а собранную структуру автоматического управления. Если кто-то слабо представляет себе, что это такое (структура), то вот простейшая структура бездатчикового векторного управления синхронным двигателем:
Каждый квадратик – это иногда несколько формул, а иногда модуль на десяток-другой страниц кода. У модуля есть входы/выходы, а также некоторые переменные состояния (например, интегральная часть ПИ-регулятора и прочее). Также желающие могут посмотреть аналогичную структуру на странице википедии. Так как система управления замкнутая, то неправильная работа одного блока (или неправильная его настройка) приводит к неработоспособности всей структуры. И найти, где именно проблема – та еще задача.
Как же это отлаживать?
Итак, что же делать, как это отлаживать? Внешний осциллограф? Не поможет. Осциллограф, конечно, необходим для отладки некоторых чисто аппаратных проблем, но им можно лишь увидеть входные и выходные величины микроконтроллера, а сотни переменных внутри структуры останутся за кадром. Ну увидите вы, что ток фазы двигателя странно дергается, и странно дергается выходное напряжение инвертора. А почему – какой блок внутри ПО МК к этому приводит (или к этому приводит кривой двигатель или датчик положения или ещё что) – останется непонятным.
Модель? Да, это хорошее подспорье. Чаще всего разработка сложных структур управления начинается с моделирования. В терминах ТАУ и в виде дифференциальных уравнений описывается объект управления, строится предполагаемая система регулирования (как на рисунке выше, например), а далее всё это реализуется… ну, кто в чем любит, но стандарт-де-факто – это Simulink Matlab. В нем можно «нарисовать» структуру вместе с моделью объекта управления, используя «рассыпуху» в виде интеграторов, сумматоров, переходных функций и т.п. Можно воспользоваться его пакетом по моделированию электрических цепей, где есть готовые IGBT ключи, электродвигатели, резисторы, конденсаторы и прочее, отдав на откуп программистам матлаба реализацию нарисованного в виде дифференциальных уравнений, а саму структуру управления нарисовать уже в виде «рассыпухи» самому. А еще можно написать все нужные блоки в матлабе на Си. Этот способ удобен тем, что отлаженный программный код в матлабе можно просто скопировать в микроконтроллер. Обычно этот этап всегда следует за «рисованием», когда структура системы управления после прикидочных исследовательских работ по моделированию более-менее сформировалась. Но зачастую параметры объекта априори неизвестны, или известны очень неточно – никогда еще софт, работающий в модели, не начинал также хорошо работать на объекте. Также нельзя заложить в модель «всё» – переходные процессы переключения транзисторов, насыщение магнитопровода, вихревые токи, ёмкостные связи, уплывание параметров от температуры и от экземпляра к экземпляру, помехи то здесь, то там… А иногда объект регулирования настолько сложен, что проще делать разработку структуры управления для него уже непосредственно на объекте.
Например, когда мы делали систему управления для поддержания тока в дуге плавильной печи при помощи транзисторного источника напряжения, объект управления (дуга) был чем-то из разряда черного ящика. Мы нашли несколько моделей дуги в разных статьях, но они описывали внутренние процессы в плазме дуги, без ответа на наш «простой» вопрос – как надо задавать на дугу напряжение, чтобы ток оставался постоянным, и справится ли с этим обычный ПИ-регулятор тока? (если кому интересно – не справился, пришлось городить «огород высоких материй», но всё получилось).
Также есть ряд продуктов, позволяющих «рисовать» программы непосредственно для микроконтроллеров. В том числе тот же Matlab умеет генерировать Си-код для МК именитых брендов на основе модели в Simulink. Якобы можно нарисовать и отладить нарисованную структуру системы управления на компьютере в модели, а потом загрузить в МК – и готово, поехали! И даже такие среды позволяют отлаживать нарисованные структуры управления прямо внутри МК, смотреть переменные и т.п., а на сайтах таких продуктов есть куча демо-проектов для самых сложных систем, «запрограммированных» таким образом. Но так как все реальные проекты до сих пор почему-то программируют «руками», то можно догадаться, что с «рисованием» что-то не так. Но тут даже сложно описать, что именно, когда не так – всё. Главный аргумент против – это отсутствие полного контроля над происходящим внутри МК. Вы нажимаете кнопку в такой среде «сделать хорошо» и надеетесь, что генератор кода сделает за вас всё остальное. Для каких-то простых систем, где производительности МК «за глаза», сроки разработки очень поджимают, а программировать на фирме, которая взялась за проект, никто не умеет… то да, наверное, можно попробовать «нарисовать» программу. Но если она не заработает как надо, или будет иметь какой-то очень специфический глюк, то отладить её уже не будет никакой возможности. А для сложной задачи, где даже при программировании руками с производительностью МК всегда проблемы, рисование не подходит просто по причине нехватки ресурсов – любой язык программирования, чем он более высокоуровневый (куда уж выше рисования), генерирует менее оптимальный машинный код. А низкоуровневые оптимизации, которые сделал бы программист на Си, такая система сделать не сможет (расчет блоков одной структуры с разным тактированием, использование закешированных значений синуса и косинуса, замена функций деления на умножение на заранее подготовленную величину, или совсем уж хитрые вещи типа таких и т.п.).
Таким образом, приходится писать свой софт, и писать на Си. И отлаживать свой софт так или иначе надо, и надо на объекте. Наверное, к этому месту статьи все уже поняли, что отладить структуру управления можно только просмотром осциллограмм внутренних переменных, т.е. просмотром графиков во времени, как меняется та или иная переменная на Си – скажем, «выход вот того блока, пятого слева, одновременно с входами третьего справа». Получая картинки типа такой:
И сделать это можно только средствами самого микроконтроллера. Нельзя просто взять и поставить внешний быстрый интерфейс связи и посылать «наверх» значение какой-то переменной, так быстро, как только можно, а уже в системе верхнего уровня строить график. Потому что ни один интерфейс связи МК не успеет сделать это с той частотой, с которой протекают регулируемые переходные процессы. А если успеет, то все ресурсы МК уйдут на обслуживание этого интерфейса связи. Поэтому делают так – записывают осциллограмму в оперативную память МК, просто в массив. Обычно много точек не надо – достаточно поймать нужный момент, когда именно записывать данные: возвести нужный триггер на старт записи. И тогда можно увидеть, что выдавали те или иные блоки системы управления в момент сбоя, как он развивался, что пытался сделать МК. Конечно, все переменные сразу не заосциллографировать – но на практике по нашему опыту хватает, скажем, четырех массивов по 256 точек каждый – эдакий четырехканальный осциллограф средствами МК. Если сбой работы оборудования происходит не раз в неделю, то отладить это не проблема – в одном опыте смотрим эти 4 переменных, в следующем заменяем половину на другие, смотрим снова… пока не найдется неправильно работающий блок, или пока не снимем всё, что происходит на всех блоках и не уйдем просматривать «отснятый материал», почесывая то место, кто чем думает…
Чем же снимать такие осциллограммы? Какой софт это умеет? Через какой интерфейс связи это пересылать? Собственно, Texas Instruments потому и является лидером по производству motorcontrol микроконтроллеров, так как он сделал для этого всё, что надо: Code Composer Studio (их среда разработки) плюс режим реального времени МК. Режим реального времени – это когда через JTAG среда разработки может запрашивать и записывать данные в оперативной памяти МК без его остановки. Даже не просто без остановки, а без малейшего нарушения его работы. Этот режим есть во всех МК серии C2000, но для использования требуется дорогой и быстрый JTAG, который это поддерживает. Но кроме самого режима в МК должно быть что-то соответствующее и на обратной стороне кабеля: среда разработки Code Composer Studio «из коробки» умеет строить осциллограммы. Причем как в простейшем режиме, когда пользователь задает имя переменной Си и видит её изменение во времени на графике, а среда запрашивает данные с той частотой, с которой сможет (обычно хорошо, если герц 10), так и в режиме отображения массива в памяти в виде осциллограммы – т.е. как раз то, что описывалось выше. Таким образом, пользователь в МК делает ПО, которое запишет в массивы нужные осциллограммы, а Code Composer Studio через JTAG в реальном времени их скачает и покажет. При этом устройство может продолжать работать как ни в чем не бывало. Этот инструмент успешно используется уже больше десяти лет, и, собственно, такая идеология отладки (кажется, но могу ошибаться) и была предложена Texas. Во всех их демо-проектах есть модуль даталоггера (который записывает массивы осциллограмм) и в мануалах рассказывается, как им пользоваться. Кстати, здесь надо бросить камень в огород ARM. У них тоже есть режим реального времени, и на этой архитектуре есть МК, которые могут управлять электродвигателями. Однако ни в одной среде разработки мне не повстречалось функции построения графиков, даже если режим реального времени поддерживается. Например, в любимом всеми Keil даже нельзя на запущенном МК нормально поменять значение переменной – она постоянно обновляется, а вписываемое пользователем в окошко новое значение затирается… Не говоря уже о каких-то там графиках. Может быть кто-то в комментариях предложит работающий вариант? Или это «никому не надо», поэтому и не работает?
Но с этим способом отладки, даже через Code Composer Studio, есть проблема. И эта проблема JTAG. Как было сказано, его разъем не всегда доступен, а чаще всего на запущенном оборудовании и не доступен вовсе. Да и, честно признаться, не очень комфортно сидеть в паре метров от мегаватного преобразователя, смотреть его осциллограммы работы, и очень сконцентрировано и сосредоточенно объезжать мышкой кнопку «стоп» микроконтроллера, вдруг по пути дрогнет палец? А вы знаете, как глючит тачпад при работе мощного ШИМ? А если сглючит среда? А если JTAG? Всё, бабах?
Кроме того, осциллограммы в среде разработки отображаются в тех значениях, «как есть» на Си, без всякого масштабирования, на разных окнах графиков, без пользовательских единиц измерения (надо помнить, что на этом графике 0.342 это вольты, их надо умножить в уме на 540 чтобы получить физические единицы, а тут 1.2 это амперы с масштабом 800А). И неудобно, и страшно. А еще ведь не на всех МК и средах разработки можно смотреть осциллограммы! Вдруг у вас – не Texas? Поэтому мы решили изобрести другой путь.
Наше решение
Собственно, если нам не нужна пошаговая отладка, то в чем проблема? Заменяем всё, что мы делаем через JTAG, на любой другой интерфейс связи и делаем свою оболочку верхнего уровня, которая строит графики так, как нам захочется. Profit!
Так мы и сделали. Интерфейс связи мы выбрали CAN, протокол – CANopen. Почему? CAN – очень хороший промышленный интерфейс связи, помехоустойчивый, имеет аппаратный арбитраж, неразрушающий доступ к шине, аппаратное подтверждение посылок, и при этом – всего два провода и земля. Это лучше, чем все RSы, и менее монстровидное, чем Ethernet (который на motorcontrol МК скорее экзотика). Почему CANopen? Собственно, для CAN есть два распространенных протокола, это J1939 («автомобильный») и CANopen (станки, автоматика, датчики и прочее). Разницы между ними не так много, но CANopen нам показался более гибким, поэтому мы реализовали его в своем собственном стеке (драйвере). Кто не знает ничего о CANopen – основная его функция, как и многих протоколов для МК, это предоставление доступа к словарю объектов (списку переменных на Си МК) по определенному адресу. Делаться это в нем может двумя основными способами: сообщениями SDO вида запрос-ответ, а также сообщениями PDO в виде постоянной отправки значений по таймеру или по событию (настраивает верхний уровень, что посылать и когда). Также есть различные служебные сервисы типа аварийного сообщения (emergency), сообщения наличия устройств в сети (heartbeat) и т.п. Мастер в сети не обязателен: кто хочет – посылает, кому надо – принимает.
Мы сделали стек CANopen не только для МК, но и для компьютера в виде библиотеки. И уже на её основе под Windows написали свою среду верхнего уровня. Сначала сделали просто доступ к переменным словаря объектов, чтобы можно было смотреть и менять настройки системы управления (а их, между прочим, сотни!), потом сделали отрисовку графиков путем периодического запроса параметра словаря объектов по сети, а потом добавили загрузку осциллограмм из массивов МК (причем выбор что осциллографировать производится также из переменных объектов словаря). Получили всё тоже самое, что дает отладка через JTAG. Или нет? Нет, потому что нужна была еще функция обновления ПО через CAN. Несмотря на наличие бутлоадера по CAN в МК Texas, мы решили сделать свой, так как стандартный был не CANopen и мог мешать работе других устройств в сети, пока мы шьем одно, также как и устройства могли мешать прошивке. Кроме того, там были проблемы с коррекцией ошибок и пропажей сообщений (хоть CAN и очень хорош, сбои иногда бывают, а прошивка – очень ответственная вещь, чтобы не сделать верификацию или повторную попытку отправки битого куска). Поэтому мы реализовали свой «программатор» по сети CAN, но в рамках протокола CANOpen. Вот теперь всё. Теперь мы смогли полностью отказаться от JTAG, используя его только один раз, для программирования нового МК.
При этом такой подход открыл нам еще новые горизонты отладки, которые мы не видели раньше. Так как среду верхнего уровня мы делали с прицелом не только на программистов, но и на «обычных людей», мы сделали всем параметрам русскоязычные названия и сделали документацию наладчика по каждому параметру (документация не среды, а устройства, конечно). И это принесло пользу – теперь при наличии какой-то проблемы с приводом не обязательно «дёргать» разработчика – обслуживающий персонал заказчика в ряде случаев может самостоятельно выполнить диагностику проблем. Теперь мы можем получить е-меил вида «У нас привод стал странные звуки издавать иногда, я посмотрел осциллограмму датчика положения, вот что увидел (картинка). Проверил заземление экрана, оно отвалилось, я подпаял и все заработало как надо!». И совершенно не нужно никуда ехать или лететь! Второе «открытие» – если есть проблема, просим заказчика подключить компьютер к оборудованию и дать управление удаленным рабочим столом через интернет – запускаем свою среду верхнего уровня, сами все осциллографируем, правим параметры/прошивку/говорим что сломалось – profit! Опять не надо никуда ехать (главное, чтобы интернет на объекте был, хотя бы через сотовую сеть).
С годами использования эта программа верхнего уровня обрастала мелкими функциями, как грибами (естественный процесс для софта, которым пользуются). Это и работа с журналом аварий устройства, и сохранение/загрузка слепка всех параметров в файл на компьютере, и конфигурирование панели управления устройством а-ля «пульт управления», и ведение логов сети в файл, и отдача трафика CAN сети по TCP/IP, и автоматическая множественная прошивка/параметрирование однотипных устройств в сети (если устройств десятки, то прошить все руками – лениво, нужен скрипт) и т.п.
Ну а теперь немного рекламы. Сейчас это уже очень мощный инструмент (назвали мы его ни много ни мало – UniCON), который в некоторых задачах выглядит функциональнее, чем аналогичное ПО от именитых брендов по настройке их приводов и устройств. При этом он не привязан к конкретному устройству – можно настраивать хоть электропривод, хоть печку, хоть зарядное устройство – меняется только словарь объектов. Сейчас в нашей компании мы не видим возможности выполнить успешно новый сложный проект без наших CANopen средств отладки. Для работы с UniCON нужно всего лишь встроить в МК наш стек CANopen, после чего МК превращается в цифровую лабораторию. Уверены, все фирмы, которые делают серьезные системы управления на МК, имеют подобные средства отладки. Но мы предлагаем наше CANopen решение в виде самостоятельного программного продукта, так как оно выполнено универсально в плане независимости от функций устройства. На текущий момент мы реализовали стек CANopen с описанными расширенными функциями для МК Texas Instruments C2000, их ARM микроконтроллеров (например, семейства Concerto) и для К1921ВК01Т ОАО «НИИЭТ». Поэтому если вам требуется разработать систему управления электроприводом или другим сложным объектом управления, то мы приглашаем вас к сотрудничеству.
P.S.
В комментариях с нетерпением ждем критики вида «Так есть же *** – оно делает все то же самое и бесплатно». Так как мы долго искали аналогичные по функционалу средства отладки для ARM, но споткнулись даже об именитые среды разработки.
Автор: НПФ ВЕКТОР