Code generation is no longer the bottleneck it used to be. AI-assisted tools have made writing a first draft of firmware code fast. What has not gotten faster, at least not by the same tools, is everything that happens after the code is written: building it correctly, getting it onto the device, and figuring out why it does not behave as expected.
These three stages, build, flash, and debug, are where firmware engineering time actually concentrates. Each has its own sources of friction.
Build: Compilation Is Rarely the Slow Part
Compiling source code is fast. What consumes time is everything around the compilation step:
- Selecting the correct toolchain version for a given MCU or SoC family.
- Resolving board support package (BSP) configuration for the specific hardware revision in use.
- Untangling dependency conflicts between vendor SDK components.
- Reproducing a build that worked on one machine but fails on another due to environment drift.
BSP porting in particular is a known source of friction. Moving firmware from a reference design to a customer’s actual board layout means adjusting pin mappings, clock trees, and peripheral configuration, and a build that succeeds does not guarantee the configuration is correct. It only means the compiler was satisfied.
Flash: More Than Copying Bytes to a Chip
Flashing looks like a mechanical step, copying a binary onto a device, but it carries its own failure modes:
- Bootloader state can prevent a flash operation from completing cleanly.
- Partition layout mismatches can cause a valid image to be written to the wrong location.
- Physical connection issues, debugger compatibility, and power state during flashing all vary across board revisions.
None of this is visible from source code. It only becomes visible when someone is physically working with the target device, which is one reason flashing problems are disproportionately time-consuming relative to how simple the operation sounds.
Debug: Where the Real Time Disappears
Debugging is where the gap between “compiles” and “works” becomes concrete. A firmware image can build cleanly, flash successfully, and still behave incorrectly once it runs, because of:
- Timing-dependent behavior that only appears under real electrical and thermal conditions.
- Chip errata: known hardware bugs that require specific software workarounds documented, if at all, in vendor addenda rather than the main datasheet.
- Peripheral behavior that differs from datasheet specification under edge-case conditions.
This is where Real Hardware Verification matters most. Simulators and emulators can catch logic errors, but they cannot reproduce the electrical and timing reality of the actual target device. Diagnosing a hardware-dependent bug requires observing the device itself, forming a hypothesis, changing something, and re-testing on hardware again. That cycle, not the original code generation, is usually the largest single time cost in a firmware project.
The Common Thread: Hardware Feedback
Build, flash, and debug are different activities, but they share a common bottleneck: each one depends on feedback from the physical device, not just from source code. A build configuration is only confirmed correct once it flashes and runs. A flash operation is only confirmed correct once the firmware executes as expected. A debug hypothesis is only confirmed correct once it is verified on hardware.
This is the structural reason firmware development resists the kind of automation that has sped up general software engineering. Code generation happens in an editor. Build, flash, and debug happen in contact with hardware, and closing that loop, tying a hardware observation back to a specific fix, is exactly the coordination problem FWAuto is built to orchestrate as an Agent OS, rather than to replace with faster code suggestions.
