Open reading without registration · demonstrations are clearly labelled
Program complete

Embedded C: ESP32, STM32 and reliable firmware

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.

Instruction: englishPublished lessons: 60
Start reading

Offline reading

Build PDF

Embedded C: ESP32, STM32 and reliable firmware

The file preserves a published release with its text, examples and images. Your local progress is excluded.

What to include

Lessons selected: 60. Maximum per export: 60. Program order will be preserved.

View program

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.

What you need to know

  • Basic C: pointers, structures, unsigned arithmetic and object lifetime.
  • Familiarity with GPIO/UART and FreeRTOS tasks.

Tools and equipment

  • No equipment is required for reading and interactive self-checks.
  • For source assignments: a specific ESP32/STM32 board, its SDK and chip documentation, and suitable measurement tools.

One step at a time

Course program

Learning lessons: 60

Module 01

Architecture, FreeRTOS and industrial inputs

Responsibility boundaries, events, queues, watchdog supervision and input signals.

10 lessons
  1. 01

    Lesson 1. Firmware is a system, not just while(1)

    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.

  2. 02

    Lesson 2. ESP-IDF project structure: organizing firmware into components

    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.

  3. 03

    Lesson 3. FreeRTOS tasks: keeping firmware from becoming a tangle of threads

    Design FreeRTOS tasks around responsibilities over time: ownership, priorities, queues, timestamps, overload policies and independent modem operation.

  4. 04

    Lesson 4. FreeRTOS queues, event groups and task notifications

    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.

  5. 05

    Lesson 5. Watchdog: protection, not an enemy

    Use watchdogs to diagnose stalled responsibilities. Distinguish IWDT, TWDT, STM32 IWDG and WWDG; combine bounded recovery with meaningful heartbeat checks rather than unconditional feeding.

  6. 06

    Lesson 6. A state machine for Quectel EC25

    An event-driven EC25 modem service handles AT replies, URCs, deadlines, reconnects and recovery without blocking phase detection.

  7. 07

    Lesson 7. A UART parser for AT commands

    Continuously assemble and classify a byte stream containing command replies and interleaved URCs, keeping parsing separate from recovery.

  8. 08

    Lesson 8. ESP32 GPIO and strapping pins

    Audit pin boot roles, Flash/PSRAM use, debugging, input-only restrictions and analogue constraints before assigning a peripheral.

  9. 09

    Lesson 9. Optocoupler inputs

    An optocoupler does not produce an ideal digital level: account for pulses, inversion, CTR, pull resistors, filtering and timestamp uncertainty.

  10. 10

    Lesson 10. Detecting 220 V AC after an optocoupler

    Detect traffic-light phase presence from a pulse window and stability confirmation, distinguishing physical detection, confirmation and event-emission times.

Module 02

ESP32 and STM32 peripherals

Timers, GPIO, UART/RS-485, DMA, ADC, CAN and diagnostic limits.

10 lessons
  1. 11

    Lesson 11. ADS1115, GPIO expanders and comparators: choosing a traffic-light input frontend

    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.

  2. 12

    Lesson 12. ESP32 and STM32 timers: when vTaskDelay() is no longer enough

    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.

  3. 13

    Lesson 13. STM32 clock tree: understanding RCC before timers, UART, ADC and CAN/RS-485

    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.

  4. 14

    Lesson 14. STM32 GPIO and EXTI: receiving discrete signals correctly

    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.

  5. 15

    Lesson 15. STM32 UART/USART and RS-485: industrial serial communication without lost bytes

    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.

  6. 16

    Lesson 16. DMA and buffers: moving data faster requires a memory architecture

    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.

  7. 17

    Lesson 17. STM32 and ESP32 ADCs: 12-bit resolution does not mean 12-bit accuracy

    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.

  8. 18

    Lesson 18. STM32 CAN/FDCAN and ESP32 TWAI: an industrial bus without unexplained bus-off

    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.

  9. 19

    Lesson 19. Watchdogs and health monitoring: recover with useful diagnostics

    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.

  10. 20

    Lesson 20. Production firmware logging: keeping diagnostic messages out of the real-time path

    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

