Embedded HandbookПриложения
Все разделы › V. Отладка и качество
STM32F103, STM32F407 · уровень справочник · 47 мин чтения
Открыть в интерактивном справочнике

36. Типовые проблемы: симптом → причина → лечение

Каждый раздел справочника заканчивался «граблями» — здесь они собраны вместе и переставлены. Не по темам, а по тому, как выглядит беда: вы видите симптом, а не причину, и искать нужно от него. Больше четырёхсот строк, и большинство приборов, которые «не работают без причины», попадают в одну из них.

Цифра в последнем столбце — раздел, где разобрано подробно.

Как это называется в документации

Оригинал Перевод
troubleshooting поиск и устранение неисправностей
symptom симптом, внешнее проявление
root cause первопричина
intermittent перемежающийся, «иногда»
heisenbug ошибка, исчезающая при попытке наблюдения
works on my desk «на столе работает»
sanity check проверка очевидного
bisect поиск делением пополам

36.1 Порядок действий

Прежде чем искать по таблице — пять вопросов по порядку. Ответ «нет» на любой из них означает, что дальше искать рано.

1. Собирается ли без предупреждений? Не только без ошибок. Предупреждение о неявном приведении, неиспользуемом значении или неинициализированной переменной — в половине случаев и есть ответ.

2. Доходит ли до main? Точка останова на первой строке. Не дошёл — неверный файл запуска, таблица векторов, стек (раздел 11).

3. Тактируется ли то, что не работает? Половина всех «код правильный, а не работает» — забытый бит в RCC->AHBENR/APB1ENR/APB2ENR. Проверить регистр в отладчике, не код: код мог быть написан, но не дойти.

4. Та ли частота? Прочитать RCC->CFGR и SWS в отладчике, а не верить SystemCoreClock. Кварц не той частоты, PLL не включилась, SWS не проверен — и всё, что зависит от времени, врёт пропорционально.

5. Включено ли прерывание на всех уровнях? Периферия → NVIC → глобально. И приоритет назначен явно — по умолчанию он нулевой, и под ядром это ошибка.

Дальше — таблица.

Пять вопросов по порядку и что проверять при ответе «нет»

Три приёма, которые работают всегда

Делить пополам. Убрать половину кода — заработало? Значит беда в убранной половине. Повторять. Десять шагов — тысяча строк.

Делить пополам: тысяча строк сводится к одной за десять шагов; один шаг — убрать половину кода и проверить, заработало ли

Свести к минимуму. Отдельный проект из десяти строк, который воспроизводит беду. Если не воспроизводится — беда во взаимодействии, и это уже ответ.

Читать регистры, не код. Код говорит, что вы хотели. Регистр — что получилось. Расходятся — где-то между ними.


36.2 Не собирается и не компонуется

Симптом Причина Лечение §
у коллеги file not found на заголовке своего же проекта в Include Paths абсолютный путь пути от файла проекта: .\App;.\Board;.\Drivers 4а
undefined symbol при компоновке, хотя файл в папке есть файл не добавлен в группу проекта µVision добавить файл в группу 4а
Error #540: … component is not available … pack … is not selected версии паков не закреплены, а самый новый пак устроен иначе закрепить версии в Select Software Packs 4а
«uses RTOS support that is part of a Legacy Pack» в цели чужого проекта включена старая ОС RTX в настройках цели выбрать Operating system: None 4а
SVC_Handler определён дважды заготовки обработчиков остались в файле прерываний удалить три заготовки; подмену имён в конфигурации оставить 24
неразрешённая ссылка на функцию ядра, которая есть в исходниках не включён её INCLUDE_ добавить макрос в FreeRTOSConfig.h 24, 33
неразрешённая ссылка на vApplicationGetIdleTaskMemory включено статическое размещение написать обе функции выдачи памяти 24
#error из FreeRTOS.h обязательный макрос не задан сообщение называет его 33
ошибка на pvPortMalloc не подключён файл кучи добавить один heap_N.c 25
ошибка на xPortGetMinimumEverFreeHeapSize подключён heap_1/2/3 перейти на heap_4 25
__forceinline не компилируется адаптация RVDS под Arm Compiler 6 взять portable/GCC/ARM_CM3 24
программные таймеры не собираются нет INCLUDE_xTaskGetSchedulerState или configTIMER_* добавить 33
прошивка внезапно потяжелела включены таймеры, группы, буферы — а нужно одно отключить лишнее 24
'else' without a previous 'if' после вызова макроса макрос из нескольких операторов без do { } while (0) обернуть тело в do { … } while (0) 127
после перехода на C23 — «too many arguments to function call» объявление f() без void: в C23 это функция без параметров написать прототип с типами параметров 128
«unknown type name 'constexpr'» стандарт ниже C23 или компилятор без C23 -std=c23 на armclang 6.24 или #define / enum 128
не найден __stack_chk_fail при компоновке включена -fstack-protector-strong, а обработчика и контрольного слова нет написать __stack_chk_guard и __stack_chk_fail 129
код с F4 на F0 или G0 не собирается: неизвестна __set_BASEPRI у Cortex-M0 и M0+ нет BASEPRI критическая секция через PRIMASK (__disable_irq) 7
на F0 после своего загрузчика прерывания уходят в его таблицу у Cortex-M0 нет VTOR скопировать таблицу в начало ОЗУ и включить MEM_MODE в SYSCFG->CFGR1 7
undefined reference, хотя -l указан библиотека в командной строке раньше объекта, который её использует -l после исходников и объектов 143
relocation R_X86_64_32 … recompile with -fPIC объект для .so собран без -fPIC пересобрать с -fPIC 143
libpq-fe.h: No such file заголовки libpq лежат в /usr/include/postgresql -I$(pg_config --includedir) 148
insmod: Invalid module format vermagic модуля не совпал с ядром собрать под заголовки своего ядра 147
class_create не собирается с ядра 6.4 один аргумент, раньше два ветка по LINUX_VERSION_CODE 147
fatal error: esp_flash.h: No such file в проекте ESP-IDF у компонента указан REQUIRES — зависимости теперь только явные дописать компонент в REQUIRES 151
ledc_timer_config вернул ESP_FAIL частота × 2^разрядность больше 80 МГц уменьшить разрядность или частоту 153
прошивка собралась, а образ 0 байт и плата молчит в своём скрипте компоновщика нет KEEP(*(.isr_vector)) и ENTRY, а --gc-sections выбросил всё вернуть ENTRY(Reset_Handler) и KEEP, после сборки смотреть --print-memory-usage 4в

36.3 Не запускается

