LabWired The easy way to build hardware

The Ghost in the CI: Why Embedded Tests Flake and How to Stop It

Keywords: flaky firmware tests, deterministic embedded simulation, HIL CI/CD, race conditions, hardware in the loop.

The “Just Rerun It” Culture

It’s 2:00 PM on a Friday. You just pushed a three-line fix for an I2C edge case. You wait 45 minutes for the Hardware-in-the-Loop (HIL) pipeline to finish.

Red checkmark. Error: Timeout waiting for sensor acknowledgment.

You check the logs. There’s nothing wrong with your I2C patch. You sigh, click “Rebuild”, and walk away. 45 minutes later, it passes. You’ve just experienced the single greatest morale killer in embedded engineering: the flaky firmware test.

When a software team’s tests flake, they might blame a noisy network or a wonky database state. When an embedded team’s tests flake, the list of suspects is endless: a loose USB cable, a wearing flash wear-level, a slight variance in a power supply, or a test script that relied on a sleep(100) that really needed to be sleep(110) today because the host PC was compiling something else in the background.

The result is always the same: developers lose trust in the CI pipeline. “Oh, that test just fails sometimes, ignore it and rerun” becomes the accepted norm. This is how critical bugs slip into production.

Why Your Firmware CI is Flaky

In embedded systems, flakiness usually boils down to the friction between software logic and physical reality.

1. The HIL Bottleneck

Testing on real Hardware-in-the-Loop (HIL) rigs is the gold standard for final validation, but it’s terrible for CI. HIL setups are expensive, fragile, and inherently non-deterministic. If your CI runs on a physical board in a server rack, you’re at the mercy of environmental instability. If another team is stressing the network, or if a relay gets stuck, your test fails for reasons that have nothing to do with your code.

2. The “Real-Time” Simulation Fallacy

To escape the HIL bottleneck, many teams turn to software simulators (like QEMU). But most standard emulators aim for speed, running instructions “as fast as possible.”

If your firmware expects a specific sequence of DMA interrupts, and your host CI server suddenly spins up a heavy Docker build on another core, the timing shifts. The simulated hardware behaves differently than the physical hardware. You’ve traded hardware instability for host-load instability.

3. The vTaskDelay Anti-Pattern

Because timing is so unpredictable in both HIL and standard emulation, test engineers compensate by scattering hardcoded sleeps (vTaskDelay, sleep(100)) throughout their test scripts. These represent hopes and prayers, not robust engineering.

The Solution: Bit-Accurate Determinism

To kill flakiness, you must divorce simulated time from real-world time.

LabWired’s engine isn’t built just to execute instructions quickly; it’s built for lockstep determinism.

This means the simulation clock drives everything. Whether your CI runner is a 64-core beast or a struggling laptop, the order of instruction execution, DMA transfers, and interrupt firing remains mathematically identical. Every single time.

Proof in the Output: Deterministic Headless Execution

Consider how a standard LabWired CI test executes headless validation. In a recent benchmark on our uart-ok.yaml fixture, we saw the following output:

$ labwired test --script examples/ci/uart-ok.yaml
2026-02-23T20:32:23.113Z INFO labwired_core::system::builder: Loading system manifest: "ci-fixture-uart1.yaml"
2026-02-23T20:32:23.113Z INFO labwired_core::system::builder: Loading chip descriptor: "ci-fixture-cortex-m3-uart1.yaml"
2026-02-23T20:32:23.113Z INFO labwired_loader: ELF Entry Point: 0x9
OK

It boots the firmware, maps the Cortex-M3 core, runs the target code, captures the UART OK string, and exits—all deterministically.

And it doesn’t sacrifice speed for precision. Our recent single-core throughput benchmarks reliably hit ~46.9 MIPS (Millions of Instructions Per Second):

[PERF] MIPS: 46.95 (Elapsed: 0.213s)

By moving to a strictly deterministic virtual hardware platform with this performance profile, you gain superpowers that physical HIL can never offer:

Stop Rerunning the Pipeline

Flaky tests aren’t a law of physics; they are a symptom of using the wrong tools for continuous integration. HIL is for final sign-off. For the agility required in modern development, you need an environment where 1 + 1 always equals 2.

If you’re tired of babysitting your CI, it’s time to test your firmware on a platform that actually tells you the truth.


Ready to stop the flakiness? Check out our Getting Started Guide or see how we compare in LabWired vs QEMU.

Andrii Shylenko
Andrii Shylenko

Founder, LabWired.