Reliability, updates and testing

Fault domains, configuration, OTA, CI/HIL, unit tests, fuzzing and synchronization.

10 lessons
  1. 21

    Lesson 21. Fault handling and safe degraded modes

    Handling faults and entering safe degraded modes.

  2. 22

    Lesson 22. Configuration, NVS, and Flash settings

    Configuration is part of firmware. Corrupt, outdated, or incompatible Flash parameters should lead to safe defaults and a clear explanation, not a hang.

  3. 23

    Lesson 23. Safe OTA through EC25 with rollback

    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.

  4. 24

    Lesson 24. CI/CD for firmware releases

    Build the path from a firmware commit to a safe release.

  5. 25

    Lesson 25. Unit testing embedded code without a board

    Separate application logic from ESP-IDF, STM32 HAL, and hardware so that hundreds of tests can run on Linux/Windows in seconds.

  6. 26

    Lesson 26. Fuzzing and property-based testing

    A unit test checks a scenario you imagined. A fuzzer tries to find one you did not think of.

  7. 27

    Lesson 27. Data races, deadlock, and priority inversion

    Prefer a single owner for a shared resource; other tasks send commands and events instead of accessing it directly.

  8. 28

    Lesson 28. Interrupt architecture

    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.

  9. 29

    Lesson 29. DMA, ring buffers, and cache coherency

    DMA moves bytes but does not manage buffer ownership. Reliable streaming requires explicit read/write rights for every region of memory.

  10. 30

    Lesson 30. Hardware timers, Input Capture, and Output Compare

    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

Time, security and hardware resilience

Timestamps, Modbus framing, crash diagnosis, MPU, TrustZone, TLS, commands and power.

10 lessons
  1. 31

    Lesson 31. Time architecture and device synchronization: monotonic clock, UTC, NTP, PPS, and drift estimation

    Four distinct concepts of time: monotonic time, UTC, hardware capture time, and local civil time.

  2. 32

    Lesson 32. UART/RS-485 and Modbus RTU: half-duplex, DE control, framing, and reliable DMA transport

    Industrial serial transport from UART and RS-485 electrical signaling to framed, validated protocol transactions.

  3. 33

    Lesson 33. Low-level HardFault and ESP32 crash debugging: find the cause, not just the crash location

    Investigate crashes caused by invalid pointers, memory corruption, stack overflow, DMA errors, and data races.

  4. 34

    Lesson 34. MPU, stack guards, and memory protection: catch corruption at the write

    Hardware memory protection can turn hidden corruption into an immediate, diagnosable fault near the responsible instruction.

  5. 35

    Lesson 35. TrustZone, Secure Boot, and secret isolation: separate keys and critical functions from normal firmware

    Different security mechanisms protect boot authenticity, runtime boundaries, stored secrets, and revoked versions.

  6. 36

    Lesson 36. TLS, PKI, and certificate lifecycle: secure MQTT/HTTPS through ESP32 and EC25

    Secure device-to-server communication requires certificate, hostname, and validity checks, plus a workable rotation lifecycle.

  7. 37

    Lesson 37. Secure commands over MQTT, CAN, and RS-485: HMAC, anti-replay, and idempotency

    Build a bounded, authenticated, authorized, and auditable remote-command path.

  8. 38

    Lesson 38. Deterministic memory management: static allocation, object pools, and heap-fragmentation protection

    Design firmware to avoid unpredictable memory-related crashes after weeks of continuous operation.

  9. 39

    Lesson 39. Brownout resilience and embedded power: survive EC25 startup, voltage dips, and power loss

    Treat power, early warning, safe outputs, and transactional storage as part of firmware architecture.

  10. 40

    Lesson 40. EMC/ESD and industrial-input protection: do not hide poor circuit design with software debounce

    Protect the connector-to-MCU path against electrical transients and diagnose residual disturbances in firmware.

