The CAN protocol
What is a CAN bus?
A CAN bus is just two wires, CAN_H and CAN_L, twisted together, with a 120 Ω resistor across them at each end. Every node hangs off the same pair. Below are three nodes; in a real car you might have dozens.
Each node has a central unit, typically a microcontroller, and a transceiver that
turns its logic-level TX bit into bus voltages and reports back what it reads on
RX. The controller never touches the bus directly. Everyone shares the pair and samples
every bit at the same point in time.
Dominant and recessive
CAN's two bit states aren't "high" and "low". They're dominant (0) and
recessive (1). A transceiver actively drives the bus to send dominant; for
recessive it just lets go and the bus relaxes to a resting voltage on its own. If any node drives
dominant, every node reads dominant - recessive only shows up when nobody is driving. If one node
transmits a 0 and another transmits a 1 at the same time, 0 wins.
The bitstream
Here's a real frame as raw bits, in transmission order, after bit-stuffing (explained below).
It's the same string the Frame Inspector shows. Each character is one bit on the wire. Edit it and
everything below re-draws live (only 0 and 1 are accepted).
Bit-stuffing
A CAN receiver resyncs its clock off every bit edge, so a long run of identical bits with no edge would let it drift. A transmitter prevents that by watching its own output and inserting one bit of the opposite polarity after every five identical bits in a row, whether or not the data needed it. Every receiver knows the rule and removes that extra bit on the way back out. These stuff bits are called out separately in the table and scope below.
CAN Bitfields
Those bits are packed into fixed fields: a start bit, the ID (which also sets priority), a few control bits, up to 8 bytes of data, a CRC checksum, an ACK slot, and an end marker. The table below is the live parse of the bitstream above. Hover a row to light up its bits in the oscilloscope.
Expand the table to see the field-by-field breakdown and edit it directly. Change a value there and the bitstream rewrites itself, including a freshly computed CRC. The two views are the same frame seen two ways, so editing one edits the other.
Bit-field layout - editable field table, click to expand
| Field | Width | Bits (on the wire) | Value |
|---|
CAN Voltages
Now the voltages. Each bit becomes a level on CAN_H and CAN_L; what
the transceiver actually decides is the difference between them. RX can run
at any logic-level voltage depending on the transceiver, commonly 3.3 V or 5 V; this page
assumes 3.3 V. The traces below are drawn to scale and share one voltage axis: the 3.3 V logic
swing is taller than the ~1 V each individual CAN line moves between dominant and recessive. Drag
your mouse across to read out any bit.
CAN_H and CAN_L look noisy on purpose. Both pick up the same electrical
hash because they're twisted together and run side by side. Watch the CAN_H − CAN_L trace:
it stays clean. The noise hits both wires equally, so subtracting one from the other cancels it. That's
why CAN survives in an engine bay - the receiver only ever looks at the difference.
How ACK works
Find the ACK bit in the scope (the red column). The transmitter sends the whole frame, but when it hits the ACK slot it deliberately goes recessive and listens. Any node that received the frame with a good CRC slams the bus dominant for that single bit. Wired-AND does the rest: the transmitter reads back a dominant bit it didn't send, which proves at least one other node is alive and got the message.
- Sender TX drives the whole frame but releases the ACK slot to recessive.
- Receiver TX stays recessive the whole frame except it pulls the ACK slot dominant.
- Bus / RX is the wired-AND: identical to the sender everywhere except the ACK bit.
Nobody answers? The ACK slot stays recessive, the transmitter flags an ACK error and retransmits, assuming auto-retransmission is enabled. Put a single node on a bus with no listeners and, with that default on, it will retry forever.
Avoid collisions with arbitration
No master, no scheduler. Any node can start sending the moment the bus goes idle, and two nodes
sometimes start in the same bit time. When that happens, both write to the bus at once, and dominant
wins, so nobody loses data: every transmitter watches the bus while it sends, and the
instant it sends a recessive 1 but reads back a dominant 0, it knows a
higher-priority message is talking over it. It backs off and becomes a receiver. The winner never even
notices.
The race happens over the SOF bit and the ID: whichever node has more early dominant
bits, usually the lower ID, keeps going. Enter two hex IDs below and hover the graph to see exactly where
the loser drops out. You can mix standard and extended frames too: if they share the same base ID, the
standard frame wins, because right after the ID it sends a dominant RTR bit (Remote
Transmission Request: recessive for a remote frame, dominant for data) and a dominant IDE
bit (Identifier Extension: recessive means an extended 29-bit ID follows), while the extended frame has to
send a recessive SRR in that same slot (Substitute Remote Request, a placeholder that
keeps the two frame types lined up bit-for-bit). Dominant beats recessive, so standard wins. Try ECU A
123 (Std) against ECU B 123 (Ext) and watch where it splits.
Nothing gets corrupted. Unlike an Ethernet collision, no frame is lost. The high-priority frame goes out with zero delay; the loser just retries the moment the bus is free. The ID is the only thing arbitration looks at, so the ID is the priority.
Which messages get the low IDs?
Two broad kinds of traffic share the bus, and the ID assignment isn't an accident:
- Periodic ("mission-time") messages are the stuff the car needs constantly: engine
RPM, wheel speed, steering angle. These fire on a fixed clock, often every
10 msor20 ms, and they get the lowest IDs so they win arbitration and arrive on time. - Aperiodic messages are event-driven traffic, like a button press or a diagnostic tool asking a question. They show up irregularly and usually carry higher IDs, so a chatty diagnostic session can never starve the powertrain frames that keep the car running.
Designers hand out IDs with this in mind: the more time-critical the message, the lower its ID. Priority isn't a separate setting you configure. It falls straight out of the number you chose.