5.5.5 · D2Embedded Systems & Real-Time Software

Visual walkthrough — Communication interfaces — UART, SPI, I2C (master - slave), CAN bus

2,007 words9 min readBack to topic

This is the central magic of the parent topic's CAN section: non-destructive bitwise arbitration. We derive it from zero.


Step 1 — What is even on the wire? Two lines, one difference

WHAT. CAN uses two wires, called CANH and CANL. A receiver does not read either wire alone. It reads the difference:

  • ::: voltage on the "high" wire, measured against ground
  • ::: voltage on the "low" wire, measured against ground
  • ::: the single number the receiver actually cares about — the gap between them

WHY the difference and not one wire? Because noise (a spark, a motor) hits both wires almost identically — it adds the same bump to and . When you subtract, that shared bump cancels: The noise term vanishes. That is the whole point of differential signaling — read that first if it's new.

PICTURE. Below: both wires wiggle together when noise hits (top), but their difference (bottom) stays clean.

Figure — Communication interfaces — UART, SPI, I2C (master - slave), CAN bus

Step 2 — Two named states: dominant and recessive

WHAT. CAN gives the two logic values special names, and they are not symmetric:

The names matter: "dominant" literally wins. Keep this straight —

Which bit value is dominant?
logic 0
Which bit value is recessive?
logic 1

WHY name them this way instead of just high/low? Because the electrical behaviour is lopsided, exactly like an open-drain line. A node can only force the dominant state; to be recessive it just stops forcing and lets the bus relax. So if anyone pushes dominant while everyone else is recessive, the whole bus goes dominant. Recessive can never override dominant.

PICTURE. The two states drawn as levels, with the "who can force it" arrow.

Figure — Communication interfaces — UART, SPI, I2C (master - slave), CAN bus

Step 3 — Wired-AND: the bus computes a logical AND of all talkers

WHAT. Put many nodes on the same two wires. The bus level obeys one rule:

Because dominant = 0, a single dominant (0) forces the AND to 0. This is exactly Wired-AND logic — the same trick I2C uses on SDA.

WHY does AND fall out of the electronics? From Step 2: a node can only pull toward dominant(0) or release to recessive(1). "Everybody released" is the only way the bus stays recessive(1). One puller → dominant(0). That truth table is AND. No chip is running an AND gate; the wires do it physically.

PICTURE. Three nodes, their bits, and the resulting bus — a dominant 0 from anyone drags the whole line down.

Figure — Communication interfaces — UART, SPI, I2C (master - slave), CAN bus

Step 4 — The key move: every talker also listens, bit by bit

WHAT. While a node transmits each bit, it immediately reads the bus back and compares:

Two outcomes only:

  • sent = read-back → I still agree with the bus → keep going.
  • sent recessive(1) but read-back dominant(0) → someone stronger is on the line → I lost, stop transmitting instantly, switch to just listening.

Notice the third case (sent dominant, read recessive) is impossible: from Step 3, if you send dominant the bus is dominant. So the only way to "lose" is to send a 1 and hear a 0.

WHY listen every bit instead of waiting for the end? Because if you wait until the message is finished to notice a clash, the message is already garbled and must be re-sent — that's what ordinary networks do (poll/retry style). CAN checks inside every bit, so it can bail out before it corrupts anything. That is why the survivor's message is never damaged.

PICTURE. The compare loop: transmit driver on top, sense line feeding back into a comparator.

Figure — Communication interfaces — UART, SPI, I2C (master - slave), CAN bus

Step 5 — Play it out: two nodes race their IDs

WHAT. Every CAN message begins with its identifier (ID), sent MSB-first (using a shift register, most-significant bit first). Let two nodes start at the same instant:

  • Node A: ID = 0b0100... (decimal-ish low)
  • Node B: ID = 0b0110...

Walk the bits together. At each position the bus = AND of both (Step 3), and each node compares (Step 4):

