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.
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.
The full exchange the analyzer decodes:
| Direction | CAN ID | Bytes | ISO-TP / UDS |
|---|---|---|---|
| tester → ECU | 0x111 | 10 0B 27 01 5A 11 22 33 | FirstFrame — SecurityAccess requestSeed, 11 bytes |
| ECU → tester | 0x222 | 30 08 00 … | FlowControl — ClearToSend |
| tester → ECU | 0x111 | 21 44 55 66 77 88 | ConsecutiveFrame |
| ECU → tester | 0x222 | 06 67 01 DE AD BE EF | Positive response — seed |
- Working → the ECU answers
06 67 01 DE AD BE EF; the analyzer decodes the whole exchange. - Broken → the FirstFrame and FlowControl appear… then silence.
Run them right here
Both labs are embedded below — press Run in each, then open the Logic tab (or the floating logic-analyzer panel) to watch the analyzer decode the FirstFrame → FlowControl → ConsecutiveFrame → response exchange. The fixed ECU reassembles the multi-frame request and returns the SecurityAccess seed; the broken one shows the FirstFrame and the FlowControl, then goes quiet.
06 67 01 DE AD BE EF. Open full-screen ↗The actual bug: two different clocks
ISO-TP has a timer called N_Cr: "if I got a FirstFrame and I'm waiting for the ConsecutiveFrame, give up if it doesn't come in time." The trouble is which clock you measure against. In his port the timer was armed from a source that read 0 (an unset get_time_ms), but the code that checks it was fed HAL_GetTick(), already thousands of milliseconds in. So the check was effectively:
if (HAL_GetTick() - 0 >= N_Cr) // (large number) - 0 is always "expired"The instant the FirstFrame arrived and the timer armed, the next service tick decided it had already timed out, tore down the multi-frame session, and threw away the ConsecutiveFrame. Single frames don't use N_Cr, so they were fine. It's a clock-source mismatch, not length math. With LabWired I was able to reproduce and debug the bug not even touching the silicon.
Closing the loop on silicon
Then I flashed the same firmware onto a real F103 over the ST-Link and read its result back out of RAM over SWD:
Simulator: DIFF_RESP = 67 01 DE AD BE EF
Real F103: 0x20000400 -> 5eed0067 00000006 adde0167 0000efbe -> 67 01 DE AD BE EF
sim == silicon: PASS
Byte-for-byte identical, exact simulation in LabWired.