У каждого программиста микроконтроллеров с опытом формируется коллекция решенных багов. Баги появляются и исчезают, как вспышки на Солнце. Некоторые из них весьма эпичные.
Самый типичный баг - это зависание прошивки. Переслали мигать heart beat LEDы, UART-CLI перестала отвечать на команды. В таких случаях не надо подвергаться конвульсиям, судорогам и парралличу. Надо спокойно разбираться в ситуации.
Выявление причин багов порой сродни работе детективом. Это проявляется в том, что очень трудно выявить причину бага. Сначала разработчик идет по ложному следу, ходит кругами, а конце концов выясняется (порой случайно), что причина на самом деле была проста, как солдатский валенок.
Вот об этом сейчас и поговорим...
1-- Отлаживаем телематическую плату в CAN сети. Подключили переходник USB-CAN. Автомобиль не заводится. Стартер работает, но зажигания (вспышек в цилиндрах) не происходит. Разобрали половину впускного коллектора. Рукой шевелили дроссельную заслонку. Три часа искали причину поломки. Оказывается в OBD-II разъем попал кусок фольги от папиросок, которые замкнули три крайних пина. Стоило пинцетом извлечь мусор, как автомобиль завёлся с пол-оборота. Вот так. Этот баг называется "Мусор между разъёмами". Вот так просто и не затейливо.

2-- Схемотехники разработали электронную плату с разъемом Tag-Connect. Плату разрабатывали полгода. Плата скомпонована с плотностью нейтронной звезды. А после сборки выяснилось, что никак не примонтировать самый главный разъём - тот что для программирования. Ручной зажим Tag-Connect не защелкнуть, так как пальцы банально не пролезают между стабилизатором напряжения Traco Power и разъёмом Tag-Connect. Да... Всё не предвидишь. В результате пришлось просить женщин с тонкими пальцами, чтобы соединить программатор и электронную плату. Этот баг называется: "толстые пальцы".

3--При питании от USB электронная плата не включается. Вернее она на мгновение мигнет и сразу отрубается. Сначала я подумал, что происходит это из-за инициализации BLE и UWB. Якобы они сильно просаживают напряжение. Но при отключении всего wireless connectivity из сборки пропадание электропитания осталось. Но потом случайно заметил. Когда USB вилка вставлена до упора, то на плату не подается питание. Однако если же USB вилку аккуратно выдвинуть всего только на полдлины, то так питание поступает! Оказывается был просто бракованный разъём гнезда для USB-A. На плату просто не поступало питание по USB. Мораль: "Не надо жалеть денег на кабели USB".
4-- Отсутствие SWD link(a). Программатор не видит target по SWD. Собрали стенд, положили SWD длиной 90 см и нет Link(а) с MCU. Когда кабель 12 см, то link есть. Оказывается, что пакеты SWD шины просто не проходили через slip-ring. Slip-ring - это такое устройство, чтобы пропускать провода через подшипник. Чтобы провода не наматывались на ось и не рвались. Пришлось прошивать электронные платы внутри турели навесу.

