Чему посвящён курс
- Проектировать границы драйверов, сервисов и state machines.
- Разбирать тайминги, ownership, recovery и условия корректности.
- Формулировать воспроизводимые проверки и критерии для собственной платы.
60 учебных разборов от архитектуры и периферии до устойчивости, безопасности и долговечности данных. Русский оригинал, полный английский перевод и отдельно отмеченная практика Egorov Learn. Примеры требуют адаптации к конкретной плате; компиляция и испытания на оборудовании не заявляются.
Последовательные шаги
Учебных уроков: 60
Модуль 01
Разделение ответственности, события, очереди, watchdog и обработка входных сигналов.
Как правильно мыслить embedded-прошивку: слои, события, драйверы и сервисы. Главная идея: прошивка для ESP32 или STM32 - это не один большой файл с GPIO, UART и таймерами, а маленькая система, где каждый блок отвечает за свою область. Типичный набор подсистем в реальном проекте:
Структура ESP-IDF проекта: как правильно делить код на components, что класть в main, как оформлять CMakeLists.txt, где хранить пины платы, где держать бизнес-логику, а где - драйверы. Предыдущий урок был про архитектурное мышление. Сегодня переводим это в реальную структуру ESP-IDF проекта.
Как проектировать задачи FreeRTOS в ESP-IDF: сколько задач нужно, какие у них должны быть ответственности, как выбирать приоритеты, где использовать очереди, а где не плодить лишние потоки. Главная мысль: FreeRTOS task - это не “просто поток”. Это владелец конкретной ответственности во времени.
Три главных механизма связи между задачами FreeRTOS:
Watchdog в ESP32/ESP-IDF и STM32: зачем он нужен, какие бывают виды, почему он срабатывает, как правильно “кормить” watchdog и почему плохая идея вставлять esp_task_wdt_reset() куда попало. Главная мысль: Watchdog - не костыль от зависаний, а диагностический механизм, который показывает, что архитектура задачи нарушена.
Машина состояний для Quectel EC25: AT-команды, OK, ERROR, URC, таймауты, MQTT/TCP/UDP reconnect и восстановление связи. Главная мысль: Модем нельзя обслуживать как последовательность send_at(); delay();. Модем должен быть отдельным сервисом со своим состоянием, очередью запросов, таймаутами и восстановлением.
UART-парсер для AT-модема Quectel EC25: поток байтов, сборка строк, отделение ответов на команды от URC, обработка OK, ERROR, +CME ERROR, +QMTOPEN, +QMTCONN, +QMTSTAT, переполнение буфера и частичные сообщения. Главная мысль: AT-парсер не должен “ждать строку OK”. Он должен непрерывно разбирать поток, в котором ответы на команды и асинхронные URC могут перемешиваться.
GPIO-ограничения ESP32/ESP32-C3 и правила выбора пинов: strapping pins, UART0, flash/PSRAM- пины, JTAG/SWD, input-only GPIO, ADC2 при Wi-Fi, оформление board_pins.h. Главная мысль: В embedded нельзя выбирать GPIO только по принципу “свободная ножка”. У каждой ножки есть история: загрузка, flash, отладка, аналоговые ограничения, подтяжки, sleep/wakeup и периферийные функции.
Дискретные входы через оптопары: что реально происходит между внешним сигналом 220 В / 24 В / 12 В и GPIO ESP32/STM32, почему на выходе могут быть пульсации, дребезг, задержки, ложные фронты. Главная мысль: Оптопара не превращает внешний сигнал в идеальный логический уровень. Она превращает его в ток через светодиод, затем в ток фототранзистора, а уже потом схема подтяжки и фильтрации делает уровень для MCU.
Алгоритм детектирования фазы светофора по AC-сигналу после оптопары: окно импульсов, стабильность, подавление ложного OFF и правильный timestamp. Главная задача: Отличать реальное включение/выключение фазы от пульсаций 50/100 Гц, кратких пропаданий, помех и переходных состояний.
Модуль 02
Таймеры, GPIO, UART/RS-485, DMA, ADC, CAN и диагностические ограничения.
Выбор входного фронт-энда: оптопара -> GPIO, оптопара -> GPIO-расширитель, оптопара -> ADS1115, оптопара -> компаратор/Schmitt trigger -> GPIO. Главная мысль: ADS1115 измеряет, GPIO-расширитель расширяет, компаратор/Schmitt очищает сигнал.
Разница между vTaskDelay(), vTaskDelayUntil(), esp_timer, GPTimer, RMT, MCPWM/LEDC на ESP32 и TIM/Input Capture/Output Compare/DMA на STM32. Главная мысль: vTaskDelay() не является точным физическим таймером.
STM32 clock tree: HSI/HSE, PLL, SYSCLK, HCLK, APB1/APB2, kernel clocks, prescaler’ы и реальные частоты периферии. Главная мысль: если не знаешь частоту периферии, не знаешь её реальное поведение.
GPIO modes, pull-up/pull-down, floating input, push-pull/open-drain, output speed, alternate function, analog mode и EXTI. Главная мысль: GPIO на STM32 - это не просто 0/1, а настраиваемый электрический узел.
UART/USART, RX через interrupt/DMA/ring buffer, RS-485 DE/RE, half-duplex, Modbus RTU timing. Главная мысль: UART - поток байтов; RS-485 добавляет управление направлением передачи.
DMA, circular buffers, half-transfer/complete callbacks, UART RX DMA, ADC DMA, cache coherency. Главная мысль: DMA - это отдельный участник системы, который читает/пишет память параллельно CPU.
ADC: sampling time, source impedance, calibration, oversampling, DMA scan, min/max/avg и диагностика. Главная мысль: ADC измеряет результат схемы выборки, а не идеальное напряжение.
CAN/FDCAN/TWAI: bit timing, sample point, arbitration, termination, transceiver, filters, error counters, bus-off recovery. Главная мысль: CAN - не UART, а многомастерная шина с арбитражем, ошибками, приоритетами ID и строгой физикой.
Hardware watchdog, task watchdog, heartbeat, progress counters, reset reason, panic/core dump, fault snapshot, recovery. Главная мысль: watchdog кормят только тогда, когда вся система действительно здорова.
Log levels, rate limit, event ring buffer, breadcrumbs, fault snapshot, binary events, UART/MQTT/CAN telemetry, CLI diag/events/health. Главная мысль: логирование само может стать причиной задержек, переполнений и watchdog reset.
Модуль 03
Fault domains, конфигурация, OTA, CI/HIL, unit tests, fuzzing и синхронизация.
Разбираем обработку отказов и безопасные деградированные режимы:
Главная мысль: конфигурация - это часть прошивки. Если параметры в Flash испортились, устарели или не подходят новой версии firmware, устройство должно не зависнуть, а загрузиться с безопасными defaults и понятно сообщить причину.
Главная мысль: OTA заканчивается не тогда, когда файл записан во Flash, а когда новая прошивка загрузилась, прошла самодиагностику и сохранила возможность следующего обновления.
Строим путь прошивки от коммита до безопасного релиза:
Как отделить прикладную логику от ESP-IDF, STM32 HAL и реального железа, чтобы запускать сотни тестов на Linux/Windows за секунды. Правильная цепочка:
Главная мысль: unit-тест проверяет придуманный тобой сценарий. Fuzzer пытается найти сценарий, о котором ты не подумал.
Главная мысль: лучший способ защитить общий ресурс - по возможности вообще не делить его между задачами. Назначь ресурсу одного владельца, а остальные задачи пусть отправляют ему команды и события.
Главная мысль: ISR должна быстро зафиксировать аппаратное событие, очистить источник прерывания, передать минимальную информацию задаче и завершиться. Парсинг, фильтрация, recovery, логирование и работа с сетью выполняются не в ISR.
Главная мысль: DMA решает проблему перемещения байтов, но не решает проблему владения буфером. Надёжность появляется только тогда, когда в каждый момент известно, кто имеет право читать или изменять конкретную область памяти.
Главная мысль: если момент фронта или длительность импульса важны, событие должно фиксироваться или формироваться аппаратным таймером. Задача FreeRTOS должна обрабатывать уже готовый timestamp.
Модуль 04
Timestamp, Modbus framing, crash diagnosis, MPU, TrustZone, TLS, команды и питание.
Сегодня разбираем четыре разных понятия времени:
Сегодня разбираем промышленный последовательный транспорт:
Сегодня разбираем диагностику аварий, возникающих из-за:
Сегодня разбираем аппаратную защиту памяти:
Сегодня разбираем механизмы безопасности:
Сегодня разбираем защищённую связь устройства с сервером:
Сегодня строим безопасный путь удалённой команды:
Сегодня разбираем, как спроектировать прошивку, которая не начинает случайно падать через недели непрерывной работы из-за памяти:
Сегодня разбираем питание как часть архитектуры прошивки:
Сегодня разбираем устойчивость платы к электромагнитным помехам и электрическим переходным процессам:
Модуль 05
FSM, бинарные протоколы, fault injection, observability, release provenance и identity.
Конечный автомат, или FSM, описывает подсистему как набор допустимых состояний, событий и переходов:
Проектируем бинарный протокол поверх UART, RS-485, TCP, UDP, CAN FD, MQTT binary payload и HIL-связи с Raspberry Pi. Основные темы:
Проверяем parser не только ручными тестами, а миллионами случайных и полуслучайных входов:
Главная мысль: надежность не доказывается наличием if (err). Нужно воспроизводимо вызвать ошибку и проверить, что recovery ограничена, наблюдаема и не повреждает данные.
Строим систему, которая после reset отвечает:
Главная мысль: version=1.8.0 недостаточно. Полная идентичность прошивки - это source, configuration, dependencies, toolchain и хеш конкретного артефакта.
Главная мысль: это разные механизмы, включать их нужно в правильном порядке.
Главная мысль: у каждого устройства должна быть собственная криптографическая идентичность. Производственная станция не должна записывать один общий пароль или private key на весь парк.
Главная мысль: mTLS/MQTT подтверждает канал, но устройство все равно должно проверить автора команды, адресата, свежесть, полномочия и допустимость операции сейчас.
Переходим от «в среднем работает быстро» к вопросу:
Модуль 06
DMA ownership, SPSC, snapshots, replay, contracts, recovery и сохранность Flash.
DMA позволяет периферии читать и писать RAM без участия CPU. Это удобно для ADC, UART, SPI, CAN, Ethernet и больших потоков данных, но появляется новая проблема: кто сейчас владеет буфером и видят ли CPU и DMA одинаковую версию данных. Типовой путь:
SPSC означает Single Producer / Single Consumer. Это кольцевой буфер, где ровно один producer пишет head, а ровно один consumer пишет tail. Он подходит для быстрых путей:
Нужно обновлять конфигурацию, пока realtime-задачи продолжают её читать. Например:
Идея: записывать не произвольный лог, а входные события de- terministic core, чтобы потом точно воспроизвести поведение FSM на ПК.
Unit test проверяет конкретный сценарий. Property-based test- ing проверяет законы системы на множестве автоматически сгенерированных сценариев.
Design by Contract формализует правила системы прямо в коде:
Когда ошибка обнаружена, не всегда нужно перезагружать весь MCU. Строим recovery ladder:
Строим storage, который переживает внезапное отключение питания в любой точке update transaction. Главная мысль: после power loss допустим OLD или NEW, но никогда HALF-NEW.
После crash consistency нужно посчитать ресурс Flash. Ресурс расходуют physical program/erase operations, а не размер переменной сам по себе. Главная мысль: запись 4 байт раз в секунду может превратиться в сотни миллионов logical updates за 10 лет.
Endurance — это сколько раз можно erase/program. Retention