Вопросы на собеседовании: Embedded-инженер
100 реальных вопросов с образцовыми ответами и пояснениями для уровня Junior Embedded-инженер.
Смотреть пример резюме: Embedded-инженер →Тренировка флешкарточками
Интервальное повторение · Hunter Pass
Вопросы
Это микроконтроллер, потому что процессорное ядро, память и аппаратная периферия объединены в одной микросхеме.
- Ядро Cortex-M3 выбирает и выполняет инструкции прошивки, хранящиеся в 64 КБ flash.
- В 20 КБ SRAM при включенном питании находятся изменяемые данные, например стек, глобальные переменные и коммуникационные буферы.
- Встроенные GPIO, таймеры, ADC, UART, I2C и SPI позволяют прошивке управлять аппаратурой без отдельных микросхем-контроллеров.
- Частота ядра 72 МГц задает верхний темп выполнения инструкций, но периферия может работать медленнее из-за собственных частот и делителей шин.
Зачем это спрашивают: Интервьюер проверяет, отличаете ли вы процессорное ядро Cortex-M от построенного вокруг него полноценного MCU.
Memory-mapped I/O означает, что обычная на вид операция загрузки или записи обращается по этому адресу к аппаратной периферии, а не к RAM.
- Для 32-разрядного регистра по адресу 0x41004410 прошивка должна использовать определение из заголовка производителя или volatile-указатель на uint32_t.
- Запись меняет аппаратные биты GPIO, поэтому значение может управлять физическими выводами, а не храниться как обычная память.
- Перед обращением нужно включить тактирование GPIO, иначе запись может не дать эффекта или вызвать ошибку шины.
- Справочное руководство определяет доступные для записи и зарезервированные биты, поэтому прошивка должна сохранять поля, которыми не управляет.
Зачем это спрашивают: Интервьюеру важно увидеть, что вы связываете обращение к регистру из C с реальной периферией и ее ограничениями.
Сначала ядро читает векторы через загрузочный alias 0x00000000, который STM32 может сопоставить с flash по физическому адресу 0x08000000.
- Первое слово по адресу alias аппаратно загружается в MSP до выполнения первой программной инструкции.
- Второе слово загружается как адрес обработчика сброса, причем бит 0 должен задавать состояние Thumb.
- Загрузочные выводы, option bytes и remap определяют, какая физическая память видна по адресу 0x00000000, поэтому начальное чтение не обязано идти прямо с 0x08000000.
- Затем обработчик сброса инициализирует память и частоты перед main, а позже прошивка может перенести таблицу через VTOR.
Зачем это спрашивают: Интервьюер проверяет, отличаете ли вы загрузочный alias Cortex-M от физического адреса flash STM32.
Прошивка должна настроить и стабилизировать источники частоты, прежде чем выбрать выход PLL на 72 МГц системной частотой.
- Включить внешний генератор 8 МГц и дождаться его флага готовности, а не считать, что он запускается мгновенно.
- Настроить множитель PLL на 8 МГц умножить на 9 и делители APB так, чтобы ни одна шина периферии не превысила допустимую частоту.
- До повышения частоты ядра установить нужное для 72 МГц число тактов ожидания flash, иначе выборка инструкций может нарушиться.
- Переключить источник системной частоты на PLL и по статусным битам проверить, что выбран нужный источник.
Зачем это спрашивают: Интервьюер проверяет знание того, что настройка частот выполняется в определенном порядке и учитывает ограничения flash и шин.
Я бы включил тактирование порта C, настроил только PC13 как выход и управлял светодиодом через регистр установки и сброса GPIO.
- Сначала нужно включить тактирование порта C и по справочному руководству найти конфигурационное поле PC13.
- Затем очистить только четыре бита этого поля и выбрать двухтактный выход с невысокой скоростью, достаточной для светодиода.
- Запись в половину сброса BSRR для PC13 включает светодиод, а запись в половину установки выключает его.
- BSRR меняет один вывод без read-modify-write, способной затереть одновременное изменение других битов порта.
Зачем это спрашивают: Интервьюер проверяет безопасную точечную работу с регистрами и понимание схемы, где светодиод включается низким уровнем.
Нет, volatile делает обращения наблюдаемыми для компилятора, но не придает атомарность и не синхронизирует последовательность проверки и очистки.
- Volatile не дает компилятору постоянно держать флаг в регистре или удалить обращения к значению, которое меняется вне обычного потока выполнения.
- Обработчик может установить флаг между чтением и очисткой в основном цикле, из-за чего одно событие таймера потеряется.
- Отдельная выровненная 32-разрядная загрузка или запись на этом ядре атомарна, но последовательность из двух операций атомарной не является.
- Нужна короткая критическая секция, поддерживаемый компилятором атомарный примитив или счетчик с явно безопасной схемой передачи.
Зачем это спрашивают: Интервьюер проверяет ключевое ограничение: volatile не обеспечивает ни атомарность, ни синхронизацию.
Я бы очистил трехбитное поле маской, а затем вставил значение 101, сдвинутое в биты с 4 по 6.
- Маска поля равна 0x7 со сдвигом влево на 4 и покрывает ровно биты 4, 5 и 6.
- Один раз прочитать регистр, выполнить value &= ~mask, затем value |= (0x5 << 4) & mask.
- Записать собранное значение обратно через volatile-определение 32-разрядного регистра от производителя.
- Если аппаратура имеет отдельные регистры установки и очистки, при наличии одновременных писателей лучше использовать их вместо небезопасной read-modify-write.
Зачем это спрашивают: Интервьюер проверяет, умеете ли вы менять многобитное поле, не повреждая несвязанные состояния аппаратуры.
Я бы хранил каждый отсчет в uint16_t, а сумму 1000 отсчетов накапливал в uint32_t.
- Двенадцать бит помещаются в uint16_t, тогда как uint8_t обрежет значения выше 255.
- Максимальная сумма равна 4 095 000, что превышает максимум uint16_t, равный 65 535.
- Аккумулятор uint32_t безопасно вмещает этот максимум и позволяет затем вычислить целочисленное среднее.
- Типы фиксированной ширины явно закрепляют предположения о размере и диапазоне между компиляторами и семействами MCU.
Зачем это спрашивают: Интервьюер оценивает, выбираете ли вы ширину целого типа по реальному диапазону, а не по привычке.
Надежнее использовать аппаратный таймер, потому что у пустого цикла нет стабильной длительности в один такт на итерацию.
- Реальное число тактов определяют инструкции, переходы, такты ожидания flash и работа конвейера, а не только частота 48 МГц.
- Оптимизация компилятора может сократить, переставить или полностью удалить пустой цикл задержки.
- Прерывания могут приостановить цикл и непредсказуемо растянуть 10-микросекундный импульс.
- Сравнение таймера или канал output compare отсчитывает такты периферии и может переключить вывод на заданном значении счетчика.
Зачем это спрашивают: Интервьюеру важно увидеть, что вы переводите частоту во время, но понимаете ненадежность программных циклов задержки.
Регистр должен иметь тип uint32_t, потому что его аппаратная ширина всегда равна 32 битам независимо от модели данных компилятора.
- Тип uint32_t при наличии занимает 32 бита, тогда как unsigned long на разных платформах бывает 32- или 64-разрядным.
- Volatile-обращение неверной ширины может затронуть соседние адреса или породить неподдерживаемую транзакцию на шине.
- Битовые маски вроде UINT32_C(1) << 31 тогда имеют известную ширину и предсказуемое поведение.
- Статическая проверка размера типа регистра может рано обнаружить неподходящую конфигурацию сборки.
Зачем это спрашивают: Интервьюер проверяет понимание того, что размеры типов C нужно явно согласовывать с шириной аппаратных регистров.
Я бы не использовал здесь неограниченную кучу и сначала рассчитал полный бюджет RAM для худшего случая.
- Статическая память вместе с запланированным стеком уже занимает 20 КБ, оставляя 12 КБ до учета библиотек и стека прерываний.
- Выделение 6 КБ оставляет мало запаса и может завершиться ошибкой или фрагментацией после разных последовательностей выделения.
- Фиксированная рабочая область на 6 КБ с явным владельцем дает детерминированный расход памяти, если одновременно собирается только один пакет.
- Оставшийся запас нужно подтвердить по карте линкера и измерению максимального использования стека, а не по номинальным 32 КБ.
Зачем это спрашивают: Интервьюер оценивает, принимаете ли вы решения о стеке, статической памяти и куче на основе ограниченного бюджета RAM.
Внутри функции buffer является указателем, поэтому sizeof возвращает размер указателя, а не исходного массива на 64 байта.
- При передаче в функцию аргумент-массив преобразуется в параметр-указатель.
- На 32-разрядном Cortex-M sizeof(buffer) обычно равен 4, а не 64.
- Нужно явно передавать емкость, например указатель вместе с length типа size_t, и проверять по ней все индексы.
- Если функция действительно требует ровно 64 байта, интерфейс может использовать тип-обертку, который сохраняет контракт размера.
Зачем это спрашивают: Интервьюер проверяет понимание преобразования массива в указатель и безопасных интерфейсов для буферов.
После возврата из функции настройки сохраненный указатель становится недействительным, потому что время жизни локального буфера закончилось.
- Те же байты стека могут быть повторно использованы другой функцией до запуска callback через 5 мс.
- Чтение через устаревший указатель дает неопределенное поведение и может случайно работать только в некоторых сборках.
- Буферу нужно дать статическое время жизни, разместить его в объекте с более долгой жизнью или скопировать нужные данные в хранилище callback.
- Правило владения должно определять, кто может менять эти 32 байта, пока callback ожидает запуска.
Зачем это спрашивают: Интервьюер проверяет, умеете ли вы находить висячий указатель, возникший из-за времени жизни объекта на стеке.
Прошивка должна скопировать или собрать четыре байта в выровненный uint32_t, а не приводить buffer + 1 к указателю на uint32_t.
- Адрес со смещением 1 не обязан удовлетворять требованию четырехбайтного выравнивания счетчика.
- Прямое приведение может вызвать fault на целевой платформе и нарушает правила C об aliasing или представлении объектов.
- memcpy в выровненный uint32_t понятен, а компиляторы обычно эффективно оптимизируют фиксированное копирование четырех байтов.
- После копирования нужно декодировать заданный порядок байтов, потому что выравнивание и endianness являются разными вопросами.
Зачем это спрашивают: Интервьюер проверяет, безопасно ли вы обрабатываете невыровненные двоичные данные вместо рискованного приведения указателя.
В пакет UART нужно сначала отправить 0x12, затем 0x34, потому что сетевой порядок байтов является big-endian.
- Little-endian описывает размещение 0x1234 в памяти MCU, обычно 0x34, а затем 0x12 по возрастающим адресам.
- Протокол на линии задает собственный порядок байтов и не должен зависеть от размещения данных в памяти процессора.
- Старший байт кодируется через value >> 8, а младший через value & 0xFF.
- Тест приемника со значением 0x1234 хорошо выявляет случайную сериализацию в порядке байтов хоста.
Зачем это спрашивают: Интервьюер оценивает, отделяете ли вы endianness процессора от порядка байтов, заданного протоколом.
Я бы ожидал padding и проверил размер через sizeof, а не считал, что три поля суммарно занимают 7 байтов.
- Компилятор обычно добавляет три байта перед timestamp, чтобы uint32_t начинался на границе четырех байтов.
- Он также может добавить два байта в конец, чтобы элементы массива структур сохраняли нужное выравнивание, и тогда размер будет 12 байтов.
- Перестановка полей в порядке uint32_t, uint16_t, uint8_t может уменьшить типичный размер до 8 байтов без упакованных обращений.
- Для формата на линии или во flash поля нужно сериализовать явно, потому что раскладка компилятора не является стабильным протоколом.
Зачем это спрашивают: Интервьюер проверяет понимание padding структуры из-за выравнивания и отказ от использования нативной раскладки как формата.
Я бы объявил таблицу как const и передавал ее через указатель на const, чтобы вызывающий код не мог случайно изменить калибровочные данные.
- const документирует, что 256 байтов доступны только для чтения после сборки образа прошивки.
- Типичный embedded-линкер может оставить такие данные во flash, не копируя их при запуске в дефицитную RAM.
- Параметр типа const uint8_t * разрешает чтение через указатель, но запрещает запись через этот интерфейс.
- Размещение все равно зависит от скрипта линкера и toolchain, поэтому карта должна подтвердить отсутствие копии в RAM.
Зачем это спрашивают: Интервьюер оценивает и корректное применение const, и его практическую связь с расходом flash и RAM.
Я бы жестко соблюдал протокольный максимум 48 байтов и резервировал еще один байт под конец строки.
- Перед записью полезного байта нужно проверять, что текущая длина меньше 48, а не считать физическую емкость буфера новым лимитом протокола.
- После полной команды длиной от 0 до 48 байтов нулевой терминатор записывается в buffer[length], поэтому максимальная строка занимает 49 байтов.
- При получении 49-го полезного байта нужно отбрасывать данные до разделителя кадра, а не принимать команду вне протокола.
- Явный статус превышения длины не позволит парсеру принять обрезанный префикс за корректную команду.
Зачем это спрашивают: Интервьюер проверяет, отделяете ли вы лимит протокола от емкости хранилища и места под терминатор.
Нужно использовать беззнаковое вычитание и сравнивать прошедшую разницу с 500, а не сравнивать абсолютные метки времени.
- Сохранить start как uint32_t и проверять (uint32_t)(now - start) >= 500.
- Беззнаковая арифметика работает по модулю 2^32, поэтому разность остается корректной при одном переполнении счетчика.
- Шаблон безопасен, когда измеряемый интервал меньше половины диапазона счетчика, чему 500 мс явно соответствует.
- Тест со start около 0xFFFFFFF0 и now после нуля должен проверить граничный случай.
Зачем это спрашивают: Интервьюер оценивает, правильно ли вы используете определенное стандартом переполнение беззнаковых чисел для embedded-таймеров.
Парсер должен проверить, что count не превышает SIZE_MAX, деленное на 12, и что получившиеся 72 000 байтов помещаются в реальный бюджет буфера.
- Умножение нужно проверить до выполнения в типе размера, иначе переполненное малое значение приведет к выделению слишком маленького блока.
- Даже без арифметического переполнения 72 000 байтов превышают всю RAM MCU объемом 64 КБ, поэтому значение нужно отклонить.
- Преобразовывать недоверенное значение count в size_t следует только после проверки его допустимого диапазона по протоколу.
- Один и тот же проверенный размер в байтах должен ограничивать и выделение, и последующий цикл обработки элементов.
Зачем это спрашивают: Интервьюер проверяет, отличаете ли вы арифметическое переполнение от численно корректного результата, невозможного для устройства.
Закрытые вопросы
- 21
PB5 переназначили на альтернативную функцию UART, после чего записи для светодиода на этом выводе перестали менять напряжение; как найти причину и безопасно вернуть вывод в режим GPIO?
peripherals - 22
Кнопка соединяет PA0 с землей и читается каждую 1 мс на плате Cortex-M0+ с напряжением 3,3 В; зачем входу pull-up и какие значения должна видеть прошивка?
firmwaremcu - 23
Механическая кнопка опрашивается каждые 5 мс и может дребезжать 12 мс; как отфильтровать ее с интервалом стабильности около 20 мс?
debounce - 24
Таймер общего назначения получает частоту 48 МГц и должен вызывать прерывание каждую 1 мс; приведите допустимую пару prescaler и auto-reload и объясните правило минус единица.
interrupts - 25
Таймер на 48 МГц должен генерировать PWM с частотой 20 кГц и коэффициентом заполнения 25 процентов для вентилятора; какие значения периода и сравнения вы выберете?
- 26
12-битный ADC использует опорное напряжение 3,3 В и возвращает код 2048; какому входному напряжению это примерно соответствует и какие предположения влияют на результат?
- 27
12-битный ADC должен измерять сигнал датчика с частотой 200 Гц на MCU с частотой 64 МГц; разумна ли частота выборки 1 кГц и какой простой буфер выделить для 100 мс данных?
- 28
Кнопка на EXTI0 из-за дребезга вызывает десять прерываний за 3 мс на Cortex-M0+ с частотой 48 МГц; что должен делать обработчик и где выполнять debounce длительностью 20 мс?
interruptsmcudebounce - 29
На Cortex-M4 прерыванию ADC с частотой 10 кГц назначен приоритет NVIC 2, а прерыванию UART на 115200 бод приоритет 5; у какого выше срочность и что произойдет, если оба ожидают одновременно?
interruptsperipheralsmcu - 30
Windowed watchdog принимает обновление только через 200-400 мс после предыдущего, а исправный superloop выполняется каждые 100 мс; как собрать признаки здоровья и выбрать момент обновления?
firmwarereliabilityaggregation - 31
Сколько времени один байт занимает на линии UART при 115200 бод и формате 8N1 и какова примерная максимальная скорость полезных данных?
peripheralsconfig - 32
MCU на 48 МГц отправляет UART на 115200 бод в формате 8N1, а приемник настроен на 9600 8E1; почему он будет сообщать об ошибках кадра или четности?
peripheralsconfig - 33
Два устройства на 3,3 В используют общую шину I2C 400 кГц с дорожками длиной 10 см; почему SDA и SCL работают с открытым стоком и зачем каждой линии нужен подтягивающий резистор?
peripherals - 34
Датчик температуры имеет 7-битный I2C-адрес 0x48 и регистр 0x00; опишите транзакцию на 400 кГц, которая читает два байта данных и включает решения об ACK.
transactionsperipherals - 35
Шина I2C на 400 кГц имеет полную емкость около 150 пФ и медленные фронты с подтяжкой 10 кОм; почему 4,7 кОм тоже может не хватить и какое значение попробовать на плате 3,3 В?
peripherals - 36
SPI-датчик требует mode 3, частоту не выше 8 МГц и низкий chip-select на протяжении передачи 3 байтов; как настроить и выполнить транзакцию на MCU с частотой 48 МГц?
evmtransactionsconfig - 37
Во время полнодуплексной передачи 4 байтов по SPI на 4 МГц MCU хочет только отправить команду; почему он все равно должен обработать принятые байты и как узнать, приняла ли периферия команду?
peripheralsevm - 38
Два узла одновременно начинают передавать стандартные CAN-кадры на 500 кбит/с с идентификаторами 0x120 и 0x080; какой кадр выиграет арбитраж и что произойдет со вторым узлом?
- 39
Стандартный CAN-кадр данных на 500 кбит/с несет идентификатор 0x321 и DLC 8; для чего нужны идентификатор, DLC, CRC и поле ACK?
- 40
На плате 3,3 В находятся четыре датчика температуры, каждый выдает 2 байта с частотой 10 Гц по дорожкам длиной 15 см, а MCU имеет одну I2C на 400 кГц и одну SPI на 8 МГц; какой протокол выбрать?
peripheralstypingevm - 41
Bare-metal MCU с частотой 48 МГц должен читать кнопку каждую 1 мс, обновлять светодиод каждые 10 мс и отправлять статус каждые 100 мс; как организовать superloop без блокирующих задержек?
bare-metal - 42
Датчику нужно 50 мс на преобразование, а передача его отчета из 12 байтов по UART занимает около 1,1 мс при 115200 8N1; спроектируйте простой автомат состояний IDLE, MEASURING и REPORTING для цикла 100 мс.
designperipherals - 43
Вход статуса создает одно событие в секунду, но минимальная ширина импульса неизвестна, а UART принимает пакеты по 64 байта на 115200 бод; какие сигналы можно безопасно опрашивать?
peripherals - 44
Обработчик UART получает один байт каждые 86,8 микросекунды при 115200 8N1, а основной цикл может остановиться на 5 мс; как будет работать кольцевой буфер на 128 байтов?
interruptsperipherals - 45
Карта линкера для MCU со 128 КБ flash показывает 72 КБ .text, 10 КБ .rodata и 4 КБ загрузочного образа .data во flash; сколько flash остается и что проверить дальше?
- 46
Карта MCU с 32 КБ RAM показывает 4 КБ .data, 12 КБ .bss, зарезервированный стек 6 КБ и кучу 2 КБ; какой запас RAM остается?
cssdata-structures - 47
После сброса образ Cortex-M имеет 2 КБ инициализированной .data и 6 КБ .bss в 32 КБ RAM; что аппаратура делает до обработчика сброса и что startup-код внутри него выполняет перед main?
mcu - 48
Вы меняете UART платы на 48 МГц со скорости 9600 на 115200 бод и правите три определения регистров; какой базовый Git-процесс использовать перед отправкой на review?
zero-to-onegitperipherals - 49
Сборка для Cortex-M4 на 64 МГц предупреждает, что 12-битное значение ADC типа uint16_t преобразуется в uint8_t перед передачей; как обработать предупреждение при -Wall -Wextra -Wconversion?
mcu - 50
12-битный ADC с опорным напряжением 3300 мВ передает данные в расчет температуры каждые 100 мс; где провести границу unit-теста, чтобы тестам не требовалась аппаратура Cortex-M?
hypothesis-testingtestingmcu - 51
Сигналы A и B квадратурного энкодера создают 4000 фронтов в секунду и иногда дают недопустимые переходы; как надежно считать направление?
- 52
На таймер поступает тактовая частота 1 МГц, а LED должен завершать один цикл включения и выключения каждые 500 мс. Какой период таймера нужен, если ISR переключает LED?
interrupts - 53
Цифровой вход получает высокий импульс длительностью 37 мкс; как измерить его через input capture свободно работающего таймера на 1 МГц?
- 54
LED с активным низким уровнем подключен к PWM-пину, но при значении сравнения 75% его яркость выглядит примерно как 25%. Что вы проверите?
- 55
12-битный ADC постоянно занижает показания датчика с выходным сопротивлением около 100 кОм при самом коротком времени выборки; что нужно изменить?
- 56
Стабильный датчик измеряется 12-битным ADC с частотой 10 тысяч выборок в секунду, но коды скачут в диапазоне 20 отсчетов. Как исследовать и уменьшить шум?
- 57
Свободно работающий 16-битный таймер тикает с частотой 1 МГц, но прошивке нужно измерять интервалы в несколько секунд; как расширить и безопасно читать такой таймер?
firmware - 58
GPIO на кабеле длиной 2 м дребезжит в шумной установке, хотя прошивка включает логическую подтяжку вверх; как сделать вход надежным?
firmwareperipherals - 59
Красный LED с резистором 330 Ом должен управляться от 3,3 В, но настроенный высокий GPIO показывает только 0,2 В. Какие безопасные проверки вы сделаете?
peripheralsconfig - 60
Плата печатает нечитаемый текст по UART, логический анализатор измеряет длительность каждого бита около 8,68 микросекунды, а терминал настроен на 9600 бод. В чем ошибка?
peripherals - 61
Обе платы используют 57600 бод, но приемник сообщает об ошибках кадра во многих байтах. Анализатор показывает дополнительный бит четности перед стоп-битом. Что нужно изменить?
- 62
I2C-анализатор показывает адресные биты и 9 импульсов SCL, но SDA остается высокой на 9-м импульсе, а MCU сообщает об отсутствии подтверждения. Что вы проверите?
peripherals - 63
В datasheet датчика указаны 0xD0 для записи и 0xD1 для чтения, но API MCU ожидает 7-битный I2C-адрес. Какое значение должен передать драйвер?
peripheralsapi - 64
После reset MCU во время передачи на 400 кГц SDA остается низкой при высокой SCL, и I2C-периферия не может начать работу. Как безопасно восстановить маленькую плату?
peripherals - 65
SPI-датчик возвращает сдвинутые и непостоянные байты на 2 МГц. Его datasheet требует CPOL 1 и CPHA 1, а анализатор правильно декодирует только в режиме 3. Что вы сделаете?
evmperipherals - 66
Два SPI-устройства совместно используют MISO, и линия держится около 1,4 В, когда оба chip-select случайно активны. Какова вероятная неисправность и безопасное исправление?
evmperipherals - 67
Прошивка отправляет SPI-байт 0x96, но периферийное устройство интерпретирует 0x69. Clock mode и chip select выглядят правильно. Что проверить дальше?
firmwareperipheralsevm - 68
На CAN-шине 500 кбит/с установлены три терминатора по 120 Ом, и часто появляются error frame. Какое сопротивление ожидается между CAN_H и CAN_L при выключенном питании?
peripherals - 69
После повторных ошибок передачи CAN-узел переходит из error-active в error-passive, а затем в bus-off; что означают эти состояния и как искать причину?
- 70
Протокол на скорости 115200 бод разрешает ровно один кадр на 100 байтов до обслуживания приемника; какова минимальная полезная емкость буфера и когда пауза 20 мс требует больше памяти?
capacitytyping - 71
Таймерное прерывание частотой 1 кГц выполняет вычисление длительностью 2 мс, и другие прерывания теряются. Что нужно изменить?
interrupts - 72
На 8-битном MCU ISR увеличивает 16-битный счетчик выборок, а main loop его читает. Иногда main loop видит невозможное значение. Почему?
interrupts - 73
UART idle-line разделяет кадры переменной длины от 20 до 200 байтов, которые принимает циклический DMA; как находить границы кадров и не терять данные при переходе через конец буфера?
peripherals - 74
Двоичный кадр начинается возле конца кольцевого буфера на 128 байтов и продолжается с индекса ноль; как разобрать и проверить его без предположения о непрерывной памяти?
indexesvalidationmemory - 75
ADC измеряет 10 тысяч выборок в секунду в циклический DMA-буфер на 200 значений. Когда должны происходить half-transfer и full-transfer callbacks и как их использовать?
peripheralscallbacks - 76
12-битный ADC пишет в массив uint16_t, но DMA настроен на 32-битную ширину периферии и памяти, и в буфере на 100 выборок появляются пропуски. Что исправить?
peripheralsconfigmemory - 77
ISR заполняет буфер пакета на 32 байта и устанавливает ready, но main loop иногда читает пакет из байтов двух кадров. Как безопасно передать данные?
interrupts - 78
GPIO создает пять фронтов, пока его прерывание запрещено на 10 мс, но после повторного включения прошивка видит только одно прерывание. Почему и как посчитать каждый фронт?
firmwareinterruptsperipherals - 79
Ошибка в обработчике импульса длительностью 100 микросекунд исчезает каждый раз, когда вы останавливаетесь на breakpoint внутри него. Как отлаживать, не скрывая проблему тайминга?
- 80
Конфигурационная переменная неожиданно изменяется примерно раз в 3 секунды. Как поможет watchpoint в JTAG или GDB?
configdebugging - 81
Плата на Cortex-M4 входит в HardFault через 30 секунд. Какие значения из exception stack frame вы сохраните сначала и что они покажут?
mcuerror-handling - 82
Прошивка доходит до assert(state == READY), потому что после команды состояние осталось IDLE; как через GDB найти неверный переход?
firmware - 83
Обработчик HardFault на Cortex-M работает через MSP, но прерванная задача могла использовать PSP; как найти автоматически сохраненный exception frame?
interruptsmcuerror-handling - 84
В отчете о сбое есть PC 0x0800432A, но у вас только map-файл и ELF от вчерашней сборки. Как надежно найти исходный код?
- 85
SWD подключается после reset, но отключается примерно через 50 мс, когда новая прошивка входит в sleep и перенастраивает пины. Как вернуть управление?
firmware - 86
I2C-датчик возвращает неправильное значение, но логический анализатор показывает адрес 0x48, регистр 0x01, ACK и два ожидаемых байта данных. Что исследовать дальше?
peripherals - 87
SPI работает на 1 МГц, но ломается на 12 МГц. Логический анализатор декодирует чисто, а осциллограф у приемника показывает фронт около 30 нс и сильный ringing. Что делать?
evmperipherals - 88
UART надежен через перемычку 10 см, но повреждает данные через кабель 1 м на 115200 бод. Как разделить ошибку прошивки и физического канала?
firmwareperipherals - 89
Функция объявляет локальный массив на 512 байтов и работает в задаче со стеком 1 КиБ. Чем это опасно и что изменить?
- 90
Embedded heap на 8 КиБ получает случайные выделения от 20 до 200 байтов и освобождает их в другом порядке. Через несколько часов выделение 300 байтов не удается, хотя свободно 2 КиБ. Что произошло?
embeddeddata-structures - 91
После одного commit прошивка выросла на 14 КиБ, хотя новая функция выглядит небольшой; как найти причину и не допустить следующего сюрприза с размером?
firmware - 92
Стек на 2 КиБ заполнен 0xA5 при запуске, и после стресс-теста 600 байтов в нижней части остались нетронутыми. Что показывает watermark?
- 93
Компилятор предупреждает, что индекс 10 выходит за границы int values[10] в цикле с условием i <= 10. Что нужно сделать?
- 94
Локальная переменная состояния функции читается до присваивания, и плата запускается в разных режимах при 20 повторных reset. Как исправить и проверить это?
- 95
Сборка для MCU с SRAM 32 КиБ падает после добавления debug-буфера 8 КиБ; теперь map сообщает 40 КиБ .bss. Что делать?
- 96
Задача FreeRTOS должна запускаться каждые 100 мс, но между запусками она крутится в busy wait и лишает времени низкоприоритетную задачу логирования. Что нужно использовать?
rtoslogging - 97
GPIO ISR должен отправить событие в очередь FreeRTOS на 8 элементов, которую ждет задача с более высоким приоритетом. Какой API и какое поведение yield нужны?
rtosinterruptsperipherals - 98
Разработчик передает 256 как stack depth в xTaskCreate и документирует это как 256 байтов. Почему это может быть неверно?
- 99
Плата на батарее должна просыпаться от RTC каждые 5 секунд и потреблять 10 микроампер во сне, но мультиметр постоянно показывает 2 мА. Как это отлаживать?
- 100
Watchdog с таймаутом 1 секунда кормится из timer ISR, поэтому плата не перезапускается при deadlock в main loop. Кто должен владеть кормлением watchdog?
interruptsreliabilitylocking