Симптом Причина Лечение §
не доходит до main файл запуска, таблица векторов, указатель стека точка останова в Reset_Handler 11
HardFault сразу после vTaskStartScheduler имена трёх обработчиков не подменены макросы vPortSVCHandler и др. 24
собирается, задачи не переключаются то же: вектора ведут на пустые заготовки то же 24
останов внутри port.c при старте configASSERT: приоритет прерывания или группировка стек вызовов; PRIGROUP ≤ 3 24, 28
стоит в vPortValidateInterruptPriority прерывание выше порога вызвало функцию ядра приоритет ≥ 5 или убрать вызов 28
останов сразу после старта задачи задача вышла из своей функции бесконечный цикл или vTaskDelete(NULL) 26
памяти не хватает с первого запуска куча 10 КБ на камне с 20 уменьшить или статическое размещение 25
часы «сбрасываются» при каждой перезагрузке RTC инициализируется безусловно проверять флаг инициализации в backup 12
мгновенный выход из Standby не сброшен CWUF сбросить перед входом 10
cannot open shared object file при запуске библиотеки нет в RUNPATH, LD_LIBRARY_PATH и кэше; текущий каталог не ищется rpath $ORIGIN или установить в систему 143
insmod: Operation not permitted нет прав или контейнер root на настоящей машине 147
ESP32 не стартует с подключённой периферией датчик тянет strapping-вывод при сбросе; GPIO12 вверх переводит флеш на 1,8 В освободить выводы 0, 2, 5, 12, 15 на время сброса 153
ESP32 перезагружается при включении Wi-Fi просадка ниже порога 2,43 В: слабый стабилизатор или кабель питание с запасом на пики радио 150
модуль на 4 МБ, а программа видит 2 размер флеш-памяти в menuconfig по умолчанию 2 МБ CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y 150
ESP32 после обновления по сети снова на старой версии новая прошивка перезапустилась до подтверждения — загрузчик откатил её подтверждать esp_ota_mark_app_valid_cancel_rollback() после самопроверки 159
после прошивки программатором ESP32 грузит старое приложение в otadata осталась запись о разделе ota_0 стереть otadata или всю флеш-память 159

36.4 Периферия молчит

Симптом Причина Лечение §
код АЦП с F1 на F0 или G0 не собирается: нет SQR3, CR2 у АЦП F0/G0 нет очереди — каналы отмечаются битами маска в CHSELR, запуск ADSTART, конец EOC 14
G0: АЦП не даёт ADRDY, калибровка не заканчивается не включён регулятор ADVREGEN или не выждано 20 мкс после него ADVREGEN, пауза 20 мкс, затем ADCAL и ADEN 14
G0: после смены канала первое измерение — с прежнего канала новая маска CHSELR вступает не сразу после записи CHSELR дождаться CCRDY 14
G0: питание по VREFINT завышено на 10 % заводской код снят при 3,0 В, а в формуле 3300 VREFINT_CAL_VREF из LL своей серии 14
код I²C с F1 на F0 или G0 не собирается: нет SR1, DR, CCR у F0/G0 другой блок I²C TIMINGR, обмен через CR2 (NBYTES, AUTOEND), флаги в ISR 17
F0/G0: программа виснет в ожидании TXIS на адрес никто не ответил — пришёл NACKF ждать TXIS и NACKF вместе, NACKF сбросить в ICR 17
F0/G0: после первого обмена блок «занят» не сброшен STOPF после AUTOEND записать STOPCF в ICR 17
код SPI с F1 на F0 или G0 не собирается: нет DFF разрядность у нового SPI — поле DS в CR2 DS = размер − 1, для 8 бит 0111 18
F0/G0: SPI шлёт лишний нулевой байт, приём сдвинут на байт 16-битная запись в DR при 8-битных посылках писать и читать DR байтом: *(volatile uint8_t *)&SPI1->DR 18
F0/G0: RXNE не поднимается после одного байта порог очереди приёма — два байта бит FRXTH в CR2 18
G0: канал DMA настроен и включён, а передачи нет запрос не подведён к каналу — не записан DMAMUX DMAMUX1_ChannelN->CCR = номер запроса из LL; канал N+1 DMA ↔ канал N DMAMUX 9
код DMA с F1 на F0 или G0 не собирается: DMA_CCR4_DIR, DMA1EN биты CCR без номера канала, у F0 бит тактирования DMAEN DMA_CCR_DIR, RCC_AHBENR_DMAEN 9
F0: DMA от USART1 идёт не на тот канал привязка не как у F1: USART1_TX — канал 2, с USART1TX_DMA_RMP — 4 таблица привязок F0 или бит переноса в SYSCFG->CFGR1 9
код сна с F1/F0 на G0 не собирается: нет PWR->CR, PDDS у G0 режим — поле LPMS в CR1, флаги — в SCR LL_PWR_MODE_* в LPMS, CWUF1/CSBF в SCR, EWUP1 в CR3 10
G0: запись во Flash даёт SIZERR или PGAERR SIZERR — запись байтом или полусловом; PGAERR — два слова не из одного двойного слова двойными словами по адресу, кратному 8: два 32-битных слова подряд 11
код Flash с F1/F0 на G0 не собирается: нет FLASH->AR страница у G0 стирается по номеру поле PNB в CR 11
код таймера с F1/F0 на G0 не собирается: нет RCC->APB1ENR у G0 регистры тактирования — APBENR1/APBENR2 RCC_APBENR1_TIM3EN, RCC_APBENR2_TIM1EN 13
F0/G0: частота ШИМ ниже расчётной — в 1,5 раза (F0) или в 1,125 раза (G0); в 9 или 4,5 раза, если система осталась на HSI PSC рассчитан под 72 МГц F1 такт таймера 48 (F0) или 64 МГц (G0): PSC 47 или 63 для счёта 1 МГц; проверить, что система ушла на PLL 13
код правильный, регистр не меняется не включён такт блока бит в RCC->xxxENR; проверить в отладчике 6
HardFault с PRECISERR, BFAR = адрес периферии то же: обращение к нетактируемому блоку то же 6, 35
запись в PWR->CR не проходит PWR на APB1 без такта RCC_APB1ENR_PWREN 10
таймер считает, а на выводе ничего вывод не в альтернативной функции настроить GPIO 13
настройки таймера не вступают в силу нет события обновления бит UG или дождаться переполнения 13
TIM1 молчит не выставлен MOE в BDTR выставить 13
прерывание таймера не приходит HAL_TIM_Base_Start только запускает счёт, UIE не выставлен HAL_TIM_Base_Start_IT 13
светодиод BluePill не откликается на ШИМ PC13 к таймеру не подключён внешний светодиод на выводе канала, например PA6 13
таблица через DMA в ШИМ не идёт в таймере темпа не разрешён запрос UDE DIER = TIM_DIER_UDE 9
DMA берёт каждое второе значение таблицы MSIZE 32 бита при таблице uint16_t размеры по элементу и регистру 9
прерывание не приходит цепочка: такт порта → EXTI → NVIC → глобально проверять по цепочке 7
обработчик зовётся бесконечно не сброшен флаг EXTI->PR записать единицу 7
I²C не работает вовсе нет подтяжек 4,7 кОм на обе линии 17
I²C: конфликт с ведомым выводы push-pull открытый сток 17
SPI не отвечает режим CPOL/CPHA, MOSI/MISO, CS, скорость проверять по порядку 18
SPI выходит из режима ведущего не выставлен SSI выставить с SSM 18
CAN не принимает при работающей передаче не настроен фильтр хотя бы один принимающий всё 19
одинокий узел CAN без конца повторяет кадр некому подтвердить: узел пассивный, но не в bus-off второй узел или петля 19
USB не определяется подтяжка D+, 48 МГц, HSI вместо кварца резистор 1,5 кОм; кварц; частота 20
CAN и USB вместе на F103 общая память буферов одно из двух 19, 20
SWO молчит SWD не JTAG; TRACE_IOEN; TRCENA; ключ; канал; настройки отладчика по порядку 21
SWO не работает на клоне отладчика клон не принимает трассировку другой отладчик 21
PB3 не работает как GPIO занят под SWO одно из двух 21
DMA не стартует забыто разрешение со стороны периферии (DMAT, DMA в ADC_CR2) выставить 9
DMA на F4 не стартует повторно остались флаги прошлой передачи сбросить в IFCR 9
ЦАП нет в кристалле его там нет смотреть даташит до разводки 15
сторожевой таймер срабатывает при отладке не выставлен DBGMCU->CR остановить сторож в отладке 12
флеш по SPI пишется «вхолостую» забыт Write Enable перед каждой записью и стиранием 41
f_mount → FR_NO_FILESYSTEM носитель не отформатирован f_mkfs 42
gpio_set_direction вернул ESP_ERR_INVALID_ARG выводы 34–39 только на вход, номеров 24 и 28–31 нет взять другой вывод 153
ADC2 отвечает ESP_ERR_TIMEOUT при включённом Wi-Fi второй блок АЦП занят радио перенести вход на ADC1 (GPIO32–39) 154
adc_continuous_config → ESP_ERR_INVALID_ARG частота ниже 20 кГц или выбран ADC2 20 кГц … 2 МГц и только ADC1 154