Module 05

Production firmware engineering

FSMs, binary protocols, fault injection, observability, release provenance and identity.

10 lessons
  1. 41

    Lesson 41. Finite-state machines in embedded systems

    A finite-state machine, or FSM, describes a subsystem as a set of permitted states, events and transitions.

  2. 42

    Lesson 42. Designing a binary protocol

    Design a binary protocol over UART, RS-485, TCP, UDP, CAN FD, MQTT binary payloads and a Raspberry Pi HIL link.

  3. 43

    Lesson 43. Fuzzing and property-based testing

    Test a parser with millions of random and semi-random inputs, not just manually chosen examples.

  4. 44

    Lesson 44. Fault injection and chaos testing

    Reliability is not established by the presence of if (err). Reproduce failures and check that recovery is bounded, observable and does not damage data.

  5. 45

    Lesson 45. Observability and postmortem analysis

    Build diagnostics that explain a reset, the active operation, the last FSM state, preceding events and the exact ELF needed for analysis.

  6. 46

    Lesson 46. Reproducible release builds and provenance

    version=1.8.0 is not enough: firmware identity includes source, configuration, dependencies, toolchain and the hash of the specific artifact.

  7. 47

    Lesson 47. Secure Boot, Flash Encryption and anti-rollback

    Distinguish code authentication, Flash confidentiality, OTA recovery and anti-rollback, and plan their lifecycle in the correct order.

  8. 48

    Lesson 48. Unique device identity and provisioning

    Every device needs its own cryptographic identity. A production station must not write one shared password or private key across the fleet.

  9. 49

    Lesson 49. Secure remote commands

    mTLS/MQTT authenticates the channel, but the device must still verify a command's author, recipient, freshness, permissions and current admissibility.

  10. 50

    Lesson 50. Latency budgets and timing in FreeRTOS

    Move beyond average speed: estimate the maximum delay from a hardware event to its response and budget each component of that path.

Module 06

Memory, concurrency and durable data

DMA ownership, SPSC, snapshots, replay, contracts, recovery and Flash durability.

10 lessons
  1. 51

    Lesson 51. DMA, cache coherency and zero-copy

    DMA moves data between peripherals and RAM without CPU copying, but buffer ownership and CPU/DMA visibility must be explicit.

  2. 52

    Lesson 52. A lock-free SPSC ring buffer

    A Single Producer / Single Consumer ring has one writer of head and one writer of tail, making index ownership explicit for fast data paths.

  3. 53

    Lesson 53. RCU, immutable snapshots and double-buffered configuration

    Update configuration while real-time tasks keep reading it: construct a validated immutable snapshot, publish it atomically and protect the old snapshot's lifetime.

  4. 54

    Lesson 54. Event sourcing and deterministic replay

    Record the input events of a deterministic core rather than an arbitrary log, then reproduce the FSM behaviour on a PC.

  5. 55

    Lesson 55. Property-based testing and state-machine fuzzing

    A unit test checks one scenario; property-based testing checks system laws across many automatically generated scenarios.

  6. 56

    Lesson 56. Design by Contract in embedded C

    Design by Contract expresses preconditions, postconditions and invariants directly in code, distinguishing internal faults from external runtime failures.

  7. 57

    Lesson 57. Fault containment and supervisor architecture

    Use a recovery ladder to isolate and recover a fault domain before escalating to a whole-MCU reset or safe mode.

  8. 58

    Lesson 58. Brownout, power-fail transactions and crash-consistent storage

    After power loss at any update step, storage must recover a complete old or new configuration, never a mixture.

  9. 59

    Lesson 59. Flash wear, endurance and write amplification

    Budget physical Flash program/erase operations, classify acceptable data loss and reduce frequent writes through batching and checkpoints.

  10. 60

    Lesson 60. Data retention, ECC, scrubbing and latent corruption

    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.