Firmware and embedded software engineers
Turn electrical events and system intent into deterministic, observable and recoverable behaviour on a constrained computing platform.
After this module, you should be able to:
- Structure firmware around explicit responsibilities and states
- Control concurrency, timing and shared resources
- Handle invalid inputs and faults deliberately
- Create reproducible implementation and verification evidence
Study guide · Updated · About 8 minutes reading + 20–30 minutes practice
Before you start: Read TEA-105 and TEA-107. Basic embedded C or C++ and task or interrupt concepts are assumed.
Firmware is where logical decisions meet physical time.
The role spans boot, drivers, scheduling, control logic, diagnostics, communications, data storage and update. Correct results are not enough: they must arrive at the right time, in the right state and with predictable behaviour when inputs, hardware or execution fail.
Control behaviour from reset to recovery.
| Area | Key decision | Evidence |
|---|---|---|
| Boot and update | How are images authenticated, selected, rolled back and recovered? | Boot design and update tests |
| Concurrency | Who owns data and peripherals, and how is access bounded? | Task model and resource rules |
| Timing | What are the rates, deadlines, jitter limits and overload response? | Timing budget and measurements |
| State control | Which transitions are legal and what outputs accompany them? | State model and transition tests |
| Fault handling | What is detected locally, reported, retried or made safe? | Diagnostic design and fault tests |
Separate mechanism from policy
A driver should expose hardware truth and bounded operations; higher layers decide system policy. This makes behaviour testable and prevents safety decisions from being scattered across callbacks and interrupt handlers.
Build vertical slices before broad feature coverage.
- Define contracts. Record data representation, ownership, timing, errors and initial state.
- Establish the execution model. Map interrupts, tasks, priorities and blocking behaviour.
- Implement one end-to-end path. Sense, decide, actuate, report and diagnose.
- Add observability. Use structured events, counters, timestamps and retained fault context.
- Exercise adversity. Inject timeouts, corrupt data, resets and resource exhaustion.
- Automate the build. Pin tools, capture options and make artefacts reproducible.
Worked hand-off: missed control deadline
Systems engineering defines the latest safe output update. Firmware budgets execution and instruments deadline misses. Hardware provides a watchdog or output-disable path. Safety engineering defines the required reaction, while verification drives CPU and I/O load to demonstrate the response.
Keep implementation intent and results reproducible.
Components, dependencies, data flow and execution model.
Hardware registers, messages, timing and error semantics.
Reviews, static analysis, coding rules and traceable changes.
Tool versions, options, dependencies and binary identity.
Measured load, latency, stack use and worst observed cases.
Unit, integration, target and fault-injection outcomes.
Common traps
Control policy becomes hidden in asynchronous side effects.
Timeout, partial transfer and peripheral reset are ignored.
Logical assertions pass while deadlines remain unverified.
The released image cannot be rebuilt from controlled inputs.
Own state, time and resource behaviour
Firmware responsibilities include what happens before normal operation, between asynchronous events and after a fault. Define state ownership and legal transitions, including cancellation and delayed completion. Code that works in a normal sequence may fail when the host repeats a request during recovery.
Budget execution time, stack, queues and peripheral access. Avoid hiding long operations in apparently simple interfaces. A diagnostic write that sometimes erases flash may block a control task. State the maximum relevant behaviour and test under the configuration in which the product ships.
Use explicit numeric representations, units and invalid states. Validate range and conversion before changing outputs. The compiler accepting a cast does not show that the physical value is meaningful or that arithmetic overflow has been excluded.
Treat the hardware contract as a reviewed dependency
Confirm reset defaults, clock changes, DMA ownership and peripheral error behaviour with the hardware engineer. Code generation can produce a valid configuration without proving it matches the board or system budget. Review the generated result as part of the design.
Keep assumptions visible in interfaces and verification. A sample should carry validity and age, not just a number. A request result should distinguish rejection, acceptance, completion and failure. Define whether buffers are copied or borrowed, and when a caller may reuse them.
Report a boundary uncertainty early. If the firmware cannot reliably distinguish a sensor failure from a valid measurement, the team needs a system decision or hardware change. An arbitrary threshold in code does not resolve that uncertainty.
| Firmware hand-off | Minimum useful content |
|---|---|
| To hardware | Observed electrical behaviour, timing and reproducible configuration. |
| To application | State model, message semantics, error handling and compatibility. |
| To verification | Requirements, expected response, observation points and build identity. |
| To service | Version identification, diagnostic meaning and approved recovery steps. |
Make a release reproducible and explainable
Retain source revision, dependencies, compiler and linker settings, configuration, build commands and generated artefact identity. Demonstrate that a test result belongs to the released binary, not a developer’s nearby build. Keep development credentials and debug features outside production authority.
Resolve anomalies with a product impact assessment. A rare reset is not harmless merely because the application restarts. Determine the physical state and interrupted operation outcome, add a targeted regression, and update the design when the cause changes an architectural assumption.
Practical exercise
An illustrative engineering exercise; values are assumptions for this lesson.
Fix a service command that races with Stop
A service task queues a motor target. Stop then enters a latched fault state, but the queued service request is processed later and starts the motor.
- Locate the missing ownership or authority check.
- Specify cancellation and state validation at execution time.
- Define a regression sequence and the evidence needed for the fix.
Show the worked answer
The component that owns the actuator must check current authority when applying the request, not only when it was queued. Entering the fault state revokes service authority and invalidates affected pending operations. Use an operation or mode generation identifier where it helps distinguish old work.
Verify the interleaving directly: queue service work, enter Stop, then release the delayed consumer. The output must remain in the required fault response. Repeat at relevant transition boundaries, including restart, and inspect whether other queued commands share the defect. Retain the exact binary, event sequence and physical output trace with the regression result.
Review criteria
- Execution validates current state and authority.
- Revoked work cannot become active later.
- The regression forces the original interleaving.
Check your understanding
Is checking a command when received sufficient?
Not if execution occurs later and authority can change. The owner must also enforce the current state at the point of effect.
Why identify the tested binary?
Source proximity does not prove equivalence. Compiler options, generated files and dependencies can change behaviour.
Further learning
- Arm CMSIS documentationProcessor, device and software interfaces for Cortex-based systems.
- TEA-105 · Real-time behaviourTiming, scheduling and concurrency foundations.
Engineer the behaviour around the code.
Dependable firmware makes ownership, states, timing, diagnostics and recovery as deliberate as the functional algorithm.