36.5 Работает, но не так

Симптом Причина Лечение §
все задержки не те, но пропорционально configCPU_CLOCK_HZ ≠ реальная частота привести к RCC 33
частота таймера вдвое больше удвоение такта на APB1 при делителе ≠ 1 учесть ×2 13
мигает вдвое медленнее расчёта переключение раз в 0,5 с — это период 1 с период мигания = два переключения 13
яркость прыгает на максимум при повороте энкодера влево CNT взят как положение и перешёл через ноль разность показаний со знаком, накопитель с ограничением 13
частота ЦАП/сигнала не та то же удвоение то же 15
задержки стали короче после смены тика задержки записаны числами pdMS_TO_TICKS везде 24
период задачи больше заданного vTaskDelay считает от вызова xTaskDelayUntil 26
две задачи с разными приоритетами ведут себя как равные приоритет выше максимума молча ограничен ≤ configMAX_PRIORITIES − 1 26
запас стека кажется вчетверо меньше функция возвращает слова ×4 26
vTaskList показывает приостановленной ждущую задачу вечное ожидание уведомления отчёт принимает за приостановку это норма; eTaskGetState вернёт eBlocked 26
счётчик считает меньше гонка на инкременте критическая секция 30
мьютекс: Give возвращает отказ мьютекс не был взят; у рекурсивного — отдаёт не владелец каждому Give — свой Take в той же задаче 30
остановленный таймер пошёл сам xTimerChangePeriod запускает xTimerStop следом 29
выход по маске не гаснет, когда условие пропало ждали биты группы, а сброс бита группа не сообщает ждать признак изменения, правила считать самим 31
выходы считаются по «старым» входам группу перечитали после пробуждения разбирать значение, которое вернула xEventGroupWaitBits 31
доли задач в статистике времени скачут счётчик тикает реже переключений задач DWT->CYCCNT или быстрый таймер 26
камень встаёт при создании задачи configASSERT на приоритете не меньше configMAX_PRIORITIES приоритет меньше максимума 26
прибор с зависшей задачей не перезагружается сторож кормит программный таймер без проверки: демон жив всегда кормить только при отметках всех задач 29, 12
задача опроса кнопки «залипает» xQueueSend ждёт места в полной очереди ждать 0 и считать потери 27
одно нажатие даёт несколько событий дребезг контакта три одинаковых чтения подряд 27, 8
таймер срабатывает с опозданием приоритет демона ниже занятой задачи демон на максимум 29
точнее миллисекунды не выходит разрешение — тик аппаратный таймер 29
задача просыпается по кругу без события флаг группы не сброшен на выходе clearOnExit = pdTRUE 31
флаг из прерывания ставится с задержкой через демона таймеров включить таймеры, поднять демона 31
бит 24 группы событий не работает старший байт занят ядром биты 0…23 31
задача просыпается на каждый байт триггер 0 или 1 разумный порог 32
АЦП врёт после разгона превышена ADCCLK делитель 14
показания АЦП занижены и плавают мало времени выборки увеличить SMPR 14
АЦП: читается только первый канал сканирование без DMA включить DMA 14
АЦП: погрешность на F1 нет калибровки CAL после включения 14
ЦАП не доходит до краёв выходной буфер включён это норма; либо выключить 15
ЦАП проседает под нагрузкой буфер выключен, нагрузка низкоомная включить буфер 15
сигнал ЦАП ступенчатый мало точек или нет фильтра таблица + RC 15
UART: мусор вместо текста скорость или делитель пересчитать BRR 16
SWO: мусор вместо текста частота ядра в отладчике ≠ реальной исправить в настройках 21
SWO теряет символы скорость мала для объёма поднять скорость, меньше вывода 21
SPI: сдвиг на бит неверная фаза CPHA 18
CAN: скорость не та поля тайминга не уменьшены на единицу −1 в каждом поле 19
CRC продолжает предыдущий расчёт не сброшен CRC_CR_RESET 12
таймаут сторожа впритык LSI гуляет на десятки процентов двойной запас 12
DS18B20 отдаёт ровно +85 °C прочли до конца измерения или датчик перезапустился по питанию ждать полное время измерения; 85,000 — перемерить 96
мороз превращается в тысячи градусов код DS18B20 прочитан как беззнаковый приводить к int16_t 96
DHT22 молчит короткий стартовый импульс или опрос чаще раза в 2 с 2 мс (DHT11 — 18 мс), не чаще раза в 2 с 97
DHT22 на морозе показывает тысячи градусов знак и модуль прочитаны как дополнительный код старший бит — знак 97
CRC SHT31 не сходится никогда взята функция CRC от 1-Wire полином 0x31, начало 0xFF, старшим битом вперёд 97
давление «ни о чём» при верной схеме калибровка BMP280 не прочитана или разобрана не тем порядком байт 24 байта с 0x88, младший первым 98
BME280 не даёт влажность на модуле BMP280: в регистре 0xD0 — 0x58 проверять код модели до работы 98
высота по давлению плывёт на сотни метров давление уровня моря меняется с погодой: 30 гПа — 245,1 м p0 от метеослужбы или считать от старта 98
MPU-6050 отдаёт одни нули после включения он спит записать 0 в PWR_MGMT_1 (0x6B) 99
показания ADXL345 — мусор при верной схеме разобраны старшим байтом вперёд, как у MPU-6050 у ADXL345 младший байт первым 99
угол по гироскопу уходит на десятки градусов за минуту интегрируется смещение нуля калибровать ноль в покое, корректировать акселерометром 99
расстояние HC-SR04 на морозе завышено на проценты не учтена температура: метр при 0 °C читается как 1037 мм температура в перевод эха 100
таймаут HC-SR04 срабатывает на каждом замере без URS сброс счётчика по фронту эха поднимает флаг обновления TIM_CR1_URS 100
HC-SR501 не видит сидящего человека датчик ловит движение, а не присутствие учитывать выдержку или другой датчик 100
INA219 показывает ток и мощность ноль не записан калибровочный регистр: после включения он пуст записать CAL при запуске 101
ACS712 показывает ток без нагрузки ноль взят половиной шкалы, а питание датчика не ровно 5 В: при 4,9 В — −268 мА мерить ноль без нагрузки 101
показание INA219 «замерло» при большом токе на шунте больше ±320 мВ — регистр шунта упёрся в ±32 000; бит OVF может не встать проверять регистр шунта; меньше шунт или другое усиление 101
пустые весы показывают 39 кг 24-битный код HX711 без расширения знака: −1 стал 16 777 215 расширять знак 102
после смены усиления HX711 первый отсчёт «не тот» усиление действует со следующего отсчёта первый отсчёт выбросить 102
весы изредка показывают дикие значения прерывание растянуло единицу на SCK дольше 60 мкс — HX711 уснул запрещать прерывания на пачку импульсов 102
фоторезистор показывает 0 или 4095 не свет, а обрыв или замыкание в делителе проверить делитель; крайние коды — неисправность 103
BH1750 на солнце застыл на 54 612 лк код упёрся в 65535 при MTreg 69 MTreg 31 103
сопротивление слоя MQ на треть больше делитель к АЦП стоит параллельно RL: 7,5 кОм вместо 10 считать с RL, нагруженным делителем 103
−250 °C с MAX31855 читается как 3846 °C 14-битный код без расширения знака расширять знак 104
показания MAX6675 не меняются CS опускают чаще, чем раз в 0,22 с: чтение прерывает измерение читать раз в 250 мс 104
термопара в печи показывает 1184 вместо 1200 °C линейный пересчёт MAX31855 по 41,276 мкВ/°C поправка по таблице типа K 104
кадры Ethernet уходят, но никто не отвечает тип записан младшим байтом вперёд: 0x0608 вместо 0x0806 числа в полях кадра — старшим байтом вперёд 105
прибор видит соседей, но не интернет нет шлюза или маска шире настоящей: чужой адрес ищут ARP-ом маска и шлюз как у сети 105
ARP отвечает, а ping молчит неверная сумма IP или ICMP — получатель выбрасывает пакет молча считать сумму при нуле в её поле 105
соединение TCP «живо» через 15 минут после обрыва кабеля повторы с удвоением: 924,6 с до отказа своя проверка связи 106
прибор за NAT перестал получать команды запись NAT истекла: у UDP — после 30 с тишины поддержка связи чаще тайм-аута 106
TCP упирается в сотни килобит на быстром канале маленькое окно: 2048 байт при 50 мс — 0,33 Мбит/с окно больше или время ответа меньше 106
прибор не получает адрес по DHCP не выставлен флаг «отвечать всем»: ответ ушёл на адрес, которого у прибора ещё нет флаг 0x8000 в DHCPDISCOVER 107
прибор ходит на старый адрес сервера ответ DNS держат в кэше дольше срока из записи кэш — не дольше TTL 107
TLS не проходит проверку сертификата часы прибора стоят на 2000 году: сертификат «ещё не действителен» синхронизировать часы до TLS 107
ответ из другой сети не приходит, хотя запрос маршрутизатор пропустил у получателя нет обратного маршрута: ответ ушёл его шлюзу по умолчанию маршрут обратно через тот же маршрутизатор 108
через VPN ходят мелкие пакеты, а большие пропадают MTU туннеля 1420: 1500-байтный пакет в него не влезает MTU 1420, MSS 1380 108
Wi-Fi соседа на канале 3 мешает сильнее, чем на канале 1 соседние каналы перекрываются: шаг 5 МГц при ширине 20 каналы 1, 6 или 11 108
прошивка на Ada: «cannot find entry symbol _start», образ на 0x8000 общая среда light без карты памяти камня свои crt0.S и link.ld или среда под плату 113
сборка Ada падает на предупреждениях о Last_Chance_Handler -gnatwe превращает напоминания о проверках в ошибки проверки оставить, убрать -gnatw.X 113
gnatprove без предусловия «доказал» всё взял старые результаты из того же каталога прогон в чистой копии 113
таблица векторов Rust — килобайт на пустом месте нет крейта камня: cortex-m-rt резервирует все 256 слов крейт камня с его прерываниями 114
Cargo собрал программу, но не для камня забыли --target --target thumbv7m-none-eabi или thumbv7em-none-eabihf 114
на другой машине крейт собрался иначе не закоммичен Cargo.lock Cargo.lock в репозиторий 114
PlatformIO: вчера собиралось, сегодня нет платформа не закреплена и обновилась ststm32@20.0.0 в platformio.ini 115
CMake падает на проверке компилятора для голого камня пробная сборка пытается скомпоновать программу CMAKE_TRY_COMPILE_TARGET_TYPE = STATIC_LIBRARY 115
компилятор PlatformIO оказался старым тулчейн по умолчанию у ststm32 20.0.0 — GCC 7.2.1 свой пакет в platform_packages 115
модель на плате отвечает не так, как на компьютере признаки не приведены к масштабу обучения среднее и разброс — в прошивку вместе с весами 116
k-NN не помещается в ОЗУ хранит всю обучающую выборку: 600 примеров — 4800 байт признаков порог, дерево или маленькая сеть 116
на обучающей выборке 100 %, на проверочной хуже порога модель запомнила примеры точность — только на данных, которых модель не видела 116
в спектре вибрации пик, которого в механизме нет наложение: 160 Гц при выборке 256 Гц видны как 96 Гц частота выборки с запасом и фильтр перед АЦП 117
прошивка выросла на 77 КБ от одного БПФ arm_rfft_fast_init_f32 тянет таблицы всех размеров arm_rfft_fast_init_256_f32 — под свой размер 117
подшипник то распознаётся, то нет признак «частота главного пика»: сильный тон вращения перекрывает дефект энергия в полосе частот дефекта 117
модель верна в Python на 83 %, на объекте намного хуже окна одной записи попали и в обучение, и в проверку разбивать по записям: честная оценка 75,9 % 118
дефектов почти не находит при высокой общей точности редкий класс: 21 окно из 861, модели выгодно его не замечать веса классов: 180 из 180 вместо 60 118
исправный мотор модель считает дисбалансом у крепления датчика своя чувствительность калибровка при установке: 410 → 481 из 540 118
выходы int8 на плате на единицу расходятся с TensorFlow Lite CMSIS-NN по умолчанию округляет при пересчёте дважды: совпали лишь 533 из 540 окон CMSIS_NN_USE_SINGLE_ROUNDING — все 540 бит в бит 119
после квантования модель отвечает одним классом вход квантован не масштабом и нулевой точкой входного тензора или без нормировки масштаб и нулевая точка из .tflite, нормировка как при обучении 119
сильный сигнал неотличим от очень сильного насыщение: представительная выборка не видела таких амплитуд все классы и режимы в представительной выборке 119
модель нормы не видит усилившуюся вибрацию общая норма включает все моторы: дисбаланс при пороге 1 % найден в 45 окнах из 400 своя норма прибора после установки — 400 из 400 120
ложных тревог больше, чем обещал порог порог выбран на других моторах: 49 из 1200 вместо 1 % своя норма или порог по первым часам работы 120
прибор привык к растущему дефекту база подтягивается к новым окнам переучивать базу только по команде, хранить историю оценок 120
оценка заряда уходит на старой батарее фильтр с паспортным R0 списывает лишнюю просадку на заряд: 5,6 % R0 в состоянии фильтра: 0,7 % 121
добавили в фильтр состояние — стало хуже смещение тока плохо наблюдаемо: оценено 0,085 А вместо 0,05 не добавлять состояний, которых не видит измерение 121
заряд по напряжению под нагрузкой врёт на десятки процентов измерено напряжение с просадкой I·R0 и RC-цепочки таблицу — только после покоя, под нагрузкой — фильтр 121
в версии выпущенной прошивки -dirty собрано из несохранённых правок, повторить сборку нельзя выпуск только из чистого дерева, версия из git describe 109
прошивка 1.9.3 считается новее 1.10.0 версии сравниваются как текст сравнивать по числам: major, minor, patch, коммиты после тега 109
неизвестно, какой коммит сломал сборку перебор двадцати коммитов вручную git bisect run: коммит 13 из 21 за 5 проверок 109
образ прошивки каждый раз другой внутри время сборки, пути каталога и идентификатор сборки SOURCE_DATE_EPOCH, -ffile-prefix-map, --build-id=none — тот же образ байт в байт 110
тест упал, а выпуск всё равно уехал конвейер не проверяет код возврата этап падает на любой непрошедшей проверке, артефакт не создаётся 110
сборка вдруг изменилась без правок в коде компилятор «последней версии» обновился сам версия компилятора закреплена в образе сборки 110
тайм-аут срабатывает раньше времени после долгой работы сравнение с start + timeout, который переполнился: через 8 тиков вместо 100 (uint32_t)(now - start) >= timeout 122
проверка ~x == 0xF0 для uint8_t всегда ложна продвижение до int: ~0x0F — это -16 (uint8_t)~x == 0xF0 122
на компьютере сравнение верно, на плате — нет разная модель данных: (long)-1 < 1u даёт 1 на x86-64 и 0 на Cortex-M типы из stdint.h, явные приведения, _Static_assert 122
работает с -O0, ломается с -O2 неопределённое поведение: переполнение знакового, строгий псевдоним сборка с ловушками UB и -Wall; биты через memcpy 123
проверка переполнения исчезла в выпускной сборке проверка после операции: x + 1 > x компилятор заменил на 1 проверять до операции или __builtin_add_overflow 123
HardFault на команде UDF в отладочной прошивке сработала ловушка неопределённого поведения адрес в кадре исключения — строка с ошибкой 123
цикл ожидания флага из прерывания не ждёт или висит флаг без volatile: armclang превратил ожидание в BX lr volatile на флаге 124
счётчик событий из прерывания иногда отстаёт events++ — LDR, ADDS, STR, прерывание между ними atomic_fetch_add (LDREX/STREX) или критическая секция 124
таблицы съели ОЗУ без const таблица копируется из флеш-памяти в .data const — таблица остаётся во флеш-памяти 124
HardFault при вызове обработчика из таблицы нулевой указатель или таблица в ОЗУ испорчена записью за границу проверка индекса и указателя, таблица с const — во флеш-памяти 125
команда из таблицы не находится, хотя есть таблица для bsearch не отсортирована по имени тест порядка таблицы на компьютере 125
HardFault на Cortex-M0 при разборе пакета (uint32_t )(buf + 1) — невыровненный доступ memcpy или побайтный разбор: компилятор сам выберет LDRB 126
получатель видит мусор в пакете отправлена структура с байтами заполнения сериализовать поля побайтно 126
числа от датчика перевёрнуты датчик отдаёт старшим байтом вперёд, Cortex-M хранит младшим побайтный разбор с явным порядком или REV 126
сообщение об ошибке — от соседнего кода перечисление и таблица текстов написаны порознь X-макрос из одного списка или _Static_assert на длину таблицы 127
мусор в терминале после смены частоты шины делитель UART не пересчитан, ошибка скорости больше 2 % проверка делителя в #if с #error при сборке 127
задача портит чужую память при длинном пакете массив переменной длины на стеке: размер взят из пакета -Wvla, массив наибольшего размера с проверкой длины 128
сбой после длинного пакета, возврат из функции в никуда memcpy в локальный буфер без проверки длины затёр кадр стека проверка длины до копирования, -fstack-protector-strong 129
автомат состояний застыл после сбоя испорченная переменная состояния, у switch нет default default — переход в безопасное состояние 129
на G0 прерывание по спаду зациклилось флаг сбрасывают в PR, как у F4, а у G0 спад отмечается в FPR1, фронт — в RPR1 сбрасывать записью единицы в FPR1 или RPR1 7
на G0 кнопка всегда «нажата», IDR читает ноль после сброса выводы G0 аналоговые (MODER = 11), цифровой вход выключен перевести вывод во вход: MODER = 00 8
код для F0 не собирается на G0: неизвестна GPIO_MODER_MODER5 заголовок G0 называет биты по-новому (MODE5, BS5, ID0) маски по номеру вывода или функции LL 8
на G0 не переключается на PLL, хотя PLLRDY есть выход R не разрешён битом PLLREN ставить PLLREN вместе с делителями в PLLCFGR 6
на F0 или G0 UART после первого переполнения замолчал флаг ORE сам не сбрасывается, как у F1 чтением SR и DR сбрасывать записью USART_ICR_ORECF в ICR 16
после обновления сервера пропали показания приборов данные писались внутрь контейнера, а не в том всё, что должно пережить контейнер, — в volumes; down -v — только с копией 111
в журнале приёмника у всех приборов один адрес это адрес обратного прокси прокси ставит X-Real-IP, приёмник берёт адрес из него 111
прокси отвечает 502 сразу после запуска стенда приёмник ещё не готов, прокси стартовал раньше healthcheck и condition: service_healthy 111
диск сервера заполнился журналами контейнеров у драйвера json-file нет ограничения размера max-size и max-file в logging 112
упал приёмник телеметрии, а оповещений нет правила только о приборах: без метрик они молчат правило up == 0 о самом приёмнике, канал оповещений — отдельный сервис 112
дежурного будят одиночные выбросы датчика в правиле оповещения нет for условие должно держаться заданное время 112
русские имена файлов — мусор нет FF_USE_LFN, кодовая страница или строки UTF-8 при FF_LFN_UNICODE = 0 включить, FF_CODE_PAGE, FF_LFN_UNICODE = 2 42
медленная запись на флеш через FatFS сектор 512 → чтение-стирание-запись буферизовать, крупнее блок 42
статистика: printf перестал работать форматирующие функции требуют стек больше стека или выключить 33
строка до fork напечаталась дважды буфер stdout скопирован в потомка fflush(NULL) перед fork 136
read вернул −1 без видимой причины EINTR: сигнал прервал вызов повторить или SA_RESTART 136
read из канала никогда не возвращает 0 пишущий конец открыт в самом читателе закрыть его после fork 137
syslog ничего не пишет нет /dev/log в контейнере или минимальной системе LOG_PERROR или свой файл 138
read вернул −1 на неблокирующем сокете EAGAIN — «пока нечего», не ошибка ждать готовности через poll/epoll 141
epoll с EPOLLET пропускает данные не дочитали до EAGAIN читать до EAGAIN 141
тысяча вставок в SQLite — секунды автокоммит на каждую BEGIN … COMMIT пачкой 148
«код × 0,806 мВ» на ESP32 врёт на сотни милливольт опора не 3,3 В, прямая не через ноль adc_cali_raw_to_voltage с калибровкой 154
ledc_set_duty ничего не меняет скважность применяется отдельным вызовом добавить ledc_update_duty 153
fopen("/fat/лог.txt") вернул NULL длинные имена FAT выключены, только 8.3 включить LFN в menuconfig или имена 8.3 155
файлы в SPIFFS занимают втрое больше, чем данные страница 256 байт и индекс на каждый файл крупные файлы или FAT 155
printf("%.2f") печатает пустоту в newlib-nano (--specs=nano.specs) вывод float выключен ради размера ключ -u _printf_float (+13 КБ кода) или печатать целыми частями 4б

