В этом тексте перечислены основные способы отлаживать и диагностировать проекты на микроконтроллерах. Для аналогии буду каждому методу отладки метафорично приводить в соответствие аналогию из медицины
1–*HeartBeat LED (Стетоскоп)
Самое важное. Каждое электронное устройство должно иметь хотя бы один светодиод (LED) для того, чтобы пользователь, инженер или техник мог понять, что встроенное firmware вообще вертится и исполняется, а не зависло. HeartBeat LED это своего рода Smoke Test. Если LED не мигает, то тут дальше и говорить не о чем. Сразу очевидно, что прошивка либо не стартовала, либо и вовсе зависла. В случае немигающего LEDа надо подкатывать тяжелую артиллерию. Также желательно ставить отдельно красный LED для индикации ошибки в софте или железе.
HeartBeat LED обычно ставят мигать с частотой 1Hz и, если это в самом деле так, то можно тут же дать гарантию, что тракт подсистемы тактирования тоже корректно настроен.
В общем, господа, делайте всегда HeartBeat LED.
2– Пошаговая отладка GDB через SWD/JTAG (или Хирургическое вмешательство c наркозом)
В микроконтроллерах есть специальные прерывания, которые позволяют программе останавливаться на заданном адресе (аналогия с анабиозом), который binutils(ами) конвертируется в строку кода в сорцах. Чтобы этим воспользоваться нужно запустить GDB сервер отладки и GDB клиент. Можно остановить программу на конкретной строчке кода.
Однако пошаговая отладка плоха тем, что она нарушает таймингами Real Time программы. Стоит поставить одну единственную точку останова и вы уже отлаживаете совершенно не ту программу, которую писали.
9– Функции Assert (или ПЦР тест)
Это просто функции, которые выстреливают, когда их аргумент равен нулю.
Есть свой assert на каждую фазу сборки проекта: makeAssert->preprocAssert->staticAssert-> DynamicAssert. StaticAssert отрабатывает на этапе компиляции. Например, что конфиги валидные. DynamicAssert отрабатывает на этапе исполнения. Можно еще расставить как капканы preprocAssert и даже makeAssert, если вы собираете сборку из makefile(ов).
Если сработал DynamicAssert, то можно подключить GDB отладчик и поставить точку останова внутри DynamicAssert. Далее просмотреть стек вызовов и определить причину осечки. В общем пользуйтесь функциями категории assert по-полной.
3– *CLI(шка) (Command Line Interface) (или Компьютерная томография)
А вот CLI это как раз самый мощный способ отладки прошивок. Как правило CLI терминал это полнодуплексный текстовый интерфейс поверх UART. CLI как способ человеку общаться с прошивкой через понятый обоим сторонам текстовый интерфейс. При этом нужно всего 3 провода (Rx, Tx и GND) и поддержка в коде прошивки. По факту раз запустив CLI и GDB вам уже больше не понадобится. Далее отладка будет только через CLI. Далее вы ограничены одной только своей фантазией в том какие CLI команды добавить в сборку. Можно по команде вычитывать любую память. Можно запускать функции по их адресу в физической памяти. Можно просматривать значения счетчиков, можно пулять пакеты в интерфейсы I2C, SPI, UART. Можно добавить интерпретаторы аппаратных регистров таймеров. Да что угодно.
Важно, чтобы CLI была не просто простыней унылого текста как в NanoVNA V2. В хорошей CLI должно быть: эхо, энергонезависимая история введенных команд, help, TAB-автонабор, авторизация, аутентификация, поддержка цветов, отрисовка таблиц. Это минимальный джентельменский набор взрослой CLI.
Чтобы ошибки отображались красным текстом, предупреждения желтым текстом. Чтобы печатались таблицы для GPIO пинов и каналов ADC.
Также надо различать такие понятия как логирование и CLIшка. При обычном беспонтовом логировании микроконтроллер тупо и отчаянно шлет текст на улицу (в UART). В случае с CLI пользователь может даже сам асинхронно отправить текст в микроконтроллер со стороны улицы. Должна быть установка и отключение логирования для конкретных программных компонентов (например для SPI или ADC), чтобы не было ниагарского водопада из логов, парализующего работу всей прошивки и всякое взаимодействие с программой. CLI не обязательно делать в UART. Подойдет и TCP/UDP, LoRa, BLE-SPP. Просто правда в том, что UART прост как палка и стартует почти сразу после reset(а). Раньше прочих навороченных интерфейсов как TCP стек, а значит и отладить по UART можно будет практически всё.
Причем логировать можно и в RAM память, а отобразить накопившийся лог в UART только после того как проинициализируется подсистема UART (функция flush). Поэтому писать логи можно даже для инициализации подсистемы тактирования, которая отрабатывает до запуска аппаратных драйверов. Достоинство CLI в том, что CLI не нарушает таймингов в той мере, как это делает пошаговая отладка по JTAG/SWD. Вы отлаживаете прошивку "без наркоза". С CLI(шкой) у вас будет тотальный контроль над софтом и железом. Попробуйте запилить CLI и вы сами увидите как вам понравится такая отладка.
4– GPIO и осциллограф (Кардиограмма)
В прошивках есть очень быстрые RealTime процессы, которые надо измерять. Как это сделать? А вот так... Можно выставлять напряжение на свободных GPIO пинах и далее смотреть их на экране осциллоскопа. Главное чтобы осциллограф был цифровой так как нужны функции захвата перепадов напряжения. Плюс нужно минимум 2 канала для отладки чего либо нетривиального. Также крайне важно, чтобы осциллограф не гудел как пылесос, иначе не будет никакого желания вообще включать такой оссцилл.
5– GPIO и логический анализатор (Электроэнцефалография)
Более предпочтительным вариантом осциллографу является логический анализатор. У логического анализатора больше каналов (8..16 каналов). Можно анализировать сразу целые много проводные шины (MII, I2S, SDIO). Есть очень хороший логический анализатор Saleae. Подключается к PC по USB 3.0. В отличие от осциллографов логический анализатор абсолютно бесшумный, что позволяет сосредоточится на анализе. Анализ графиков делается прямо на мониторе. Софт рассчитывает периоды, частоты скважность на лету. Также у Saleae очень удобные цепляши.
*6– DAC (Цифро-Аналоговый Преобразователь) (или микроскоп)
Когда GPIO не хватает, то можно выставлять аналоговое напряжение на одном DAC пине и тоже смотреть осциллографом с достаточным разрешением. В большинстве адекватных MCU(шек) всегда есть встроенный 10...12бит ЦАП для таких случаев. Очень удобно при отладке планировщиков многопоточных прошивок. По ступеням напряжения на выходе ЦАП можно определить реальный приоритет потоков.
7– Логирование на дисплей (Глюкометр)
В принципе, если есть достаточно пинов, то для автономности отладки можно поставить какой-нибудь дисплей и отображать на нем важные метрики софта. Получится устройство тамагочи, которое само все про себя расскажет своему хозяину. Советую смотреть в сторону OLED экранов так как у OLED светятся символы, а не фон. Выглядит футуристично и очень приятно читать.
8– Модульные тесты (скрепы)
Часто возникает ситуация когда есть большой кусок кода и нет возможности пройти этот код отладчиком. Например времени мало. В этом случае можно просто покрыть этот код тестами. Также тесты позволят без опаски совершать перестройку софта. Тесты будут стимулировать вас писать более модульный и качественный код.
10– STMStudio (Электроэнцефалография)
У ST есть хипстерская Tool(а), которая позволяет по SWD/JTAG следить за конкретными переменными в физической памяти (REG, RAM, ROM) микроконтроллера.
Просто скармливаешь STMStudio *.map файл и подключаешь по SWD Target. Причем эта Tool(а) позволяет строить графики по значениями переменных в памяти. Это как утилита ArtMoney в случае с взломом компьютерных игр на PC, только для микроконтроллера. STMStudio мега удобна при отладке систем автоматического управления (ПИД ругуляторы), цифровых фильтров, триггеров Шмитта и прочей DSP обработки. Меняя значения переменных можно даже управлять поведением прошивки!
Все бы вендоры микроконтроллеров выпускали бы такие шедевральные утилиты для своих чипов как STMStudio для STM32 микроконтроллеров.
11– Логирование в SD карту (Черный ящик)
UART это весьма медленный интерфейс. Максимум 1 МBit/s. Поэтому отладка логированием в UART всё же немного, но нарушает тайминги, а значит и логику работы устройства. Если быстродействие гаджета критично, а логи тоже очень нужны, то логи можно записывать в какие-нибудь число хранилище. Например SD карту или OffChip SPI-NorFlash на несколько мегабайт. Там 25MHz это норма. Однако придется собрать файловую систему (например FatFs) на SD карте, чтобы потом можно было писать в настоящие файлы и читать их на LapTop. Затем в период Idle выгрузить логи в тот же самый UART или TCP/UDP. Easy.
12– Health Monitor (Мед брат)
Health Monitor (HM) просто поток или отдельная периодическая функция, которая только лишь регулярно проверяет критические параметры прошивки. Своего рода периодические модульные тесты. HM проверяет, например, что UART и CLI не упала. Что есть всяческие Link(и) c I2C, SPI чипами. Что напряжение не просело. Плюс Health Monitor(а) в том, что если что-то внезапно рухнет (например от заряженной частицы из космоса), то прошивка об этом узнает сразу и что-нибудь да предпримет. Health Monitor обладает правами выполнить какой-то мелкий ремонт: переинициализировать отдельный компонент, что-нибудь починить или и вовсе Reset(нуть) гаджет.
Вывод
Как видите во встраиваемом софте есть целая куча способов отлаживать код и железо. Конечно тут не все зависит только от программиста. Некоторые опции отладки требуют и от разработчика HardWare некоторых предварительных телодвижений (добавить LED(ы), UART, TestPad(ы), Flash, SWD разъем). Что вы возьмете на вооружение решать вам. Мне же для отладки в 99% случаев хватает Assert, LED, CLI, HM, uTests.
Если вам известны еще оригинальные способы отлаживать Embedded Software/Firmware, то пишите их в комментарии.
Комментарии (17)
BiosUefi
07.08.2022 21:52+1А к какому из вышеперечисленных пунктов относится Посткоды?
》пошаговой отладкой через SWD/JTAG?
На Процессорах она ещё и по каждому из ядер позволяет отлавливать и отлаживать.
Amomum
07.08.2022 21:59+4Есть еще вариант post-mortem отладки, т.е. снятие дампа памяти, который позже можно как-то расковырять (например, загрузить в отладчик)
Sun-ami
07.08.2022 23:17+1И не только памяти, но и регистров периферийных устройств. Этот метод очень полезен при обнаружении аномалий тестировщиками - часто такие аномалии очень трудновоспроизводимы. Я также добавлял функцию "снимок состояния системы" в пользовательский интерфейс, чтобы вылавливать проблемы при пусконаладке и в опытной эксплуатации.
Goron_Dekar
07.08.2022 22:49+4Какой ужас! Мало того, что нет ни эмуляций, ни трассировки в реальном времени (на самом деле есть, но автор просто не знает, как работает упомянутая "хипстерская тулза". Но даже те методы, что описаны, описаны криво!
Чем логи на SD отличаются от логов в USART? Как термометр поможет отлаживать прошивку? Можно было бы добавить примеры вспомогательного кода для отладки. Можно было бы рассказать про дампы памяти на SD и разбор инцидентов. Можно было бы описать ограничения каждого метода и лучшие кейсы применения.
PKav
08.08.2022 01:07-1Как правило, методов SWD+логический анализатор хватает для всего. Остальное для совсем уж специфических случаев, а кое что может сожрать весьма существенную часть Flash.
MichaelBorisov
08.08.2022 01:12+6Жизнь не всегда настолько добра к нам, чтобы была возможность использовать любой из перечисленных методов отладки. И тогда выход может быть найден только за счет изобретательности разработчика. Приведу пару примеров из моей практики, какие приходилось применять решения.
1) Подмена выходных сигналов отладочной информацией. В той ситуации было совершенно невозможно использовать другие методы отладки. Ни эмулятора, ни точек останова, ни debug printf, ни GPIO/LED. Вместе с тем, прошивка формировала некие выходные сигналы. Временно заменив эти сигналы отладочной информацией, удалось вывести эту информацию наружу и по ней обнаружить и исправить ошибки в программе.
2) Создание эмулятора цифрового датчика. Был создан эмулятор, поддерживающий протокол датчика, но вместо измерения физической величины, он гнал на выход тест-сигналы. Специальным образом подобранные сигналы, рассчитанные на уязвимость алгоритмов их обработки к накоплению ошибок округления, позволили надежно воспроизвести редко возникающий на практике сбой.
3) Опрос регистров причины сброса и вывод их на консоль. Применялось для отладки редко возникающего краха прошивки, приводящего к перезапуску микроконтроллера. Сбивалось раз в сутки или двое, могло без перебоев работать часами. Вывод детальной информации о сбое позволил его несколько локализовать, с последующим выводом более подробной информации и, в конце концов, окончательно отследить и исправить ошибку.
4) Создание «пыточной» программы установления сетевых соединений. Изредка затыкался сетевой стек. Ошибка была практически невоспроизводима «на заказ». С помощью программы, постоянно устанавливающей и рвущей соединения, удалось воспроизвести ошибку за полчаса-час «пыток». Дальше дело техники — внутрисхемный отладчик, останов программы, изучение ее состояния — и вот ошибка найдена и исправлена, повторные несколько суток «пыток» показали, что результат достигнут.
Да, что еще важно… Никогда не отмахиваться от сообщений коллег или клиентов о сбоях. Оно обычно само не проходит, не рассасывается — как беременность.iliasam
08.08.2022 14:02+1"Подмена выходных сигналов отладочной информацией."
Когда-то давно читал, как программист выводил ШИМ на имеющееся реле, и оно издавало звук. Причем не абы какой - для отладки в контроллере был реализован простейший синтезатор речи)Indemsys
08.08.2022 17:17+2Однако недооценена роль светодиодов при отладке.
В своё время промышленно применяли вот такие ленты для отладки:Поскольку вывод в них был по DMA из RAM без вмешательства программы, то продолжали работать даже когда софт уходил в разнос. Для управления требуется всего один сигнал.
Indemsys
08.08.2022 09:16+1STM Studio разочаровало. Работает только через адаптер ST-LINK.
В этом контексте надо было упомянуть о визуальном отладчике в Arduino IDE (раз уж автор выбрал такой хаб).
Нет также упоминаний таких методик как MIL, SIL, PIL, HIL
А это очень интересные подходы.
Gromushka
09.08.2022 20:51-1А никто не заметил, что это феерия. Начиная с ледов, которые говорят побежал или не побежал код, и заканчивая точкой дебага внутри ASSERT
Это же великолепно, учитывая, что ASSERT и есть условная остановка в критической точке по условию, а побежал или нет код легко узнается по замерам питания который расходует контроллер.
А так да, надергано с кучи разных вещей и написано на уровне спеца с опытом в районе года.
Sun-ami
09.08.2022 22:48+1Как по замерам питания определить, бегает ли контроллер по основной программе, или бесконечно перезагружается из-за ошибки, бесконечно бегает по стёртому флэшу, или завис в бесконечном цикле какого-то обработчика прерывания по-умолчанию? Не говоря уже о том, что просто посмотреть на светодиод гораздо удобнее, чем замерять ток потребления после каждой перепрошивки. Мигающий в норме светодиод нужен не только разработчику, но и эксплуатационному персоналу.
Indemsys
09.08.2022 23:16+1На самом деле наблюдая за током потребления довольно просто определять различные состояния программы, если перед этим вы наблюдали как работает правильная программа.
Вот потребление у некоей схемы при мигающем светодиоде:
Выбросы тока от светодиода очень хорошо видны. На этом фоне видны также выбросы поменьше при обращении к другой периферии на плате. Изучая эти паттерны легко научить обнаруживать ситуации зависания или просто неправильной работы. При зависаниях, скажем, кривая потребления полностью ровная и выше уровнем и т.д.
Но нужен измерительный дивайс с большим динамическим диапазоном.
Gromushka
09.08.2022 20:56Добавлю, что имея единственный GPIO вполне можно организовывать нормальный лог наружу.
Sun-ami
09.08.2022 22:55+1Да, в большинстве случаев отладочный вывод через программный асинхронный передатчик гораздо удобнее и информативнее, чем использование ЦАП. Особенно если есть свободный аппаратный таймер. Но даже если нет - всё равно можно выкрутиться.
iliasam
Не упомянут интерфейс SWO, который можно использовать как для вывода данных в терминал, так и для отображения состояния нескольких переменных, включая построение графиков (значительно быстрее, чем в STMStudio, не привязано к продукции ST).
В некоторых «жирных» контроллерах есть скоростной интерфейс ETM Trace, требует более навороченного программатора/отладчика, зато позволяет собирать огромное количество информации о происходящем в контроллере в реальном времени.
Есть еще механизм Semihosting — по интерфейсу SWD можно передавать/принимать данные в терминал.
В многих IDE есть возможность просматривать переменные в реальном времени, не останавливая MCU. Скорость обновления при этом обычно не высокая. Хотя я не уверен, что при этом отладчик не влияет на скорость выполнения программы.
В IAR (про другие IDE не знаю) есть интересная фича — при работающей отладке можно в определённом месте кода сохранить данные из RAM на диск ПК: Ссылка
Для того, чтобы просматривать содержимое массивов в виде графиков при помощи отладчика, я в свое время писал специальную утилиту: Ссылка2
sami777
Судя по частоте упоминания UART для отладки, создается ощущение, что автор в основном пользует 8 - битные решения. Посему упоминаний про SWO нет.