bit # A sends B sends bus (AND) A hears B hears verdict
1 0 0 0 0 ✓ 0 ✓ tie, continue
2 1 1 1 1 ✓ 1 ✓ tie, continue
3 0 1 0 0 ✓ 0 ✗ B loses here
4 0 (silent) 0 0 ✓ listening A alone

WHY B loses at bit 3. B sent recessive(1) but the bus read dominant(0) (because A sent 0). That's the exact losing condition from Step 4. B goes quiet immediately; A never even noticed a fight — every bit A sent matched the bus.

PICTURE. The two bit streams stacked, the AND'd bus below, and the pink "B drops out" marker at bit 3.

Figure — Communication interfaces — UART, SPI, I2C (master - slave), CAN bus

Step 6 — Edge case: identical IDs (or the same node "racing itself")

WHAT. If two nodes send the exact same ID, every bit ties — nobody ever hears a mismatch, so nobody drops out. Is that a disaster?

WHY it's fine. CAN forbids two different nodes from sending the same message ID at the same time by design — each message ID has a single producer. After the ID comes a control field and data; if the payloads happen to match, the two frames are identical anyway, so the bus carries one clean copy. If the rules were violated (two producers), the mismatch would surface later in the data field as an error and be flagged by CRC/error checks — the arbitration layer stays consistent, the higher layer catches the bug.

Degenerate sub-case — all-recessive idle. If nobody transmits, everyone is recessive(1), the AND is 1, the bus idles high-diff-zero. The first node to send a dominant start-of-frame bit (a 0) grabs an otherwise-empty bus with no contest.

PICTURE. Two lanes: (left) identical IDs → no mismatch ever, one clean copy; (right) idle bus, one node opens with a dominant SOF bit.

Figure — Communication interfaces — UART, SPI, I2C (master - slave), CAN bus

Step 7 — Edge case: the wire's own speed limit

WHAT. For "listen while you talk" to work, the read-back must be truthful within the same bit. A dominant bit from the far end of the bus needs time to travel down the cable and be sensed. If a bit is shorter than that round-ish trip, a node could finish a bit before it hears the clash.

WHY this caps length × speed. Rearranging, . Faster bitrate → smaller → shorter allowed cable. That is why classic CAN runs 1 Mbps only up to ~40 m, and long buses must slow down. Arbitration trades speed for reach.

PICTURE. A cable of length ; a dominant edge crawling from far node to near node; the bit window drawn wide enough to contain the trip.

Figure — Communication interfaces — UART, SPI, I2C (master - slave), CAN bus

The one-picture summary

Figure — Communication interfaces — UART, SPI, I2C (master - slave), CAN bus

The whole derivation on one board: two wires → their difference kills noise → dominant(0) always beats recessive(1) → the bus is a wired-AND → each node talks and listens every bit → the ID with the earliest 0 wins without corruption → and the bit must be long enough for the wire's travel time.

Recall Feynman retelling — say it like a story

Imagine a roomful of people, and the rule is: anyone whispering counts as silence, but anyone who claps forces the whole room to "clap." (Clap = dominant 0; whisper/silence = recessive 1.) Now everyone starts spelling out a number, one symbol per second, clapping for a 0 and staying quiet for a 1 — and crucially, while you clap-or-stay-quiet you also listen to the room. If you meant to stay quiet (a 1) but you hear a clap, it means someone with a smaller number is still in — so you politely shut up and just listen. You lost, but you never messed up their number, because your quiet added nothing. The person spelling the smallest number keeps going, bit for bit, perfectly, and never even knew there was a contest. The only catch: everyone has to be close enough that a clap reaches every ear before that second is up — which is why a fast, long CAN bus is impossible; the room can only be so big.

One-line version ::: differential wires cancel noise, wired-AND makes 0 beat 1, listen-while-you-talk lets the lowest ID win uncorrupted, and bit time must exceed the round-trip so everyone hears in time.