36.6 Работает иногда

Самый неприятный класс. Общее правило: «иногда» — чаще всего гонка, тайминг или память. Из аппаратных причин — длинные провода, питание и земля: их смотрят осциллографом, а не отладчиком.

Пять примет перемежающегося сбоя и их обычные причины: только с отладчиком — гонка, при оптимизации минус O2 — нет volatile или неопределённое поведение, через час — обычная функция ядра из прерывания, через неделю — утечка памяти, на столе работает а в корпусе сбоит — провода, питание и земля, которые смотрят осциллографом

Симптом Причина Лечение §
работает только с отладчиком гонка: под отладчиком тайминг другой volatile, секции, ожидание флагов 3, 16
работает при -O0, ломается при -O2 нет volatile или гонка не «ошибка компилятора» 3, 30
через час — порча данных или зависание обычная функция ядра из прерывания только FromISR 28
прибор падает через неделю утечка памяти следить за худшим остатком кучи 25
память тает при создании и удалении задач задача простоя не получает процессор дать ей время 26
задачи создаются, потом перестают кончилась куча xPortGetMinimumEverFreeHeapSize 25
свободно много, выделить нельзя фрагментация heap_4, реже создавать-удалять 25
высокоприоритетная задача тормозит без причины инверсия приоритетов мьютекс, держать коротко 30
задача пропускает события двоичный семафор при частых событиях считающий или очередь 28
реакция задачи запаздывает на миллисекунду забыт portYIELD_FROM_ISR добавить 28
критическая секция не защищает переменную переменную трогает быстрое прерывание другая защита или ниже порога 28, 30
приём по UART теряет байты при работе с дисплеем длинная критическая секция мьютекс или привратник 30
байты с UART теряются под нагрузкой буфер полон больше буфер, выше приоритет читателя 32
данные в буфере портятся два писателя или два читателя правило одного 32
теряются значения уведомления хранит одно очередь 31
дребезг даёт десяток прерываний механика кнопки подавление дребезга 7
UART: первый байт теряется приёмник включён позже передатчика порядок включения 16
UART: приём молчит после потока не сброшен ORE читать SR, затем DR 16
UART: обрезается конец посылки ждали TXE вместо TC TC перед сном 16
SPI: данные обрезаются на скорости CS снят до сброса BSY ждать BSY 18
USB: работает на одном компьютере, не на другом подтяжка или качество линий резистор; кабель 20
USB: пропадает после сна требует активности обработка пробуждения 20
USB: данные теряются при быстрой отправке хост опрашивает по расписанию буфер и отправка по готовности 20
команда по USB CDC не узнаётся пакет сравнивали с командой, а она пришла кусками кольцевой буфер и сборка строк в цикле 20
двоичные данные по CDC обрезаются strncpy остановилась на нулевом байте копировать байты, а не строки 20
ответ по CDC испорчен буфер изменили до конца передачи отдельный буфер, отправка после USBD_OK 20
SPI флеш работает через раз на макетке длинные провода на 20 МГц снизить скорость, короче провода 41
I²C виснет навсегда нет таймаутов; отвалившийся провод таймауты везде 17
стек кончается на printf сотни байт под форматирование запас или отказ от printf 26
переполнение стека в демоне таймеров printf или массив в обратном вызове не делать этого там 29
файл нулевой длины после отключения нет f_close/f_sync f_sync после записи 42
время RTC на F1 изредка прыгает на 18 часов счётчик прочитан половинами без повтора — младшая перешла через 0xFFFF между чтениями перечитать старшую половину и повторить 12
счётчик из потоков не сходится, каждый раз по-разному гонка: ++ не атомарен, volatile не помогает мьютекс или atomic_fetch_add 139
счётчик в общей памяти считает неверно нет семафора между процессами семафор POSIX или XSI 137
сигнал «потерялся» обычные сигналы не ставятся в очередь блокировать маской, а не терять 136
счётчик из двух задач ESP32 не сходится, хотя есть мьютекс второе ядро: мьютекс не защищает от него спин-блокировка portMUX_TYPE или __atomic_* 152
тактовый вход на длинном проводе ловит лишние фронты звон несогласованной линии: волна удваивается на конце и отражается последовательный резистор у вывода до волнового сопротивления линии 160
I²C работает на столе, сбоит на проводах в корпусе ёмкость проводов затягивает фронт R·C за предел режима меньше подтяжка, короче провода, стандартный режим или усилитель шины 160

