Loading header...

Requirements and Firmware Architecture

Firmware architecture turns product intent into code structure before drivers and features harden into accidental design. A good architecture names responsibilities, timing constraints, fault responses, and verification methods.

Learning Objectives

By the end of this lesson, you should be able to write measurable firmware requirements, separate application logic from hardware access, choose a simple execution model, and prepare a verification plan that can be run before hardware is final.

Write Requirements as Tests

Good firmware requirements include a condition, behavior, limit, and verification method.

Weak statement Better requirement
Device should start quickly After power-on, publish ready state within 500 ms at 25 degC
Read sensor often Sample pressure every 10 ms +/- 1 ms while in run mode
Handle errors If sensor CRC fails 3 times, enter degraded mode and raise fault code SENS_CRC

Requirements should cover startup, normal operation, low-power modes, update paths, diagnostics, and failure behavior.

Architecture Layers

flowchart TB APP[Application behavior] --> SERVICES[Services: logging, storage, protocol] SERVICES --> DRIVERS[Device drivers] DRIVERS --> HAL[MCU HAL or register layer] HAL --> HW[Hardware] TEST[Test doubles] -. replace .-> HAL

Keep policy decisions in application and service code. Keep register details in drivers. This makes unit tests and hardware migration easier.

Execution Model

Start with the simplest model that meets timing.

  • Superloop: good for small products with bounded tasks.
  • Interrupt-driven superloop: good when fast events feed deferred processing.
  • Cooperative scheduler: good for periodic tasks without preemption complexity.
  • RTOS: useful for independent timing domains, communication stacks, or blocking APIs.

CPU utilization estimate:

$$
U=\sum\frac{C_i}{T_i}
$$

Keep margin for interrupts, debugging, and future features.

State and Fault Models

stateDiagram-v2 [*] --> Boot Boot --> SelfTest SelfTest --> Run: pass SelfTest --> Fault: fail Run --> Degraded: recoverable error Degraded --> Run: clear Run --> Fault: critical error Fault --> Boot: reset command

Fault handling should define detection, debounce, logging, output behavior, recovery, and user-visible indication.

Worked Example

A temperature controller must sample every 100 ms and switch a heater safely. Requirement: if measured temperature exceeds 80 degC for 3 consecutive samples, turn heater off within 150 ms and record TEMP_HIGH. Architecture: ADC driver, temperature service, control state machine, fault logger, output driver. Verification: inject ADC readings in a unit test and confirm state, output, and log record.

Common Mistakes

  • Starting with peripheral code before behavior is defined.
  • Mixing register writes with business rules.
  • Treating interrupts as a place for full application logic.
  • No documented startup or fault behavior.
  • No test doubles for hardware-facing code.

Summary

Firmware architecture is the bridge between requirements and maintainable implementation. Define measurable behavior, timing, states, layers, and test strategy before code volume hides design problems.

Further Reading

  • Elecia White, "Making Embedded Systems."
  • Michael Barr, "Embedded C Coding Standard" and firmware architecture articles.
  • FreeRTOS documentation, architecture and scheduling chapters.

Mind Map

mindmap root((Firmware Architecture)) Core concept Requirements become tests Layers isolate hardware States define behavior Applications Controllers Sensor nodes Gateways Safety monitors Calculations CPU utilization sum C over T Startup time Fault debounce Deadline margin Design rules Keep policy above drivers Use explicit states Bound ISR work Plan test doubles Practical checks Timing table Fault table Interface contracts Boot sequence Common mistakes Vague requirements Register code everywhere Hidden states Untested faults