Finite State Machine
A finite state machine (FSM) is a computational model in which a system exists in exactly one of a finite number of defined states at any given time, transitioning between states in response to defined inputs or events. FSMs are widely used in embedded firmware to manage control flow, protocol handling, and reactive behavior in a structured, maintainable way.
In practice
In embedded systems, FSMs replace deeply nested if/else or switch/case logic with an explicit model of system behavior. Each state captures what the system is doing right now, each transition defines when and why it moves to a different state, and optional entry/exit actions run code at the moment a state is entered or left. This separation of concerns makes behavior easier to reason about, test, and extend. Common embedded use cases include button debouncing, communication protocol parsers (UART framing, Modbus, USB protocol stages), motor control sequences, power management modes, and menu navigation on display-based devices.
Two dominant implementation patterns appear in C/C++ firmware. The flat FSM uses a single switch statement over a state enum inside a periodically called function -- simple to write and sufficient for small machines with few states and no hierarchy. The table-driven FSM stores states, events, actions, and next-states in a 2D array or array of structs, making transitions data rather than code and reducing the risk of forgetting a case; note that some table-driven designs use sparse tables or default handlers rather than enumerating every possible state-event combination. More advanced designs use function pointers or virtual methods so each state owns its own event-handling logic, which scales better as the number of states grows. The blog posts "Finite State Machines (FSM) in Embedded Systems (Part 1)" through "Part 3" cover these patterns in detail, including a C++ DSL approach for reducing boilerplate.
A common pitfall is conflating the current state with a mode flag or a set of boolean variables scattered across the codebase -- an informal, implicit FSM that is hard to audit. Making the FSM explicit forces every possible state and every valid transition to be named, which surfaces missing or unintended transitions early. Another frequent mistake is performing long blocking operations inside a state's action code; on bare-metal systems without an RTOS, this stalls the entire state machine and can miss events. Keeping actions short and deferring long work to background tasks or interrupts is the standard remedy.
Hierarchical state machines (HSMs), popularized by Miro Samek's Quantum Platform (QP) framework, extend flat FSMs by allowing states to nest inside parent states that share common behavior. This avoids duplicating transitions across many peer states. For most simple embedded control problems a flat FSM is sufficient; HSMs pay off when the number of states grows large or when many states share significant common behavior. The "Implementing State Machines" blog post discusses practical trade-offs between flat and hierarchical approaches.