36.7 Зависает

Симптом Причина Лечение §
зависает, но не совсем: часть работает высокоприоритетная задача без ожидания добавить блокировку 26
живой, но ничего не делает взаимная блокировка двух мьютексов единый порядок захвата 30
зависла на xSemaphoreTake своего мьютекса взяла дважды разобрать вызовы; рекурсивный 30
все программные таймеры встали разом обратный вызов заблокировался ноль ожидания в обратных вызовах 29
зависает без отладчика SWO ждёт готовности при выключенном модуле проверка ITM_TCR_ITMENA 21
зависает на ожидании готовности RCC кварц не запустился, таймаута нет таймаут; проверить кварц 6
обработчик ждёт на семафоре ждать в прерывании нельзя TakeFromISR без ожидания 28
xTimerStart возвращает отказ очередь команд полна или демон стоит см. «все таймеры встали» 29
синхронизация задач зависает SetBits + WaitBits вместо Sync xEventGroupSync 31
xMessageBufferReceive вечно ноль приёмник меньше сообщения, оно застряло приёмник ≥ максимального кадра 32
Reset буфера — отказ кто-то ждёт остановить читателя 32
стирание флеш «зависло» сотни миллисекунд — это норма ждать BUSY с таймаутом 41
прибор не спит в режиме без тика задача просыпается чаще двух тиков найти её 33
режим без тика включён, а ток не упал configPRE_SLEEP_PROCESSING обнуляет аргумент до вызова своей функции передавать время как есть или засыпать в функции самим 33
после vTaskSuspend задача мертва выводит только vTaskResume не путать с ожиданием 26
open FIFO на чтение висит нет ни одного писателя O_NONBLOCK или открыть на запись самому 137
cond_wait — вечный сон вызван без захваченного мьютекса или без цикла проверки условия while (!ready) cond_wait под мьютексом 139
cat /dev/ringdev не завершается read драйвера не возвращает 0 при пустом буфере вернуть 0 — конец файла 147
Task watchdog got triggered … IDLE1 задача на ядре 1 не уступала процессор дольше 5 с vTaskDelay в цикле или подписка на сторожа 152
Interrupt wdt timeout on CPU0 прерывания выключены дольше 300 мс: затянутая критическая секция сократить секцию 152

