hardware-in-loop-reference
Pure-reference catalog of hardware-in-the-loop (HIL) testing for embedded systems. Defines the HIL pattern (ECU-under-test + real-time plant simulator + I/O cards emulating sensors / actuators / buses), the V-cycle progression (MIL → SIL → PIL → HIL), the canonical vendor stack (NI VeriStand + PXI / CompactRIO, dSPACE SCALEXIO / MicroAutoBox, Vector CANoe + VT System, Speedgoat real-time targets), bus emulation per protocol (CAN / CAN FD / LIN / FlexRay / Automotive Ethernet / SOME-IP), fault-injection patterns (short-to-ground, open-circuit, signal corruption), DO-178C / ISO 26262 / IEC 61508 alignment, and the test-evidence chain HIL produces. Use as the HIL terminology + vendor + standard reference when scoping an embedded test rig or interpreting an automotive / aerospace / industrial HIL test report.
Install with skills.sh (any agent)
npx skills add testland/qa --skill hardware-in-loop-referencehardware-in-loop-reference
Overview
Hardware-in-the-loop (HIL) is, per en.wikipedia.org/wiki/Hardware-in-the-loop_simulation (opens in new window), "a technique that is used in the development and testing of complex real-time embedded systems" that "provides an effective testing platform by adding the complexity of the process-actuator system, known as a plant, to the test platform". In practice it means: the production ECU runs production firmware against a real-time simulator that emulates the rest of the vehicle / aircraft / machine in closed loop, with the same electrical interfaces the ECU sees in the field.
This skill is a pure reference consumed by the per-tool skills (googletest-embedded-arm, unity-test-framework-c, qemu-system-test-runner) when teams need to decide what slips into HIL versus what stays in host / QEMU.
When to use
The HIL pattern
+-------------------+ analog/digital I/O +-------------------+
| | <----------------------------- | |
| Real-time | CAN / CAN-FD / LIN / FlexRay | ECU under test |
| plant simulator | <----------------------------- | (production |
| (vehicle / motor | | firmware, |
| / battery model) | -----------------------------> | production HW) |
| | wheel speed, temp, voltage, | |
+-------------------+ pedal position, error codes +-------------------+
|
| fault injection: short-to-ground / open / corrupt-bus / drift
v
Test sequencer + scenario scriptsPer Wikipedia (citation above), the rig "must include electrical emulation of sensors and actuators" - that emulation is what distinguishes HIL from pure software simulation. The ECU sees voltage / current / bus traffic, not numbers in RAM.
V-cycle: MIL → SIL → PIL → HIL
| Stage | Plant | Controller | Where it runs |
|---|---|---|---|
| MIL (Model-in-the-loop) | Simulink model | Simulink model | Host PC, Simulink simulation |
| SIL (Software-in-the-loop) | Simulink model | C/C++ auto-generated from controller model | Host PC, native compile |
| PIL (Processor-in-the-loop) | Simulink model on host | C/C++ cross-compiled, running on the production processor | Eval board + host |
| HIL (Hardware-in-the-loop) | Real-time plant model on real-time target | Production firmware on production ECU | Production hardware + real-time simulator |
(The terms MIL / SIL / PIL / HIL are not in Wikipedia's HIL article but are universal in automotive ECU verification - cite by stable term "automotive V-model verification stages".) Each stage tightens the realism by replacing one block with the real artefact. HIL is the last gate before SOP (Start Of Production) sign-off.
Vendor stack at a glance
Vendor product pages are largely gated (Cloudflare / login walls); cited by stable ID.
| Vendor | Real-time target | Test authoring | Notable strength |
|---|---|---|---|
| NI | PXI chassis + R-Series FPGA / CompactRIO | VeriStand (System Definition .nivssdf, stimulus profiles, real-time sequence) + TestStand orchestrator | Strong on FPGA-precision I/O; tight Simulink import. Cite "NI VeriStand 2024 System Definition File Reference" |
| dSPACE | SCALEXIO / MicroAutoBox | ControlDesk + AutomationDesk | De-facto in automotive Tier 1s; AUTOSAR-aware. Cite "dSPACE SCALEXIO 2024 / ControlDesk 2024 Help" |
| Vector | VT System (rack) + VT instrument cards | CANoe with CAPL test scripting + vTESTstudio test authoring | Bus-traffic-centric (CAN / CAN-FD / LIN / FlexRay / Ethernet / SOME-IP). Cite "Vector CANoe 17 User Manual" |
| Speedgoat | Performance / Mobile / Baseline real-time targets | Simulink Real-Time test harnesses | Tight MathWorks integration; xPC-Target descendant |
| OPAL-RT | OP4510 / OP5707 | RT-LAB + eMEGAsim | Power electronics / grid; sub-microsecond loops |
The reader should treat vendor choice as a procurement decision, not a technical one - all the vendors support the core HIL pattern. Vendor differentiation is in I/O density, FPGA latency, and which test-authoring language the team has skill in (CAPL for Vector, LabVIEW for NI, Simulink for Speedgoat).
Bus emulation per protocol
| Protocol | Speed | Topology | HIL-relevant notes |
|---|---|---|---|
| CAN classical (ISO 11898-1) | 1 Mbit/s | Multi-master bus | Standard ECU bus; nearly all rigs include a CAN card. Cite "ISO 11898-1:2015" |
| CAN FD | 5 Mbit/s data phase | Multi-master | Higher payload (64 B vs 8 B); rigs need CAN FD-capable transceiver |
| LIN (ISO 17987) | 19.2 kbit/s | Single master / multi-slave | Body electronics (door, mirror). Cite "ISO 17987-1:2016" |
| FlexRay | 10 Mbit/s | Dual-channel, TDMA | Chassis / X-by-wire on premium platforms. Cite "ISO 17458-1:2013" |
| Automotive Ethernet (100BASE-T1 / 1000BASE-T1) | 100 Mbit/s or 1 Gbit/s | Point-to-point | ADAS / infotainment backbone. Cite "IEEE 802.3bw-2015" (100BASE-T1) and "IEEE 802.3bp-2016" (1000BASE-T1) |
| SOME-IP / SOME-IP-SD | App-layer over UDP/TCP on Automotive Ethernet | Service-oriented | Service discovery + RPC; AUTOSAR Adaptive. Cite "AUTOSAR FO R23-11 SOME-IP Protocol Specification" |
| CXPI | 20 kbit/s | Single-wire | LIN replacement on JP OEMs |
Vector's CANoe is the de-facto authoring tool for the first five rows; NI VeriStand and dSPACE wrap their own driver stacks.
Fault-injection patterns
The reason HIL exists. Sw-only sims can't reproduce these:
| Pattern | What it does | Detects |
|---|---|---|
| Short-to-ground | Sensor wire shorted to chassis | Open-circuit detection logic, watchdog |
| Short-to-battery | Sensor wire shorted to V_bat | Over-voltage protection, fuse logic |
| Open-circuit | Sensor disconnected | Plausibility checks, neighbour-signal sanity |
| Signal corruption | Bit-flip on CAN frame, CRC error | CAN error counter handling, retry policy |
| Bus-off | Excessive errors trigger CAN bus-off state | Bus-off recovery state machine |
| Drift / bias | Sensor reading slowly offsets | Long-term sensor diagnostics, OBD-II logic |
| Frozen signal | Same value forever | Signal-staleness watchdog |
| Latency injection | Bus delay added | Real-time deadline handling |
| Power glitch | V_bat dips below threshold momentarily | Brown-out behaviour |
These map directly to ISO 26262-5 fault models - see standard expectations below.
Safety-standard alignment
Cited by stable ID - the standards are gated, not WebFetchable.
| Standard | HIL expectation |
|---|---|
| DO-178C §6.4.4 Structural Coverage | Aircraft software at DAL A requires MC/DC; HIL is one of the means to produce that coverage on the integrated target |
| DO-254 | The companion hardware standard. HIL exercises the DO-254 + DO-178C interface - the FPGA boundary |
| ISO 26262-4 §7 | Vehicle-level test specification - HIL is mentioned as one of the recommended methods for system + integration test |
| ISO 26262-5 §10 | Hardware fault injection - HIL fault patterns above map directly to this clause |
| IEC 61508-3 Table A.5 | "Functional testing on a HIL rig" is a recommended technique at SIL 3 / SIL 4 |
| IEC 62304 | Medical device software - HIL applies to perfusion pumps, ventilators, surgical robots; less prescriptive than 26262 |
Test evidence the HIL produces
A typical HIL test report - the artefacts a certifier expects to see - contains:
CAPL / VeriStand stimulus example shapes
CAPL test module (Vector CANoe - cite "Vector CANoe 17 CAPL Function Reference"):
testcase Test_Brake_Latency()
{
SetSignal(Vehicle::BrakePedal, 0.0);
TestWaitForTimeout(100);
SetSignal(Vehicle::BrakePedal, 1.0);
if (TestWaitForSignalMatch(ECU::BrakeOutput, 1.0, 50) == 0)
TestStepPass("Brake output engaged within 50 ms");
else
TestStepFail("Brake output did not engage in 50 ms");
}NI VeriStand real-time sequence (cite "NI VeriStand 2024 Real-Time Sequence Editor Help"):
SetChannelValue Inverter/Throttle 0.0
Wait 100 ms
SetChannelValue Inverter/Throttle 1.0
WaitUntilSettled Motor/Torque == 50.0 (tolerance 5.0, timeout 200 ms)
ReportTestResultThe two languages encode the same scenario - choose the one the team is fluent in.
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| HIL used as a regression rig for code-style checks | Rig time is expensive; lint runs on host | Push static + unit tests left; HIL only for system behaviour |
| Plant model never validated against real vehicle | "Successful" HIL run means nothing | Cross-validate plant against vehicle-on-dyno data |
| Fault-injection scenarios scripted but never replayed after firmware change | Regression invisible | Run the full fault-injection battery on every release candidate |
| Skipping PIL because "HIL covers it" | PIL catches compiler / target-CPU issues HIL can't | Keep PIL in the V-model |
| Recording everything but asserting on nothing | "Look at the trace" reviews don't scale | Each scenario must have machine-checkable assertions |
| Hardcoding I/O channel numbers in scenarios | Wiring changes break every script | Use channel aliases (VeriStand System Definition / CANoe dbc symbolic names) |
| HIL deadline missed silently | Real-time integrity violated | The simulator must monitor and FAIL on missed-deadline; not just log |
Limitations
References
Cited inline. Foundational documents:
Related skills
ceedling-build-runner
Author and run the Ceedling build system for C unit testing - the canonical build orchestration on top of Unity (assertions) + CMock (mocks) + CException (exceptions). Covers ceedling new project scaffolding, the project.yml schema (:project / :paths / :files / :defines / :flags / :tools / :test_runner / :cmock / :unity / :cexception / :gcov / :plugins), the task surface (ceedling test:all, ceedling test:{name}, ceedling test:pattern, ceedling test:path, ceedling release, ceedling clean / clobber, ceedling gcov:all, ceedling module:create, ceedling environment, ceedling dumpconfig), JUnit XML output via the report_tests_pretty_stdout / report_tests_junit_xml plugins, gcov plugin integration, host vs cross-build flow, and CI wiring. Use when a C project wants the standard ThrowTheSwitch trio bundled by one build command. For the Unity assertion API see unity-test-framework-c; for CMock semantics see cmock-reference.
cmock-reference
Pure-reference catalog of CMock and Ceedling mocking semantics for C. Defines what CMock generates from a C header (the full Expect / ExpectAndReturn / ExpectAnyArgs / ExpectWithArray / Ignore / IgnoreAndReturn / IgnoreArg_{param} / ReturnThruPtr_{param} / AddCallback / Stub / ExpectAndThrow naming family), the cmock.yml :plugins list (ignore, ignore_stateless, ignore_arg, expect_any_args, array, callback, cexception, return_thru_ptr) and what each enables, mock-suffix and mock-prefix conventions, how Unity teardown validates expectations, the resetTest mid-test verification, strict vs ignore argument-matching modes, and the trade-offs between mock / stub / spy / fake. Use as the CMock semantics reference when authoring Ceedling tests with mocks or when reading an unfamiliar mock-driven test suite.
embedded-coverage-strategy-reference
Pure-reference catalog of code-coverage strategy for embedded C/C++: the criteria hierarchy (statement / branch / decision / condition / MC/DC), the gcov toolchain (.gcno/.gcda, --coverage), the LLVM source-based toolchain (llvm-profdata / llvm-cov), host-build vs QEMU-build instrumentation, MISRA-C:2012 and DO-178C structural-coverage expectations by safety level (DAL A maps to MC/DC), and report-format choices. Use when choosing what structural-coverage level to require and wiring gcov / llvm-cov into the build; physical .gcda retrieval from hardware is in hardware-in-loop-reference, QEMU machine flags in qemu-system-test-runner, and to author the embedded tests themselves use googletest-embedded-arm or unity-test-framework-c.
googletest-embedded-arm
Author and run GoogleTest 1.17+ for embedded C++ on ARM targets - TEST() / TEST_F() / TEST_P() / TYPED_TEST(), EXPECT_* vs ASSERT_* assertions, fixtures with SetUp() / TearDown(), value-parameterised tests, GoogleMock when paired, cross-compile with arm-none-eabi-g++, run on host or under QEMU via the qemu-system-test-runner skill, --gtest_filter / --gtest_output=xml:results.xml / --gtest_shuffle / --gtest_repeat command-line flags, and XML / JSON output parsing for CI. Use when the unit-under-test is C++ (modern C++17+) and the team wants the de-facto C++ test framework instead of the C-only Unity. For C use unity-test-framework-c; for pure mocks use cmock-reference.
qemu-system-test-runner
Author and run QEMU system emulation as an embedded-test target - qemu-system-arm / qemu-system-aarch64 / qemu-system-riscv32 launching cross-compiled ELF binaries on virtual MCUs and SoCs. Covers machine selection (-M virt / mps2-an385 / mps2-an386 / mps2-an500 / mps2-an511 / mps3-an524 / lm3s6965evb / raspi3b / xilinx-zynq-a9), CPU selection (-cpu cortex-m0 / cortex-m3 / cortex-m4 / cortex-m33 / cortex-a15 / cortex-a57 / max), -kernel ELF load, -nographic + -serial stdio, ARM semihosting via -semihosting-config enable=on,target=native (so cross-compiled GoogleTest / Unity binaries print to host stdio and exit with the test return code), GDB stub via -S -gdb tcp::1234, QMP monitor via -qmp tcp:host:port for automated test orchestration, and CI wiring. Use when host-only test runs are insufficient and the team wants arch-correct (endianness / alignment / interrupt-vector) behaviour on a virtual MCU without committing to physical hardware-in-loop.
unity-test-framework-c
Author and run ThrowTheSwitch Unity (the C unit-testing library) for bare-metal and RTOS C code. Distinct from the Unity game-engine Test Framework at docs.unity3d.com: this is the ThrowTheSwitch C testing library at throwtheswitch.org/unity, a single C file plus headers that runs on 8-bit MCUs through 64-bit hosts. Anchored on the Unity assertion API and configuration macros regardless of execution environment: the TEST_ASSERT_EQUAL_* / _FLOAT / _DOUBLE / _STRING / _MEMORY / _BITS assertion families, setUp/tearDown/RUN_TEST/UNITY_BEGIN/UNITY_END semantics and the exit-code contract, the generate_test_runner.rb generator, build-time config defines (UNITY_INCLUDE_DOUBLE, UNITY_OUTPUT_CHAR, UNITY_EXCLUDE_SETJMP), and CI integration via Ceedling JUnit XML; applies to host builds, cross-builds, and QEMU-run targets alike. For QEMU machine flags, semihosting, and exit-code capture, see qemu-system-test-runner. Use when the unit-under-test is pure C and the target ranges from 8-bit AVR to Cortex-M0 to Linux ARM.