What the course covers
- Design boundaries between drivers, services and state machines.
- Reason about timing, ownership, recovery and correctness conditions.
- Define reproducible checks and acceptance criteria for a specific board.
60 learning discussions, from architecture and peripherals to resilience, security and durable data. The Russian source is accompanied by a full English translation and separately labelled Egorov Learn practice. Adapt examples to the specific board; compilation and hardware testing are not claimed.
One step at a time
Learning lessons: 60
Module 01
Responsibility boundaries, events, queues, watchdog supervision and input signals.
Think of embedded firmware as layers, events, drivers and services. An ESP32 or STM32 application is a small system with clear responsibilities, a fast input path and a separate path for transport and diagnostics.
Organize an ESP-IDF project into components, keep main small, declare CMake dependencies, separate board configuration from drivers and business logic, and maintain a reproducible baseline configuration.
Design FreeRTOS tasks around responsibilities over time: ownership, priorities, queues, timestamps, overload policies and independent modem operation.
Choose a FreeRTOS communication mechanism by its contract: message data, shared state flags, a task wakeup, mutual exclusion or a byte stream. Define overflow behavior explicitly.
Use watchdogs to diagnose stalled responsibilities. Distinguish IWDT, TWDT, STM32 IWDG and WWDG; combine bounded recovery with meaningful heartbeat checks rather than unconditional feeding.
An event-driven EC25 modem service handles AT replies, URCs, deadlines, reconnects and recovery without blocking phase detection.
Continuously assemble and classify a byte stream containing command replies and interleaved URCs, keeping parsing separate from recovery.
Audit pin boot roles, Flash/PSRAM use, debugging, input-only restrictions and analogue constraints before assigning a peripheral.
An optocoupler does not produce an ideal digital level: account for pulses, inversion, CTR, pull resistors, filtering and timestamp uncertainty.
Detect traffic-light phase presence from a pulse window and stability confirmation, distinguishing physical detection, confirmation and event-emission times.
Module 02
Timers, GPIO, UART/RS-485, DMA, ADC, CAN and diagnostic limits.
Choosing an input frontend: optocoupler -> GPIO, optocoupler -> GPIO expander, optocoupler -> ADS1115, or optocoupler -> comparator/Schmitt trigger -> GPIO. Main idea: ADS1115 measures, a GPIO expander adds inputs, and a comparator/Schmitt trigger cleans up the signal.
The differences between vTaskDelay(), vTaskDelayUntil(), esp_timer, GPTimer, RMT and MCPWM/LEDC on ESP32, and TIM/Input Capture/Output Compare/DMA on STM32. Main idea: vTaskDelay() is not a precise physical timer.
STM32 clock tree: HSI/HSE, PLL, SYSCLK, HCLK, APB1/APB2, kernel clocks, prescalers and actual peripheral frequencies. Main idea: without knowing a peripheral clock, you cannot understand its actual behavior.
GPIO modes, pull-up/pull-down, floating inputs, push-pull/open-drain, output speed, alternate functions, analog mode and EXTI. Main idea: STM32 GPIO is not just 0/1; it is a configurable electrical interface.
UART/USART, RX through interrupt/DMA/ring buffer, RS-485 DE/RE, half-duplex and Modbus RTU timing. Main idea: UART is a byte stream; RS-485 adds control of transmission direction.
DMA, circular buffers, half-transfer/transfer-complete callbacks, UART RX DMA, ADC DMA and cache coherency. Main idea: DMA is an independent participant that reads and writes memory concurrently with the CPU.
ADC sampling time, source impedance, calibration, oversampling, DMA scans, min/max/avg and diagnostics. Main idea: the ADC measures the result of a sampling circuit, not an ideal voltage.
CAN/FDCAN/TWAI: bit timing, sample point, arbitration, termination, transceivers, filters, error counters and bus-off recovery. Main idea: CAN is not UART; it is a multi-master bus with arbitration, errors, ID priorities and strict physical requirements.
Hardware watchdog, task watchdog, heartbeat, progress counters, reset reason, panic/core dump, fault snapshots and recovery. Main idea: feed the watchdog only when the system is actually healthy.
Log levels, rate limiting, event ring buffers, breadcrumbs, fault snapshots, binary events, UART/MQTT/CAN telemetry and the diag/events/health CLI. Main idea: logging can itself cause latency, buffer overflow and watchdog resets.
Module 03
Fault domains, configuration, OTA, CI/HIL, unit tests, fuzzing and synchronization.
Handling faults and entering safe degraded modes.
Configuration is part of firmware. Corrupt, outdated, or incompatible Flash parameters should lead to safe defaults and a clear explanation, not a hang.
OTA finishes when new firmware boots, passes self-test, and retains the ability to perform the next update—not merely when its file reaches Flash.
Build the path from a firmware commit to a safe release.
Separate application logic from ESP-IDF, STM32 HAL, and hardware so that hundreds of tests can run on Linux/Windows in seconds.
A unit test checks a scenario you imagined. A fuzzer tries to find one you did not think of.
Prefer a single owner for a shared resource; other tasks send commands and events instead of accessing it directly.
An ISR records the hardware event, clears its source, hands minimal information to a task, and exits; parsing, filtering, recovery, logging, and networking belong outside it.
DMA moves bytes but does not manage buffer ownership. Reliable streaming requires explicit read/write rights for every region of memory.
When edge timing or pulse duration matters, a hardware timer should capture or generate the event; a FreeRTOS task processes an already recorded timestamp.
Module 04
Timestamps, Modbus framing, crash diagnosis, MPU, TrustZone, TLS, commands and power.
Four distinct concepts of time: monotonic time, UTC, hardware capture time, and local civil time.
Industrial serial transport from UART and RS-485 electrical signaling to framed, validated protocol transactions.
Investigate crashes caused by invalid pointers, memory corruption, stack overflow, DMA errors, and data races.
Hardware memory protection can turn hidden corruption into an immediate, diagnosable fault near the responsible instruction.
Different security mechanisms protect boot authenticity, runtime boundaries, stored secrets, and revoked versions.
Secure device-to-server communication requires certificate, hostname, and validity checks, plus a workable rotation lifecycle.
Build a bounded, authenticated, authorized, and auditable remote-command path.
Design firmware to avoid unpredictable memory-related crashes after weeks of continuous operation.
Treat power, early warning, safe outputs, and transactional storage as part of firmware architecture.
Protect the connector-to-MCU path against electrical transients and diagnose residual disturbances in firmware.
Module 05
FSMs, binary protocols, fault injection, observability, release provenance and identity.
A finite-state machine, or FSM, describes a subsystem as a set of permitted states, events and transitions.
Design a binary protocol over UART, RS-485, TCP, UDP, CAN FD, MQTT binary payloads and a Raspberry Pi HIL link.
Test a parser with millions of random and semi-random inputs, not just manually chosen examples.
Reliability is not established by the presence of if (err). Reproduce failures and check that recovery is bounded, observable and does not damage data.
Build diagnostics that explain a reset, the active operation, the last FSM state, preceding events and the exact ELF needed for analysis.
version=1.8.0 is not enough: firmware identity includes source, configuration, dependencies, toolchain and the hash of the specific artifact.
Distinguish code authentication, Flash confidentiality, OTA recovery and anti-rollback, and plan their lifecycle in the correct order.
Every device needs its own cryptographic identity. A production station must not write one shared password or private key across the fleet.
mTLS/MQTT authenticates the channel, but the device must still verify a command's author, recipient, freshness, permissions and current admissibility.
Move beyond average speed: estimate the maximum delay from a hardware event to its response and budget each component of that path.
Module 06
DMA ownership, SPSC, snapshots, replay, contracts, recovery and Flash durability.
DMA moves data between peripherals and RAM without CPU copying, but buffer ownership and CPU/DMA visibility must be explicit.
A Single Producer / Single Consumer ring has one writer of head and one writer of tail, making index ownership explicit for fast data paths.
Update configuration while real-time tasks keep reading it: construct a validated immutable snapshot, publish it atomically and protect the old snapshot's lifetime.
Record the input events of a deterministic core rather than an arbitrary log, then reproduce the FSM behaviour on a PC.
A unit test checks one scenario; property-based testing checks system laws across many automatically generated scenarios.
Design by Contract expresses preconditions, postconditions and invariants directly in code, distinguishing internal faults from external runtime failures.
Use a recovery ladder to isolate and recover a fault domain before escalating to a whole-MCU reset or safe mode.
After power loss at any update step, storage must recover a complete old or new configuration, never a mixture.
Budget physical Flash program/erase operations, classify acceptable data loss and reduce frequent writes through batching and checkpoints.
Endurance describes erase/program lifetime; retention describes how long stored bits survive. Periodically verify redundant copies to detect latent corruption before the fallback is needed.