36.8 Память и HardFault

Симптом Причина Лечение §
PC в мусоре, UNDEFINSTR стек затёр адрес возврата измерить стек; ловушка 35, 26
PRECISERR, BFAR — маленькое число нулевой указатель со смещением искать NULL 35
IMPRECISERR, PC не туда запись ушла в буфер шины DISDEFWBUF на время отладки 35
UNALIGNED uint32_t * на байтовый буфер memcpy или упаковка 35, 3
HardFault в обработчике с приоритетом 0 обработчик выше системного зовёт ядро приоритет ≥ порога 7, 28
буфер DMA «не заполняется» на F4 буфер в CCM, DMA туда не ходит обычная SRAM 9, 41
DMA портит стек локальный буфер исчез вместе с кадром статический буфер 9
данные от DMA не меняются в коде нет volatile добавить 9, 14
порча при heap_5 области не по возрастанию адресов упорядочить 25
статический буфер потока портит соседа массив N вместо N + 1 + 1 32
FATFS объявлена локально структура должна жить всё время статическая 42
переполнение стека на буфере сектора 4 КБ локально статический буфер 42
буфер под DMA не выровнен 16/32-разрядный элемент по нечётному адресу __attribute__((aligned)) 9, 42
флеш: записали, а прочитали не то запись без стирания: 1→0 только стереть сектор 41
флеш умерла через месяц 100 000 циклов на сектор; журнал в один сектор ротация секторов 41
незакреплённые WP#/HOLD# ловят наводки подтянуть к питанию 41
настройки пропали после выключения посреди сохранения страницу стёрли, а записать не успели журнал на двух страницах 11
после обновления прошивки настройки «съехали» сменилась раскладка структуры поле версии, при несовпадении — умолчания 11
запись настроек обрывается ошибкой на середине блок больше страницы: соседняя не стёрта запись не больше страницы или журнал 11
прерывания запаздывают на десятки мс при сохранении стирание Flash останавливает выборку команд (F1, один банк) сохранять в спокойный момент; срочный обработчик в ОЗУ 11
Guru Meditation (Cache disabled but cached memory region accessed) при записи в NVS или обновлении обработчик с флагом ESP_INTR_FLAG_IRAM зовёт функцию без IRAM_ATTR или читает константу без DRAM_ATTR, а кэш на время записи выключен; обычные обработчики в это время просто ждут всё, что трогает такой обработчик, — в IRAM_ATTR и DRAM_ATTR, либо снять флаг ESP_INTR_FLAG_IRAM 150
malloc на 200 КБ вернул NULL при 300 КБ свободных куча ESP32 из банков, самый большой цельный кусок меньше дробить буфер или MALLOC_CAP_* 150
HardFault сразу после вызова по указателю на функцию чётный адрес перехода: CFSR = 0x00020000 (INVSTATE) брать адрес функции, а не число; разбирать CFSR, HFSR и PC в кадре исключения 4б