5-- Плата с СС26x4 зависает при перезагрузке. Плата работает под отладчиком, а при пере сбросе питания не стартует прошивка. На другой плате это не проявляется. Эта ситуация потребовала неделю на выяснение причины и устранение. Оказывается у СС26x4 MCU от TI надо прописать спец адреса в конце Flash памяти, чтобы чип переключился на внешний осциллятор. Там в последней странице Flash живет сектор конфигурации SoC-а. Вот так.
6--Статическое электричество постоянно портит жизнь. Порой ставишь электронную плату на недельный тест, чтобы наработать логи. Приходишь через неделю cнять характеристики по UART, ценнейшие логи из RAM памяти. Только дотрагиваешься до края электронной платы... Дзык! Проскальзывает искра статического электричества, которая убивает содержимое RAM памяти и прошивка заклинивает прямо на глазах.
И весь недельный тест с логами внутри накрывается медным тазом... Пришлось поднимать на устройстве NVRAM и черный ящик в SD карту, чтобы писать логи в энергонезависимую память. Вот такие вот пирожки с капустой... Понимаете?...
7--У меня был случай, когда три схемотехника спроектировали электрическую цепь электронной платы (схемотехнику), развели топологию (layouts), отправили производство в другую страну, a спустя три месяца на выходе выяснилось, что они забыли вообще даже подать на микроконтроллер электропитание! Вот так... Как говорят:
У семи нянек дитя без глаза.
8--Никак не проходит auto-negotiation в Ethernet физике по 100-Base-TX. Не проходит ping. Оказывается в монтажных мастерских техник по ошибке припаяла кварц для физики fast-ethernet, не на частоту 25 MHz, а на частоту 23 MHz! Перекинули кварц и ping-и сразу побежали, как горный ручей. Не тот был кварц.
Или вот, плата Olimex-STM32-H407 в UART3 вместо лога загрузки сыплются кракозабры. Оказывается, что прошивка думает, что кварц 25 мегагерц, а там на самом деле 12 мегагерц. Пересобрал прошивку с настройками тактирования от 12 мегагерц и побежал понятный лог на ожидаемой битовой скорости .
9--Собранная прошивка для платы с МК STM32F413ZGJ6 зависает при прыжке из загрузчика в приложение. При пошаговой отладке всё стартует отлично. При выяснении причины выяснилось, что перед прыжком в приложение загрузчик смотрел на указатель
стека и не запускал прошивку, если в таблице векторов прерываний указатель
на верхушку стека ссылается на размер RAM больше, чем 128kByte. В таких случаях загрузчик просто прыгал в бесконечный цикл. Загрузчик, к слову, писал коллега из другого дивизиона.
При этом напомню на MCU STM32F413ZGJ6 320k Byte RAM! Оказывается коллега разработчик загрузчика по ошибке всегда собирали прошивку вообще для другого MCU: STM32F205VC. И generic приложение он тоже собирали для STM32F205VC, а записывал на STM32F413ZGх. Поэтому раньше у него это зависание не проявлялось. Его прошивка работала чисто только благодаря обратной совместимости между ядрами ARM Cortex-M4 и ARM Cortex-M3. Оказалось, что ему просто лень было посмотреть, что написано на корпусе микросхемы DD14. Упс!, Микроконтроллер перепутали...
Программисты порой как туземцы какие-то вообще не понимают с чем работают. Попалась им в руки европейская игрушка и давай её вертеть не по назначению.
Техника в руках дикаря - кусок железа.
10-- Ошибка snprintf. Прошивка для ARM Cortex-M33 неожиданно сваливается в исключение Default Handler внутри функции snprintf(). А конкретно на функции svfprintfr и ассемблерной команде VSTMDB. Оказывается snprintf использует вычисления с действительными числами. При этом код прошивки был собран с активированным аппаратным FPU одинарной точности. Это опции компилятора -mfloat-abi=hard -mfpu=fpv5-sp-d16, одновременно с этим startup код не включал сопроцессоры FPU в регистре SCB->CPACR.
Пришлось либо отрубать аппаратный FPU ( -mfloat-abi=soft ), либо включать сопроцессоры FPU.
#ifdef ENABLE_FPU
/* Enable CP10 and CP11 coprocessors */
SCB->CPACR |= (3UL << 20 | 3UL << 22);
#endif
11--Загадочные прерывания. Почему-то при инициализации CAN трансивера прошивка зависает в DefaultISR. Сначала я думал, что нет тактирования на CAN трансивере, ибо SoC весьма сложно раздавал тактирование. Однако нет. Тактирование настроено нормально. Это показал вывод частоты "на улицу". Оказывается, при инициализации CAN вызываются прерывания, на которые нет обработчика. Причём это были зарезервированные для данного MCU номера прерываний, для которых для данного MCU по спеке вообще ничего не предусмотрено. И тем не менее, иногда эти номера выстреливают, что приводит к сваливанию прошивки в бесконечный цикл default_ISR. Чтобы починить инициализацию CAN трансивера пришлось определить обработчики прерываний по умолчанию для всех 196 ISR. И определить эти обработчики, как weak функции.
12--Так называемая "ошибка 71-ой минуты". Прошивка всегда стабильно зависает на 71-ой минуте работы (4291 секунде). Светодиоды перестали мигать, UART-CLI перестала отвечать на команды. Оказывается переполнилась переменная up_time_us = 4294967296 us = 4 294 967 ms = 4 294 s= 71 m. И программный компонент limiter просто ждет, когда переменная up_time_us превысит значение 4294967297 us и не вызывает никаких функций. А это и не происходит, так как 32-х битный счетчик up_time_us пошел по второму кругу. Пришлось добавить обработку на переполнение типа данных uint32_t.
13--Очень низкая дальность LoRa link-a. У нас в компании спроектировали PCB c дальнобойной радиосвязью LoRa. Однако почему-то уже на расстоянии 30 метров обрывается сеанс связи. Радиокоманды не поступают. При этом тот же код драйвера SX1262 на покупной плате T-Beam работает аж на 15 километров. Это было специально проверено на полигоне. Оказывается на нашей плате схемотехник сильно отошел от reference дизайна и заложил ключ BGS12WN6E6327XTSA1 с инверсными логическими уровнями. В переводе на кухонный язык, когда LoRa трансивер передавал сигнал, антенна была просто отключена! Когда трансивер принимал, мультиплексор DA10 подключал антенну на передатчик и ASIC ничего не принимал. Вернее антенна была в виде дорожки PCB длинной 7 миллиметров. Вот так...

И это только то, что я смог вспомнить за один присест. В реальности багов было много больше. Не наступайте на те же грабли, что и я.
Итог
Как видите, проблем может быть просто море и они поджидают вас абсолютно везде. И чтобы понять, что происходит, порой нужно воистину нешаблонное
В программировании микроконтроллеров до того, как вы дойдете до всяких так алгоритмов и структур данных пройдет год, а то и два колупания с электропитанием, макетированием, тактированием, прерываниями и прочим. А проблемы отсутствия всяческого Link(а) в программировании микроконтроллеров и вовсе красной нитью прошивают всю мою карьеру. Особенно в случае беспроводных интерфейсов.
На сам процесс программирования уходит максимум 10...30 процентов времени. В основном приходится что-то бесконечно ремонтить.
Суммируя аппаратные баги, это либо ошибка в схемотехнике или ошибка в топологии.
Баги в разработке на микроконтроллерах это совершенно нормальное явление. Главное чтобы из них делали выводы. Надо уметь выявлять их причину.
Если у вас тоже случались культовые баги в разработке на MCU и вы нашли причину и решение, то напишите про это в комментариях.
Автор: aabzel