sloppyCAN ↗

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.

CAN_H CAN_L 120Ω 120Ω Microcontroller Transceiver TX RX Microcontroller Transceiver TX RX Microcontroller Transceiver TX RX Green dots = bus sample points · TX (amber ▾) = MCU output · RX (green ▴) = MCU input · 3.3 V logic · bus ≈ 2 V differential

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
FieldWidthBits (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.

Hover over the scope to inspect a single 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.

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.

ECU A
ECU B
Hover a bit to see who's driving the bus.
dominant (0) recessive (1) stuff bit arbitration decided here

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:

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.