LabWired The easy way to build hardware

Catching a CAN bug that only shows up on real hardware — with LabWired

Category: Whitepaper

A udslib (my small ISO-14229 stack) user reported a UDS bug that wouldn’t reproduce in any test and only appeared on a particular STM32F103 setup.

Contents


Single-frame UDS requests work, multi-frame ones don’t. The ECU just goes quiet. His PCAN trace showed the tester sending the FirstFrame, ECU answers with a FlowControl, tester sends the ConsecutiveFrame… and then nothing comes back.

The bug as reported Caption: The bug as reported. 111h is the tester, 222h the ECU: FirstFrame 10 0B 27 01 5A 11 22 33, the ECU’s FlowControl 30 08 00…, the ConsecutiveFrame 21 44 55 66 77 88… — and then no response.

His own theory was a length-calculation bug. Reasonable guess for multi-frame length math. It turned out to be something else, and the interesting part. It doesn’t reproduce in a normal test, and only shows up on a particular kind of real-hardware setup.

First: it doesn’t reproduce

I didn’t touch the STM32. I took the exact bytes from his trace and replayed them straight through the current udslib, into the real dispatch layer. It worked. The ECU reassembled the 11 bytes and answered. But I also didn’t have an STM32 on my bench to reproduce the bug — that’s where LabWired comes in.

Watching it happen in LabWired

I built the real udslib firmware for the F103’s bxCAN controller and ran it in the simulator in LabWired. Then I built a second copy with the user code bug wired in, and put them side by side as two labs you open in the LabWired playground and press Run.

LabWired CAN bug reproduction trace Caption: Stepping through the firmware under lockstep instruction execution in LabWired.

The actual bug: two different clocks

The root cause was an N_Cr timer clock-source mismatch between systick hardware ticks and the protocol stack’s millisecond timer abstraction when running under real peripheral timing.

In standard host-unit tests, time was mocked using fake_time++, so both clocks moved in sync and the bug never fired. On real silicon — and in LabWired’s bit-accurate simulation — real hardware timer registers and interrupt handlers executed asynchronously, exposing the race condition.

Closing the loop on silicon

Once identified in LabWired:

  1. The tick source for ISO-TP timer management was unified to a single atomic tick provider.
  2. The fix was committed to udslib (Issue #29).
  3. The user re-tested on their physical STM32F103 setup — multi-frame SecurityAccess and transfer requests passed instantly.

By reproducing the hardware-only bug inside LabWired, we fixed a complex CAN timing bug without needing physical probes or logic analyzers attached to a physical board.


Author

Andrii Shylenko — Founder, LabWired.

Andrii Shylenko
Andrii Shylenko

Founder, LabWired.