Разбор HardFault по регистрам: бит HFSR, поле CFSR, взведённый бит с маской и что он обычно значит, с номером раздела


36.9 Питание и сон

Симптом Причина Лечение §
после Stop всё медленное тактирование не восстановлено: HSI вместо PLL восстановить PLL после пробуждения 10
ток в сне выше расчётного выводы в неопределённом состоянии аналоговый режим или подтяжка 10
ток сна на десятки мкА выше подтяжка ~40 кОм на выводе, прижатом снаружи к земле снять подтяжку или перевернуть логику 10
ток в Sleep не падает периферия включена выключать перед сном 10, 33
ток в Stop как в Sleep отладчик оставил биты DBG_STOP в DBGMCU->CR; сброс их не снимает снять биты или выключить и включить питание 10
при пробуждении камень сбрасывается, пока в питании амперметр предел 200 мкА — шунт 1 кОм, питание падает ниже 2 В перемычка параллельно прибору 10
показания мультиметра прыгают в десятки раз усредняет за доли секунды, всплески попадают через раз мерить сон и всплеск отдельно, среднее считать 10
программатор не видит камень после подготовки ко сну в аналоговый режим ушли PA13 и PA14 оставлять SWD в маске; прошить с подключением под сбросом 10
спит, но недолго (≤ 233 мс) предел SysTick ядро на меньшей частоте всё время или свой таймер сна 33
проснулся — время уплыло своя функция сна без vTaskStepTick скорректировать 33
слишком частое пробуждение съедает выгоду выход из Stop/Standby не бесплатен реже просыпаться 10
кормление сторожа из прерывания прерывание живо, программа мертва — сторож молчит кормить из основного цикла 12
флаги причины сброса врут не очищены RMVF после чтения 12
причина сброса всегда «кнопка» PINRSTF стоит почти при любом сбросе проверять его последним 12
WWDG сбрасывает сразу после запуска счётчик 0x40 — до сброса один тик запускать с 0x7F 12
WWDG сбрасывает при кормлении кормят раньше, чем счётчик опустился до окна W кормить внутри окна 12
будильник RTC будит один раз не сброшен флаг будильника (ALRAF, у F1 — ALRF): нового фронта на EXTI 17 нет сбрасывать флаг в обработчике 12
обработчик будильника RTC вызывается без конца не сброшен флаг линии EXTI 17 EXTI->PR = EXTI_PR_PR17 12
будильник F4 не записывается не сняты ключи WPR или не дождались ALRAWF 0xCA, 0x53, затем ждать ALRAWF 12
шум в АЦП/ЦАП земля, питание, опора разводка; фильтр; VDDA 14, 15
электронная нагрузка не опускается до нуля включён выходной буфер ЦАП BOFF1: вход ОУ высокоомный 15
опора АЦП «плавает» VDDA от USB через диод стабилизатор или внешняя опора 14
показания АЦП плывут вместе с батареей опора — VDDA, а считали от 3,3 В пересчёт через VREFINT 14
внутренние каналы АЦП дают ноль не включён TSVREFE CR2 у F1, ADC->CCR у F4 14
переменная RTC_DATA_ATTR обнулилась после esp_restart она переживает только глубокий сон, программный сброс загрузчик заливает заново для сброса — RTC_NOINIT_ATTR и обнуление по ESP_RST_POWERON 157
ESP32 после глубокого сна начинает с app_main выход из глубокого сна — это сброс хранить состояние в памяти RTC, смотреть esp_sleep_get_wakeup_cause() 157
датчик на ESP32 сажает батарею за недели на каждом пробуждении долгое подключение к Wi-Fi: 2 с радио дороже суток сна просыпаться реже, статический IP, канал роутера — в памяти RTC 157
ESP32 перезагружается, как только включает передатчик провал шины 3,3 В на пике 240 мА: мало ёмкости у модуля, длинный кабель 10 мкФ и 100 мкФ и больше у модуля, стабилизатор с малым падением, короткий кабель 161

36.10 Аппаратные

