Wiki / Concepts

CAN Arbitration and Frame Timing

Why a CAN frame is never early and often late. Priority arbitration, bit stuffing and cycle time turn the timestamp column of a capture into evidence in its own right.

A low-priority frame waits
6F0 ready 0C0 wins 110 wins 6F0 at last idle
6F0 became ready first and transmitted last. Arbitration delay is therefore one sided: a frame can be pushed later by the traffic in front of it, never earlier. How much later depends on the identifier's priority and on how loaded the bus is at that instant, so the same identifier drifts as the load changes.

CAN arbitration decides which node gets the wire when several want it at once, and the way it decides leaves a signature in the timestamp column of every capture. A frame can only ever be delayed, never advanced, and how much it is delayed depends on its arbitration ID and on how busy the bus was at that moment.

What it is

CAN is a broadcast bus with no scheduler. A node that has a frame ready waits for the bus to go idle, then starts transmitting; if another node starts at the same time, both compare the ID bit by bit and the one that sends a recessive bit where it reads a dominant bit backs off. Lower ID wins, and the loser retries at the next opportunity. Nothing is lost and nothing collides, but the loser's frame arrives late.

Three effects follow, and all three show up in a candump file.

Effect Consequence in a capture
Priority A low-priority identifier waits for every higher-priority frame already pending, so its latency rises sharply as the bus fills
One-sidedness The delay is a non-negative quantity added to the ideal transmission instant. There is no mechanism that makes a frame early
Bit stuffing After five identical consecutive bits the transmitter inserts one of opposite polarity, so two frames with the same DLC do not occupy the wire for the same length of time

A classic 8-octet standard frame is 47 bits plus payload before stuffing, so about 111 to 135 bits on the wire: roughly 250 microseconds at 500 kbit/s and a millisecond at 125 kbit/s. Most bus traffic is periodic, published on a fixed cycle time by each node's own timer, and the spread of the measured intervals around that cycle time is its jitter.

Why it matters

Baselining cycle time and jitter per identifier is a first-class intrusion detection signal: an injected frame usually shows up as an identifier arriving too often, or as a periodic identifier suddenly acquiring a second population of intervals. It is also the reason timing evidence has to be read carefully. Because arbitration delay is one sided and grows with load, any statistic that averages over a capture whose load changes will drift with the load rather than with the thing you were trying to measure. Fitting a straight line through arrival times measures the transmitter's timer plus the growth of the queue in front of it, which is a different number for every identifier on the bus.

How to work it

  1. Group a capture by identifier and take the differences between consecutive timestamps. That series is the cycle time and its jitter.
candump -l can0                       # (ts) can0 ID#DATA, stamped at end of frame
  1. Compare the mean interval against the documented cycle time, and the frame count against what that cycle time implies. An identifier arriving at twice its documented rate has two transmitters or an injector.
  2. Estimate the bus load by summing each frame's on-wire time over a window. Read the delay statistics of a low-priority identifier against that load curve; they will track it.
  3. When you need a timing number that does not move with the load, work from the lower edge of the distribution rather than its middle. The frames that found the bus idle are the honest ones.

Pitfalls

  • Timestamps are end of frame. The logger stamps a frame when the controller hands it over, so payload-dependent stuffing is inside your interval measurements.
  • A capture taken through a USB adapter with its own buffering can add host-side latency that is not on the bus at all. Prefer a device that timestamps in hardware when timing is the evidence.
  • Two identifiers with very different priorities are not comparable on latency. Their queues are different.
  • An identifier that beats against another periodic source can systematically miss every idle window, which makes its minimum delay an accident of arithmetic rather than a property of the bus.

Further reading