Симптом Причина Лечение §
DRC: замыкание у корпуса микроконтроллера дорожка от развязки идёт наискосок через соседние выводы конденсатор по нормали к ряду выводов, ближним выводом к VDD 130, 131
кварц не запускается на холодную конденсаторы не под CL своего кварца C1 = C2 = 2 × (CL − Cпар) 130
дорожка питания греется ширина не по току, особенно на внутреннем слое ширина по IPC-2221: 1 А при 10 °C — 0,30 мм снаружи, 0,78 мм внутри 130
DRC в сборке падает, хотя нарушений нет --exit-code-violations считает и неразведённые соединения ставить ключ, когда плата разведена целиком 131
плагин DipTrace отработал, а плата не изменилась файл обмена не перезаписан: DipTrace смотрит только на его изменение, код возврата не читает переписать тот же plugin_exchange.xml заменой целиком 132
объект, удалённый плагином DipTrace, остался на плате узел вычеркнут из XML ставить Enabled="N" 132
расстояния в дюймовом файле обмена плывут в третьем знаке четыре знака в дюймах — шаг 2,54 мкм считать с допуском в пару микрометров 132
configparser: «File contains no section headers» на проекте Altium .PrjPcb начинается с метки порядка байтов UTF-8 читать в кодировке utf-8-sig 133
скрипт KiCad не открывает плату Altium, LoadBoard вернул пустое формат по файлу не угадывается указать PCB_IO_MGR.ALTIUM_DESIGNER 133
после импорта из Altium классы цепей — 0,2 мм вместо 0,1 в классы попали настройки KiCad, а не правила Altium задать классы цепей заново 133
KiCad не открывает свой же IPC-2581 или ODB++ эти форматы KiCad только пишет переносить проектом или списком соединений 134
после импорта списка соединений у деталей нет корпусов имена посадочных мест в программах разные сопоставить корпуса по именам, остальные — руками 134
механик получил плату без деталей к деталям не привязаны 3D-модели привязать модели до выгрузки STEP 134
кварц не той частоты 8 МГц на плате, 25 в проекте привести в соответствие 6
система осталась на HSI проверен SW, а не SWS ждать SWS 6
пропал HSE — прибор встал нет CSS включить, обработать NMI 6
UART: линии перепутаны TX на TX TX → RX 16
кириллица в терминале кодировка терминала UTF-8 с обеих сторон 16
I²C: адрес не тот 0x68 против 0xD0 формат 7 бит со сдвигом 17
I²C: ADDR не сбрасывается прочитан только SR1 SR1, затем SR2 17
I²C: с одним модулем работает, с несколькими — нет подтяжки модулей складываются: пять по 4,7 кОм — 940 Ом, больше 3 мА оставить подтяжки на одном модуле 17, 95
I²C: на столе работает, на проводе сбоит ёмкость провода растягивает фронт: на 400 кГц с 2,2 кОм — 1,71 м ниже скорость, пересчитать подтяжку, буфер 17, 95
нет общей земли датчик на своей плате соединить 17, 19, 95
вход сбоит или греется с модулем на 5 В модуль подтягивает шину к 5 В снять подтяжки модуля или преобразователь уровней 62, 95
термистор показывает −40 или +125 и не меняется обрыв или замыкание делителя: код за краем таблицы проверять выход за таблицу, не выдавать за температуру 96
SPI: мусор при нескольких устройствах два CS активны подтяжки на все CS 18
SPI: дисплей работает, флешка нет разные режимы на одной шине переключать режим 18
SD-карта молчит на CMD0 неверный CRC7, мало тактов перед командой или скорость выше 400 кГц CMD0 — 0x40 00 00 00 00 95, 74 такта, делитель 256 18
на выходах 74HC595 байты перепутаны отправлены в прямом порядке первым — байт дальнего регистра 18
SWO на F407 выводит мусор в отладчике частота кварца 8 МГц вместо 168 МГц ядра частота ядра в настройках, ACPR = 83 для 2 МГц 21
SWO теряет символы и тормозит программу по байту линия 2 МГц пропускает 100 000 символов в секунду писать словами — 160 000, выводить меньше 21
на клавиатуре нажата лишняя кнопка три кнопки в углах прямоугольника без диодов: 144 тройки из 560 диод на каждую кнопку 22
общий вывод разряда индикатора греется восемь сегментов по 8 мА — 64 мА через один вывод ключ разряда — транзистор 22
CAN без трансивера прямое подключение трансивер обязателен 19
CAN: терминаторы не два по 120 на концах ровно два, на концах 19
USB: определяется как неизвестное дескрипторы анализатор протокола 20
USB: кабель без экрана, тонкий другой кабель 20
SPI флеш: режим 0 или 3, не 1 и 2 CPOL=CPHA 41
ток утекает через висящий вход вход без подтяжки подтянуть 8, 10
ключ реле выгорает, ESP32 сбрасывается при выключении реле нет диода на катушке: выброс до пробоя ключа диод параллельно катушке катодом к питанию, у дальних нагрузок — TVS 161
MOSFET от вывода ESP32 греется, реле щёлкает неуверенно транзистор не логический: от 3,3 В открыт не полностью транзистор с низким порогом или NPN с резистором базы 161

36.11 Связь и радио

Симптом Причина Лечение §
модуль Wi-Fi отвечает ERROR на всё не та скорость UART или прошлая команда не завершена скорость; дождаться ответа 37
разборщик ответов модуля путается незапрошенное сообщение пришло между командой и ответом разбирать каждую строку по её началу 37
брокер отключает раз в полторы минуты нет PINGREQ чаще keep-alive посылать по таймеру 37
CONNACK с кодом 5 не авторизован: чужой или пустой токен свой токен у каждого прибора 37, 91
соединение с брокером молча рвётся роутер удалил запись NAT, пока не было трафика keep-alive 86
сервер не может достучаться до прибора прибор за NAT прибор подключается сам 86
после переезда сервера все приборы молчат в прошивке адрес, а не имя имя в настройках, меняемых по воздуху 87, 91
сервер не может подняться после сбоя все приборы повторяют запросы разом растущая задержка со случайным разбросом 88
в базе дубликаты измерений повтор POST после обрыва PUT по номеру или ключ запроса 88
тело запроса обрезано на кириллице Content-Length в символах длина в байтах 88
балансировщик шлёт всё на один сервер нет общей зоны у группы серверов zone в upstream 88
RS-485 теряет последний байт передатчик выключен по TXE выключать по TC 89
Modbus: ошибка CRC байты CRC переставлены CRC младшим байтом вперёд 89
сервер CoAP выполнил команду дважды повтор отправлен с новым номером сообщения при повторе номер тот же 89
Zigbee теряет пакеты рядом с Wi-Fi канал перекрывается с Wi-Fi каналы 15, 20, 25, 26 89
прибор LoRaWAN замолкает на минуты на SF12 кончилась доля эфира 1 % реже слать, меньше SF 89, 93
SX1276: RegVersion читается как 0x00 или 0xFF провода, режим SPI, NSS проверять по порядку 93
SX1276 не передаёт, хотя регистры записаны бит LoRa записан не во сне сон → LoRa → ожидание 93
SX1276 на чужой частоте Frf посчитан в 32 битах считать в uint64_t 93
пакеты LoRa не доходят, ошибок нет разные SF, полоса или слово синхронизации сверить параметры на обеих сторонах 93
сетевой сервер молча не видит прибор адрес или ключ в другом порядке байт в кадре — младшим байтом вперёд 94
прибор ABP замолчал после перезагрузки счётчик кадров начался с нуля хранить счётчик в энергонезависимой памяти 94
команды до прибора класса A не доходят окно RX1 открыто поздно таймер от события «передача окончена» 94
молчание прибора не понять нет контрольной посылки посылка «я жив» раз в заданное время 90
карта покрытия врёт в модели потерь нет стен стены в модели, план с материалами 92
ESP32: esp_netif запущен, а адреса нет не создан цикл событий или не инициализирована NVS nvs_flash_init() и esp_event_loop_create_default() до драйвера сети 156
ESP32 не соединяется с Mosquitto 2 без listener 1883 и allow_anonymous брокер пускает только localhost прописать listener и учётные данные клиента 156
в журнале ESP32 даты 1970 года SNTP ещё не синхронизировался, часов с батарейкой нет ждать esp_netif_sntp_sync_wait с тайм-аутом, журналы вести в UTC 156
ESP32 не виден в сканере BLE после отключения телефона реклама не перезапускается по событию разрыва запускать рекламу снова в обработчике BLE_GAP_EVENT_DISCONNECT 158
по BLE приходят только первые 20 байт MTU по умолчанию 23, заголовок 3 байта обмен MTU или передача кусками 158

36.12 Если ничего не подошло

Строки, которых нет в таблице, — это новые грабли, и они тоже чему-то учат. Порядок:

  1. Свести к минимуму — проект из десяти строк.
  2. Прочитать регистры — все, что относятся к блоку, в отладчике.
  3. Сравнить с известным рабочим — пример из пака, чужая плата, другой камень.
  4. Осциллограф на линию — то, что на проводе, а не то, что должно быть.
  5. Записать — симптом, причину, лечение. Через год это сэкономит день.

36.13 Итоги

Дальше: раздел 36а «Приборы на столе» — мультиметр, осциллограф и логический анализатор: чем смотреть то, чего не видит отладчик.

Открыть в интерактивном справочнике