Skip to content

CAN Bus Protocol and Frame Formats

Document ID: CAN-02 Series: Telematics Tutorial Series Target audience: Intermediate — you should understand basic networking concepts (framing, addressing, error detection) and have read CAN-01 or be familiar with CAN physical layer basics.

For physical layer and electrical design, see CAN-01. For bit timing and error handling, see CAN-03. For higher-layer protocols and socketCAN, see CAN-04. For DBC signal encoding, see DBC-01.


Learning Objectives

By the end of this document, you will be able to:

  • Describe the four CAN frame types (data, remote, error, overload) and when each is used
  • Decode a CAN 2.0A (standard), CAN 2.0B (extended), and CAN FD frame bit by bit
  • Explain how non-destructive bitwise arbitration works and why lower IDs have higher priority
  • Identify bit stuffing in a captured CAN frame and calculate the overhead it introduces
  • Calculate and verify a CAN frame’s CRC

1. CAN Protocol Overview

The Controller Area Network (CAN) protocol operates at the data link layer (Layer 2 of the OSI (Open Systems Interconnection) model). It defines how data is packaged into frames, how nodes gain access to the shared bus, and how errors are detected and handled.

CAN has three major protocol versions:

Version Standard ID bits Max data bytes Max bit rate Key feature
CAN 2.0A ISO (International Organization for Standardization) 11898-1 11 8 1 Mbit/s Original standard frame
CAN 2.0B ISO 11898-1 29 8 1 Mbit/s Extended frame with larger ID space
CAN FD ISO 11898-1:2015 11 or 29 64 Arbitration: 1 Mbit/s, Data: up to 8 Mbit/s Larger payloads, faster data phase

📝 Note: CAN 2.0A and CAN 2.0B coexist on the same bus. A CAN 2.0B controller can receive both standard and extended frames. A CAN 2.0A-only controller will ignore extended frames (it treats the **SRR (Substitute Remote Request)** and **IDE (Identifier Extension)** bits as part of the control field and discards the frame). CAN FD requires all nodes to be CAN FD-capable — a single classical CAN node on a CAN FD bus will generate error frames during the data phase.


2. Frame Types

CAN defines four frame types:

2.1 Data Frame

The data frame carries application data from a transmitter to one or more receivers. This is the primary frame type — the vast majority of traffic on any CAN bus consists of data frames.

  • Contains 0 to 8 bytes of payload (0 to 64 bytes for CAN FD)
  • Identified by an 11-bit (standard) or 29-bit (extended) identifier
  • Broadcast to all nodes on the bus — receivers filter by ID

2.2 Remote Frame

The remote frame is a request for data. A node transmits a remote frame with a specific ID to request that the node responsible for that ID transmit the corresponding data frame.

  • Identical structure to a data frame but with the RTR (Remote Transmission Request) bit set to recessive (1)
  • Contains no data payload — the DLC (Data Length Code) field indicates the expected data length
  • Rarely used in modern CAN networks — most systems use periodic transmission instead of request/response

Remote frames became obsolete because the polling model they enable is inherently inefficient on a shared bus — a requesting node must wait for the response, consuming arbitration bandwidth. The industry replaced this with periodic broadcast (producer-consumer) and event-driven models where nodes transmit data autonomously at defined intervals, eliminating request overhead and providing deterministic timing.

The fundamental problem with remote frames is the lack of delivery guarantee. When Node A sends a remote frame requesting data from Node B, there is no mechanism to ensure Node B actually responds — it may be in bus-off, may have lost arbitration to higher-priority traffic, or may simply not implement the requested ID. The periodic broadcast model eliminates this ambiguity: if a node expects engine RPM at 10 ms intervals and the message stops arriving, it knows within one missed period that something is wrong.

📝 Note: CAN FD does not support remote frames. The bit position formerly used for RTR is repurposed as the RRS (Remote Request Substitution) bit, which is always dominant (0).

2.3 Error Frame

The error frame is transmitted by any node that detects an error condition. It consists of an error flag (6 dominant or 6 recessive bits, depending on the node’s error state) followed by an error delimiter (8 recessive bits).

  • Error-active nodes transmit 6 dominant bits (active error flag) — this deliberately violates the bit-stuffing rule and forces all other nodes to detect the error
  • Error-passive nodes transmit 6 recessive bits (passive error flag) — this does not disrupt other nodes
  • Error handling and fault confinement are covered in detail in CAN-03

2.4 Overload Frame

The overload frame signals that a node needs extra time before the next frame. It is structurally identical to an error frame (6 dominant bits + 8 recessive delimiter bits) but occurs only during the interframe space.

  • Used by slow receivers to delay the start of the next data or remote frame
  • Extremely rare in modern systems — most CAN controllers handle frames fast enough that overload frames are never needed

Overload frames are primarily encountered in legacy systems with slower microcontrollers that need additional time between frames to process received data. In modern systems, they may appear as a diagnostic indicator of a node that is falling behind — if a bus analyzer shows overload frames, it typically points to an underpowered or malfunctioning node. Most CAN controllers designed after 2010 do not generate overload frames under normal conditions.

2.5 Frame Type Worked Examples

The following examples show how each frame type appears on the bus. All examples use standard (11-bit) identifiers.

Example 1 — Data Frame (engine RPM at 3000 RPM)

An ECU (Electronic Control Unit) broadcasts engine RPM. ID = 0x0C0, DLC = 2, Data = 0x0BB8 (3000 decimal).

SOF: 0
ID:  0 0 0 1 1 0 0 0 0 0 0   (0x0C0)
RTR: 0  (data frame)
IDE: 0  (standard)
r0:  0
DLC: 0 0 1 0  (2 bytes)
Data: 0 0 0 0 1 0 1 1  1 0 1 1 1 0 0 0  (0x0B, 0xB8)
CRC: [15-bit CRC computed over all above bits]
CRC Del: 1
ACK Slot: 1 (transmitter sends recessive; receivers override to 0)
ACK Del: 1
EOF: 1 1 1 1 1 1 1
IFS: 1 1 1

Example 2 — Remote Frame (requesting temperature data)

A display module requests a temperature reading from ID 0x184. No data payload is transmitted.

SOF: 0
ID:  0 0 1 1 0 0 0 0 1 0 0   (0x184)
RTR: 1  (remote frame — recessive)
IDE: 0  (standard)
r0:  0
DLC: 0 0 1 0  (expected response: 2 bytes)
Data: [absent — remote frames carry no data]
CRC: [15-bit CRC computed over SOF through DLC]
CRC Del: 1
ACK Slot: 1 → 0 (acknowledged)
ACK Del: 1
EOF: 1 1 1 1 1 1 1
IFS: 1 1 1

Example 3 — Error Frame (error-active node detects CRC mismatch)

An error-active node detects a CRC error. It immediately transmits an active error flag, destroying the current frame on the bus.

[Partial frame in progress...]
...data bits...CRC mismatch detected here
                ↓
Active error flag:   0 0 0 0 0 0  (6 dominant bits — violates bit stuffing)
Error delimiter:     1 1 1 1 1 1 1 1  (8 recessive bits)
IFS:                 1 1 1  (bus returns to idle)

All other nodes detect the bit-stuffing violation caused by the 6 dominant bits and transmit their own error flags, creating an error flag overlap of 6 to 12 dominant bits total. After the delimiter, the original transmitter retries the frame.

Example 4 — Overload Frame (slow node requests delay)

A legacy node needs additional processing time after receiving a frame. During the IFS intermission, it transmits an overload flag.

[Previous frame EOF]:  1 1 1 1 1 1 1
IFS intermission begins: 1 1 ...
                              ↓ overload detected during intermission
Overload flag:          0 0 0 0 0 0  (6 dominant bits)
Overload delimiter:     1 1 1 1 1 1 1 1  (8 recessive bits)
IFS:                    1 1 1  (normal intermission resumes)
[Next frame may now begin]

Example 5 — CAN FD Frame (48-byte firmware update payload)

A gateway node transmits a firmware update chunk using CAN FD. ID = 0x7B0, DLC = 14 (48 bytes), BRS = 1 (bit rate switch enabled).

SOF: 0
ID:  1 1 1 1 0 1 1 0 0 0 0   (0x7B0)
RRS: 0  (always dominant in CAN FD)
IDE: 0  (standard 11-bit ID)
FDF: 1  (this is a CAN FD frame)
res: 0
BRS: 1  (switch to higher data bit rate)  ← bit rate switches here
ESI: 0  (transmitter is error-active)
DLC: 1 1 1 0  (DLC 14 → 48 bytes in CAN FD)
Data: [48 bytes = 384 bits at higher data-phase bit rate]
CRC: [21-bit CRC — payload >16 bytes requires CRC-21]
CRC Del: 1  ← bit rate switches back to arbitration rate
ACK Slot: 1 → 0 (acknowledged)
ACK Del: 1
EOF: 1 1 1 1 1 1 1
IFS: 1 1 1

3. CAN 2.0A Standard Data Frame

The CAN 2.0A standard frame uses an 11-bit identifier and can carry 0 to 8 bytes of data.

3.1 Frame Structure (Bit-by-Bit)

3.2 Field Descriptions

SOF (Start of Frame) — 1 bit, always dominant (0)

packet-beta
  0: "SOF"
  1-11: "Identifier (11 bits)"
  12: "RTR"
  13: "IDE"
  14: "r0"
  15-18: "DLC (4 bits)"
  19-82: "Data (0–8 bytes)"
  83-97: "CRC-15 (15 bits)"
  98: "CRC Del"
  99: "ACK"
  100: "ACK Del"
  101-107: "EOF (7 bits)"
  108-110: "IFS (≥3)"

Figure: CAN02 01 standard frame

The SOF bit marks the beginning of a data or remote frame. All nodes synchronize their bit timing on the SOF’s falling edge (the transition from the recessive idle bus to the first dominant bit).

Identifier — 11 bits

The message identifier serves two purposes: 1. Message identification — receivers use the ID to determine whether to accept or reject the frame 2. Arbitration priority — during bus contention, lower numeric IDs win arbitration (because dominant bits override recessive bits)

The 11-bit ID provides 2,048 unique identifiers (0x000 to 0x7FF). IDs 0x000–0x00F are typically reserved for highest-priority network management messages.

⚠️ Warning: The identifier is not an address — CAN is a content-based addressing system. A CAN ID identifies the *message content*, not the sender or receiver. Multiple nodes can receive the same ID, and in theory (though not recommended) multiple nodes could transmit the same ID.

RTR (Remote Transmission Request) — 1 bit

  • Dominant (0) = data frame
  • Recessive (1) = remote frame

In a data frame, RTR is always dominant. This means that if a data frame and a remote frame with the same ID compete during arbitration, the data frame wins — ensuring that a response is never blocked by its own request.

IDE (Identifier Extension) — 1 bit

  • Dominant (0) = standard frame (11-bit ID, CAN 2.0A)
  • Recessive (1) = extended frame (29-bit ID, CAN 2.0B)

r0 (Reserved) — 1 bit, always dominant (0)

Reserved for future use. Must be transmitted as dominant.

DLC (Data Length Code) — 4 bits

Indicates the number of data bytes in the frame:

DLC value Data bytes (CAN 2.0A/B) Data bytes (CAN FD)
0000 (0) 0 0
0001 (1) 1 1
1000 (8) 8 8
1001 (9) 8 (clamped) 12
1010 (10) 8 (clamped) 16
1011 (11) 8 (clamped) 20
1100 (12) 8 (clamped) 24
1101 (13) 8 (clamped) 32
1110 (14) 8 (clamped) 48
1111 (15) 8 (clamped) 64

In classical CAN (2.0A/B), DLC values 9–15 are valid but the data payload is always clamped to 8 bytes. CAN FD uses DLC values 9–15 to encode larger payloads with the non-linear mapping shown above.

DLC Mapping Worked Examples

The following examples show how DLC values translate to actual data payload sizes across classical CAN and CAN FD:

Example DLC bits DLC value Classical CAN payload CAN FD payload Typical use case
1 0000 0 0 bytes (no data) 0 bytes Heartbeat / presence signal — the ID alone carries meaning
2 0010 2 2 bytes (16 bits) 2 bytes Single 16-bit sensor value (e.g., engine RPM)
3 0100 4 4 bytes (32 bits) 4 bytes Two 16-bit signals or one 32-bit value (e.g., odometer)
4 1000 8 8 bytes (64 bits) 8 bytes Maximum classical CAN payload — most common DLC value
5 1001 9 8 bytes (clamped) 12 bytes CAN FD: extended diagnostic response or multi-signal message
6 1100 12 8 bytes (clamped) 24 bytes CAN FD: ADAS (Advanced Driver Assistance Systems) sensor fusion data or calibration block
7 1111 15 8 bytes (clamped) 64 bytes CAN FD: firmware update chunk or bulk data transfer

📝 Note: In classical CAN, a transmitter *may* set DLC to any value 0–15, but the actual data field never exceeds 8 bytes. If a classical CAN node transmits DLC = 12 with only 8 data bytes, a receiver must not attempt to read 12 bytes from the data field — only 8 are present. CAN FD controllers, however, interpret DLC 9–15 using the non-linear mapping and transmit the full expanded payload.

Data Field — 0 to 64 bits (0 to 8 bytes)

The actual payload. Transmitted MSB (Most Significant Bit) first within each byte, but byte order is application-defined. The data field is absent when DLC = 0.

CRC Sequence — 15 bits

A Cyclic Redundancy Check computed over the SOF, identifier, control, and data fields. The generator polynomial for classical CAN is:

CRC-15: x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1
        (0x4599 — implementation constant with the implicit x^15 term omitted)

All nodes independently calculate the CRC as they receive each bit. If a receiver’s calculated CRC does not match the transmitted CRC, it signals a CRC error.

def can_crc15(data_bits):
    """Calculate CAN CRC-15 over a sequence of bits (list of 0/1)."""
    crc = 0
    for bit in data_bits:
        crc_nxt = (bit ^ ((crc >> 14) & 1))
        crc = (crc << 1) & 0x7FFF
        if crc_nxt:
            crc ^= 0x4599  # Generator polynomial
    return crc

# Test vectors
test1 = [0] * 15  # 15 zero bits
print(f"CRC-15 of 15 zero bits: 0x{can_crc15(test1):04X}")

test2 = [1, 0] * 10  # 20 alternating bits
print(f"CRC-15 of 20 alternating bits: 0x{can_crc15(test2):04X}")
# Output
CRC-15 of 15 zero bits: 0x0000
CRC-15 of 20 alternating bits: 0x5593

This function takes a list of bit values (0 or 1) representing the SOF through the end of the data field and returns the 15-bit CRC. The CRC is transmitted MSB first immediately after the data field.

CRC Delimiter — 1 bit, always recessive (1)

Separates the CRC from the acknowledgment field.

ACK Slot — 1 bit

The transmitter sends this bit as recessive. Any receiver that has successfully received the frame (matching CRC) overrides this bit to dominant during this bit time. This is the CAN acknowledgment mechanism — it happens at the physical layer during transmission, not as a separate response frame.

  • If the transmitter reads back dominant during the ACK slot, at least one receiver acknowledged the frame
  • If the transmitter reads back recessive, no node acknowledged — the transmitter flags an acknowledgment error

💡 Tip: A CAN node transmitting on a bus with no other nodes will always see an ACK error, because there is no receiver to pull the ACK slot dominant. This is normal behavior when testing a single node in isolation — it does not indicate a hardware fault.

ACK Delimiter — 1 bit, always recessive (1)

Completes the acknowledgment field.

EOF (End of Frame) — 7 bits, all recessive (1)

Seven consecutive recessive bits mark the end of the frame. Because bit stuffing (Section 6) requires a stuff bit after 5 consecutive same-polarity bits, the 7 recessive EOF bits deliberately violate the stuffing rule — this is how nodes detect the frame boundary.

Interframe Space (IFS) — minimum 3 bits, all recessive (1)

The minimum idle time between frames. Consists of: - Intermission — 3 recessive bits during which no node may start a transmission - Bus Idle — the bus remains recessive until a node begins a new SOF


4. CAN 2.0B Extended Data Frame

The CAN 2.0B extended frame extends the identifier to 29 bits by inserting an 18-bit extension after the standard 11-bit base identifier.

4.1 Frame Structure

packet-beta
  0: "SOF"
  1-11: "Base ID (11 bits)"
  12: "SRR"
  13: "IDE"
  14-31: "Extended ID (18 bits)"
  32: "RTR"
  33: "r1"
  34: "r0"
  35-38: "DLC (4 bits)"
  39-102: "Data (0–8 bytes)"
  103-117: "CRC-15 (15 bits)"
  118: "CRC Del"
  119: "ACK"
  120: "ACK Del"
  121-127: "EOF (7 bits)"
  128-130: "IFS (≥3)"

Figure: CAN02 02 extended frame

4.2 Key Differences from Standard Frame

SRR (Substitute Remote Request) — 1 bit, always recessive (1)

This bit occupies the same position as the RTR bit in a standard frame. It is always transmitted as recessive in an extended frame. This ensures that during arbitration, if a standard frame and an extended frame share the same 11-bit base ID, the standard frame wins (because RTR dominant beats SRR recessive at this bit position).

IDE (Identifier Extension) — 1 bit, recessive (1)

In the extended frame, IDE is recessive (1), signaling that the 18-bit extended ID follows. In a standard frame, IDE is dominant (0).

Extended Identifier — 18 bits

Combined with the 11-bit base ID, this gives a total of 29 bits — providing 536,870,912 unique identifiers. The full 29-bit ID is used for both arbitration and message identification.

RTR — 1 bit

Same function as in the standard frame, but positioned after the extended ID.

r1, r0 (Reserved) — 2 bits, both dominant (0)

Two reserved bits instead of one. Both must be transmitted as dominant.

4.3 Arbitration Between Standard and Extended Frames

When a standard frame and an extended frame with the same 11-bit base ID compete for the bus:

  1. Both transmit the same 11 base ID bits — no winner yet
  2. At the RTR/SRR bit position:
  3. Standard frame transmits RTR (dominant if it’s a data frame)
  4. Extended frame transmits SRR (always recessive)
  5. The standard data frame wins — it sends dominant while the extended frame sends recessive

This means standard frames always have priority over extended frames with the same base ID. The full priority ordering is:

  1. Standard data frame (lowest ID wins)
  2. Standard remote frame (same ID as above, but RTR is recessive)
  3. Extended data frame (SRR is recessive, then IDE is recessive)
  4. Extended remote frame (same as above, but RTR after extended ID is recessive)

5. CAN FD Frame

CAN Flexible Data-rate (CAN FD), defined in ISO 11898-1:2015, extends classical CAN with two major improvements: - Larger payloads — up to 64 bytes per frame (vs. 8 for classical CAN) - Higher data-phase bit rate — up to 8 Mbit/s during the data portion of the frame

5.1 Frame Structure

                                          Data phase at
                                          higher bit rate
packet-beta
  0: "SOF"
  1-11: "Identifier (11 bits)"
  12: "RRS"
  13: "IDE"
  14: "FDF"
  15: "res"
  16: "BRS"
  17: "ESI"
  18-21: "DLC (4 bits)"
  22-533: "Data (0–64 bytes)"
  534-554: "CRC-17 or CRC-21"
  555: "CRC Del"
  556: "ACK"
  557: "ACK Del"
  558-564: "EOF (7 bits)"
  565-567: "IFS (≥3)"

Figure: CAN02 03 canfd frame

5.2 New and Changed Fields

RRS (Remote Request Substitution) — 1 bit, always dominant (0)

Replaces the RTR bit. CAN FD does not support remote frames — this bit is always dominant.

FDF (FD Format) — 1 bit, recessive (1)

This bit occupies the position of the r0 bit in classical CAN. In classical CAN, r0 is always dominant (0). In CAN FD, FDF is recessive (1). This is how CAN FD controllers distinguish FD frames from classical frames — a recessive bit at this position means “this is a CAN FD frame.”

⚠️ Warning: A classical CAN controller seeing a recessive bit at the r0 position will interpret it as a form error and transmit an error frame. This is why you cannot mix classical CAN nodes and CAN FD nodes on the same bus — the classical node will destroy every FD frame.

res (Reserved) — 1 bit, dominant (0)

Reserved for future protocol extensions.

BRS (Bit Rate Switch) — 1 bit

  • Dominant (0) = the entire frame uses the arbitration bit rate (no switch)
  • Recessive (1) = the data phase (from BRS to CRC delimiter) uses the higher data-phase bit rate

When BRS is recessive, the bit rate switches to the data-phase rate starting with the next bit after BRS. The rate switches back to the arbitration rate at the CRC delimiter.

ESI (Error State Indicator) — 1 bit

  • Dominant (0) = the transmitter is in the error-active state
  • Recessive (1) = the transmitter is in the error-passive state

This gives all receivers immediate visibility into the transmitter’s error state — a feature not available in classical CAN.

CRC — 17 or 21 bits

CAN FD uses a longer CRC to protect the larger payload:

Payload size CRC length Generator polynomial
0–16 bytes 17 bits CRC-17: x^17 + x^16 + x^14 + x^13 + x^11 + x^6 + x^4 + x^3 + x + 1
20–64 bytes 21 bits CRC-21: x^21 + x^20 + x^13 + x^11 + x^7 + x^4 + x^3 + 1

Additionally, CAN FD inserts fixed stuff bits in the CRC field — one stuff bit after every 4 CRC bits, with a defined parity pattern. This improves error detection compared to classical CAN’s CRC-15.

5.3 CAN 2.0 vs CAN FD Comparison

Feature CAN 2.0A CAN 2.0B CAN FD
ID length 11 bits 29 bits 11 or 29 bits
Max data bytes 8 8 64
Max arbitration rate 1 Mbit/s 1 Mbit/s 1 Mbit/s
Max data rate 1 Mbit/s 1 Mbit/s 8 Mbit/s
CRC CRC-15 CRC-15 CRC-17 or CRC-21
Remote frames Yes Yes No
Error state in frame No No Yes (ESI)
Stuff bit count in CRC No No Yes (fixed stuff bits)
Backward compatible Yes (with 2.0A) No (breaks classical nodes)
graph TB
    subgraph CAN20A["CAN 2.0A — Standard Frame"]
        direction LR
        A_SOF["SOF
1b"] --- A_ID["ID
11b"] --- A_RTR["RTR
1b"] --- A_IDE["IDE
1b"] --- A_R0["r0
1b"] --- A_DLC["DLC
4b"] --- A_DATA["Data
0-8B"] --- A_CRC["CRC-15
15b"] --- A_ACK["ACK
2b"] --- A_EOF["EOF
7b"] end subgraph CAN20B["CAN 2.0B — Extended Frame"] direction LR B_SOF["SOF
1b"] --- B_BID["Base ID
11b"] --- B_SRR["SRR
1b"] --- B_IDE["IDE
1b"] --- B_EID["Ext ID
18b"] --- B_RTR["RTR
1b"] --- B_R["r1,r0
2b"] --- B_DLC["DLC
4b"] --- B_DATA["Data
0-8B"] --- B_CRC["CRC-15
15b"] --- B_ACK["ACK
2b"] --- B_EOF["EOF
7b"] end subgraph CANFD["CAN FD — Flexible Data-rate Frame"] direction LR F_SOF["SOF
1b"] --- F_ID["ID
11/29b"] --- F_RRS["RRS
1b"] --- F_IDE["IDE
1b"] --- F_FDF["FDF
1b"] --- F_RES["res
1b"] --- F_BRS["BRS
1b"] --- F_ESI["ESI
1b"] --- F_DLC["DLC
4b"] --- F_DATA["Data
0-64B"] --- F_CRC["CRC
17/21b"] --- F_ACK["ACK
2b"] --- F_EOF["EOF
7b"] end style B_SRR fill:#00CED1,stroke:#333,color:#000 style B_EID fill:#00CED1,stroke:#333,color:#000 style F_FDF fill:#FF69B4,stroke:#333,color:#000 style F_BRS fill:#FF69B4,stroke:#333,color:#000 style F_ESI fill:#FF69B4,stroke:#333,color:#000 style F_RRS fill:#FF69B4,stroke:#333,color:#000 style F_DATA fill:#DDA0DD,stroke:#333 style F_CRC fill:#FFA500,stroke:#333 style CAN20A fill:#E3F2FD,stroke:#1565C0 style CAN20B fill:#E0F7FA,stroke:#00838F style CANFD fill:#FCE4EC,stroke:#C62828

Figure: CAN02 05 frame comparison


6. Bit Stuffing

Bit stuffing is a mechanism that ensures sufficient signal transitions on the bus for clock synchronization. CAN uses NRZ (Non-Return-to-Zero) encoding, which means the signal level stays constant for consecutive identical bits — without stuffing, a long run of identical bits would provide no edges for receivers to resynchronize their clocks. After every sequence of 5 consecutive bits of the same polarity, the transmitter inserts one stuff bit of the opposite polarity.

6.1 How It Works

Original data:  1 1 1 1 1 0 0 0 0 0 0 1 1
After stuffing: 1 1 1 1 1 [0] 0 0 0 0 0 [1] 0 1 1
                          ↑               ↑
                     stuff bit        stuff bit

In this example: - Five consecutive 1s are followed by a stuff bit of 0 - Five consecutive 0s (including the stuff bit) are followed by a stuff bit of 1

Receivers automatically detect and remove stuff bits — they are not part of the actual data.

6.2 Where Stuffing Applies

Frame region Bit stuffing? Notes
SOF Yes SOF is always dominant — starts the first stuff sequence
Identifier Yes
RTR / SRR / RRS Yes
IDE Yes
Extended ID Yes
FDF / res / BRS / ESI Yes CAN FD control bits
DLC Yes
Data field Yes
CRC sequence Yes (classical) / Fixed pattern (CAN FD) CAN FD uses fixed stuff bits in CRC
CRC delimiter No Fixed recessive, no stuffing
ACK field No Fixed format, no stuffing
EOF No Fixed 7 recessive bits — intentionally violates stuffing
IFS No Fixed recessive bits

6.3 Stuff Bit Overhead

In the worst case (alternating sequences of 5 identical bits), bit stuffing adds one extra bit for every 4 data bits — a 25% overhead. In practice, the overhead for typical data patterns is 5–15%.

def stuffed_length(bits):
    """Calculate the length of a bit sequence after stuffing."""
    if not bits:
        return 0
    stuffed = [bits[0]]
    count = 1
    for i in range(1, len(bits)):
        if bits[i] == bits[i-1]:
            count += 1
        else:
            count = 1
        stuffed.append(bits[i])
        if count == 5:
            # Insert stuff bit of opposite polarity
            stuff_bit = 1 - bits[i]
            stuffed.append(stuff_bit)
            count = 1
    return len(stuffed)

# Worst case: 40 identical bits
worst = [0] * 40
print(f"40 identical bits → {stuffed_length(worst)} bits after stuffing")

# Best case: alternating bits
best = [i % 2 for i in range(40)]
print(f"40 alternating bits → {stuffed_length(best)} bits after stuffing")
# Output
40 identical bits → 49 bits after stuffing
40 alternating bits → 40 bits after stuffing

💡 Tip: When calculating worst-case frame transmission times for bus-load analysis, always use the worst-case stuffed frame length. A CAN 2.0A frame with 8 data bytes and worst-case stuffing is 132 bits for the frame itself (SOF through EOF), or 135 bits including the 3-bit IFS — compared to 108 bits (frame) or 111 bits (cycle) without stuffing.


7. Arbitration

Arbitration is the process by which CAN nodes compete for bus access without collisions or data loss. It is non-destructive — the winning node’s frame is transmitted successfully, and losing nodes retry automatically.

7.1 How Arbitration Works

  1. A node that wants to transmit waits for the bus to be idle (recessive).
  2. It begins transmitting its frame starting with SOF (dominant).
  3. While transmitting each bit of the identifier, the node simultaneously reads the bus.
  4. If the bus value matches what the node transmitted, it continues.
  5. If the node transmitted a recessive bit but reads back dominant, another node is transmitting a dominant bit at the same position — the first node has lost arbitration.
  6. The losing node immediately stops transmitting and becomes a receiver for the winning frame.
  7. After the winning frame completes, the losing node retries.
sequenceDiagram
    participant A as Node A (ID: 0x645)
    participant BUS as CAN Bus
    participant B as Node B (ID: 0x643)

    Note over A,B: Both nodes start transmitting simultaneously

    A->>BUS: SOF (dominant)
    B->>BUS: SOF (dominant)
    Note over BUS: Bus = dominant 

    A->>BUS: Bits 10-3: 1100 0100
    B->>BUS: Bits 10-3: 1100 0100
    Note over BUS: IDs match so far — both continue

    A->>BUS: Bit 2: sends 1 (recessive)
    B->>BUS: Bit 2: sends 0 (dominant)
    Note over BUS: Bus = dominant (Node B wins)

    Note over A: Node A reads dominant but sent recessive
→ ARBITRATION LOST
Node A stops transmitting B->>BUS: Bit 1: sends 1 B->>BUS: Bit 0: sends 1 Note over BUS: Only Node B transmits from here B->>BUS: RTR, Control, Data, CRC, ACK, EOF Note over A,B: Node B's frame completes without interruption
Node A retries after bus idle

Figure: CAN02 04 arbitration

7.2 Why Lower IDs Win

CAN uses a wired-AND bus (see CAN-01, Section 2.1): - Any node driving dominant overrides recessive - Recessive only appears when no node drives dominant

During arbitration, each node transmits its identifier bit by bit. At the first bit position where two identifiers differ: - The node with a dominant bit (0) at that position sees its own bit on the bus — it continues (wins) - The node with a recessive bit (1) at that position sees dominant on the bus (from the other node) — it lost, because it sent recessive but read back dominant

Since 0 (dominant) wins over 1 (recessive), lower numeric IDs always win arbitration.

7.3 Arbitration Examples

Example 1 — Two nodes, loss at bit 2

Two nodes transmit simultaneously:

Bit position:  10  9  8  7  6  5  4  3  2  1  0
Node A (0x645): 1  1  0  0  1  0  0  0  1  0  1
Node B (0x643): 1  1  0  0  1  0  0  0  0  1  1
Bus result:     1  1  0  0  1  0  0  0  0  ←  ←

                                          ↑
                                  Node A sent 1 (recessive)
                                  Node B sent 0 (dominant)
                                  Bus shows 0 → Node A loses

At bit position 2, Node A transmits recessive (1) while Node B transmits dominant (0). Node A reads back dominant — it has lost arbitration and stops transmitting. Node B continues uninterrupted.

Example 2 — Three-way arbitration, resolved at the MSB

Three nodes compete. The highest-priority node wins at the very first ID bit.

Bit position:  10  9  8  7  6  5  4  3  2  1  0
Node A (0x400): 1  0  0  0  0  0  0  0  0  0  0
Node B (0x200): 0  1  0  0  0  0  0  0  0  0  0
Node C (0x100): 0  0  1  0  0  0  0  0  0  0  0
Bus result:     0  ←  ←
                ↑
        Node A sent 1, bus shows 0 → Node A loses immediately
        Nodes B and C continue to bit 9...
        Node B sent 1, bus shows 0 → Node B loses
        Node C (0x100) wins — lowest ID

Node C wins with the lowest ID (0x100). Node A dropped out at bit 10, Node B at bit 9.

Example 3 — Same ID, data frame vs. remote frame

A data frame and a remote frame with the same ID (0x123) compete. The RTR bit breaks the tie.

Bit position:  10  9  8  7  6  5  4  3  2  1  0  RTR
Data  (0x123):  0  0  1  0  0  1  0  0  0  1  1   0 (dominant)
Remote(0x123):  0  0  1  0  0  1  0  0  0  1  1   1 (recessive)
Bus result:     0  0  1  0  0  1  0  0  0  1  1   0
                                                   ↑
                                          Remote frame sent 1, bus shows 0 → remote loses

The data frame always wins over a remote frame with the same ID — this ensures that a data response is never blocked by its own request.

Example 4 — Standard frame vs. extended frame (same base ID)

A standard data frame (0x100) and an extended frame (base ID 0x100, extended ID 0x3FFFF) compete. The SRR/IDE bits resolve it.

Bit position:        10  9  8  7  6  5  4  3  2  1  0  RTR/SRR  IDE
Standard (0x100):     0  0  1  0  0  0  0  0  0  0  0    0       0
Extended (0x100.xxx): 0  0  1  0  0  0  0  0  0  0  0    1       1
Bus result:           0  0  1  0  0  0  0  0  0  0  0    0       ←
                                                          ↑
                                              Extended sent SRR=1, bus shows 0 → extended loses

Standard frames always win over extended frames with the same 11-bit base ID because SRR is always recessive while RTR (for a data frame) is dominant.

Example 5 — Closely spaced IDs, high bus contention

On a busy powertrain bus, four nodes attempt transmission within the same bit time. IDs differ only in the lowest bits.

Bit position:  10  9  8  7  6  5  4  3  2  1  0
Node A (0x10F): 0  0  1  0  0  0  0  1  1  1  1
Node B (0x10B): 0  0  1  0  0  0  0  1  0  1  1
Node C (0x109): 0  0  1  0  0  0  0  1  0  0  1
Node D (0x108): 0  0  1  0  0  0  0  1  0  0  0
Bus result:     0  0  1  0  0  0  0  1  0  0  0
                                        ↑  ↑  ↑
                              Bit 2: A   B  C
                              drops     drops drops
                                        at 1  at 0

Resolution sequence: All four nodes match through bit 3. At bit 2, Node A sends 1 (recessive) while B, C, and D send 0 (dominant) — Node A loses. At bit 1, Node B sends 1 while C and D send 0 — Node B loses. At bit 0, Node C sends 1 while D sends 0 — Node C loses. Node D (0x108) wins as the lowest ID.

📝 Note: Arbitration occurs only during the identifier field (and the RTR/SRR/IDE bits). By the time the DLC field begins, only one node is transmitting. The data field is never subject to arbitration.

7.4 Arbitration and Message Design

Because arbitration priority is determined by the ID value, you must design your CAN message ID scheme with priority in mind:

ID range Typical use Priority
0x000–0x00F Network management, NMT (Network Management) Highest
0x010–0x0FF Safety-critical real-time data (e.g., ABS (Anti-lock Braking System), airbag) High
0x100–0x3FF Powertrain, drivetrain data Medium-high
0x400–0x5FF Chassis, body control Medium
0x600–0x7EF Infotainment, diagnostics Lower
0x7F0–0x7FF Often reserved (OBD-II (On-Board Diagnostics) uses 0x7DF–0x7EF) Lowest standard IDs

⚠️ Warning: Never assign ID 0x000 to a periodic high-frequency message. ID 0x000 has the highest priority and will win arbitration against all other messages. If it transmits frequently, it can starve lower-priority messages from ever accessing the bus.


8. Acknowledgment Mechanism

CAN’s acknowledgment mechanism is unique — it happens within the transmitted frame, not as a separate response.

8.1 How ACK Works

  1. The transmitter sends the ACK slot bit as recessive (1).
  2. Every receiver that has successfully received the frame up to this point (matching CRC) drives the ACK slot dominant (0).
  3. The transmitter reads the bus during the ACK slot:
  4. If dominant → at least one receiver acknowledged the frame (success)
  5. If recessive → no receiver acknowledged (ACK error)
Transmitter sends:     ... CRC Del | ACK Slot (1) | ACK Del ...
                                     ↑ recessive
Receiver A overrides:                ACK Slot (0)
                                     ↑ dominant
Bus result:            ... CRC Del | ACK Slot (0) | ACK Del ...
                                     ↑ dominant = acknowledged

8.2 ACK Implications

  • ACK only confirms reception, not processing — a receiver ACKs as soon as the CRC matches. It does not guarantee that the application layer has processed the data.
  • Any one receiver is enough — even if 30 of 31 receivers have failed, the one remaining receiver still provides the ACK.
  • No individual acknowledgment — the transmitter cannot determine which node(s) acknowledged, only that at least one did.
  • Bus sniffers must be careful — a listen-only node does not ACK. If a sniffer is the only other node on the bus, the transmitter will see ACK errors. Either configure the sniffer’s transceiver to normal mode (not listen-only) or ensure at least one other active node is present.

9. CRC Calculation Walkthrough

Let’s trace a complete CRC-15 calculation for a simple CAN 2.0A frame.

9.1 Example Frame

  • ID: 0x123 (binary: 001 0010 0011)
  • RTR: 0 (data frame)
  • IDE: 0 (standard frame)
  • r0: 0
  • DLC: 1 (one data byte)
  • Data: 0xAB (binary: 1010 1011)

The CRC is calculated over the unstuffed bit stream from SOF through the end of the data field:

SOF: 0
ID:  0 0 1 0 0 1 0 0 0 1 1
RTR: 0
IDE: 0
r0:  0
DLC: 0 0 0 1
Data: 1 0 1 0 1 0 1 1

Total input bits: 1 + 11 + 1 + 1 + 1 + 4 + 8 = 27 bits

# CRC-15 calculation for our example frame
def can_crc15(bits):
    crc = 0
    for bit in bits:
        crc_nxt = bit ^ ((crc >> 14) & 1)
        crc = (crc << 1) & 0x7FFF
        if crc_nxt:
            crc ^= 0x4599
    return crc

frame_bits = [
    0,                            # SOF
    0,0,1,0,0,1,0,0,0,1,1,       # ID = 0x123
    0,                            # RTR
    0,                            # IDE
    0,                            # r0
    0,0,0,1,                      # DLC = 1
    1,0,1,0,1,0,1,1              # Data = 0xAB
]

crc = can_crc15(frame_bits)
print(f"CRC-15 = 0x{crc:04X} = {crc:015b}")
# Output
CRC-15 = 0x666F = 110011001101111

The 15-bit CRC value 0x666F (binary 110 0110 0110 1111) is transmitted MSB first immediately after the data field.

9.2 CRC-17 for CAN FD (≤16 Bytes)

CAN FD frames with data fields up to 16 bytes use a 17-bit CRC for stronger error detection than the classical CRC-15. The longer polynomial provides better Hamming distance properties for the larger frame sizes that CAN FD supports.

"""CRC-17 for CAN FD frames with data fields up to 16 bytes.
Polynomial: x^17 + x^16 + x^14 + x^13 + x^11 + x^6 + x^4 + x^3 + x + 1
Hex: 0x3685B (full 18-bit polynomial representation including x^17 term)
"""

def crc17_canfd(data_bits: list[int]) -> int:
    """Calculate CRC-17 for CAN FD frames.

    Args:
        data_bits: List of bits (0 or 1) from SOF through data field

    Returns:
        17-bit CRC value
    """
    POLY = 0x3685B  # x^17 + x^16 + x^14 + x^13 + x^11 + x^6 + x^4 + x^3 + x + 1
    crc = 0x1FFFF   # Initialize to all ones (17 bits)

    for bit in data_bits:
        msb = (crc >> 16) & 1
        crc = ((crc << 1) | bit) & 0x1FFFF
        if msb ^ bit:
            crc ^= POLY

    return crc

# Test vector 1: 8 bytes of 0x00 (64 zero bits)
test_bits = [0] * 64
result = crc17_canfd(test_bits)
print(f"CRC-17 of 64 zero bits: 0x{result:05X}")

# Test vector 2: 8 bytes of 0x55 (alternating bits)
test_0x55 = [0, 1, 0, 1, 0, 1, 0, 1] * 8
result2 = crc17_canfd(test_0x55)
print(f"CRC-17 of 8x 0x55 (64 bits): 0x{result2:05X}")

# Test vector 3: 16 bytes of 0xAA (max payload for CRC-17)
test_0xAA = [1, 0, 1, 0, 1, 0, 1, 0] * 16
result3 = crc17_canfd(test_0xAA)
print(f"CRC-17 of 16x 0xAA (128 bits): 0x{result3:05X}")
# Output
CRC-17 of 64 zero bits: 0x2773B
CRC-17 of 8x 0x55 (64 bits): 0x3D74E
CRC-17 of 16x 0xAA (128 bits): 0x3F129

9.3 CRC-21 for CAN FD (>16 Bytes)

CAN FD frames with data fields exceeding 16 bytes use a 21-bit CRC. The longer CRC is necessary because frames carrying 20 to 64 data bytes have significantly more bits to protect, and the CRC-17 polynomial does not provide sufficient Hamming distance at those lengths.

"""CRC-21 for CAN FD frames with data fields exceeding 16 bytes.
Polynomial: x^21 + x^20 + x^13 + x^11 + x^7 + x^4 + x^3 + x + 1
Hex: 0x302899 (full 22-bit polynomial representation including x^21 term)
"""

def crc21_canfd(data_bits: list[int]) -> int:
    """Calculate CRC-21 for CAN FD frames.

    Args:
        data_bits: List of bits (0 or 1) from SOF through data field

    Returns:
        21-bit CRC value
    """
    POLY = 0x302899
    crc = 0x1FFFFF  # Initialize to all ones (21 bits)

    for bit in data_bits:
        msb = (crc >> 20) & 1
        crc = ((crc << 1) | bit) & 0x1FFFFF
        if msb ^ bit:
            crc ^= POLY

    return crc

# Test vector 1: 24 bytes of 0x55 (alternating bits, 192 bits total)
test_bits = [0, 1] * 96  # alternating 0,1 pattern
result = crc21_canfd(test_bits)
print(f"CRC-21 of 192 alternating bits: 0x{result:06X}")

# Test vector 2: 24 bytes of 0x00 (192 zero bits)
test_zeros = [0] * 192
result2 = crc21_canfd(test_zeros)
print(f"CRC-21 of 192 zero bits: 0x{result2:06X}")

# Test vector 3: 64 bytes of 0x55 (max CAN FD payload, 512 bits)
test_max = [0, 1, 0, 1, 0, 1, 0, 1] * 64
result3 = crc21_canfd(test_max)
print(f"CRC-21 of 64x 0x55 (512 bits): 0x{result3:06X}")
# Output
CRC-21 of 192 alternating bits: 0x006D27
CRC-21 of 192 zero bits: 0x2FA44B
CRC-21 of 64x 0x55 (512 bits): 0x309D4A

📝 Note: CAN FD uses CRC-17 for frames with ≤16 data bytes and CRC-21 for frames with >16 data bytes. Both CRCs include a stuff-bit count field and use Gray-coded stuff bits for improved error detection. The implementation above covers the basic CRC computation — a complete implementation must also account for the fixed stuff bits inserted before the CRC field.


10. Interframe Spacing

The gap between consecutive frames on the CAN bus is defined by the Interframe Space (IFS), which ensures nodes have time to process a received frame before the next one begins.

10.1 IFS Components

Intermission — 3 bits (recessive)

After the EOF of a frame, no node may start transmitting for 3 bit times. This is the minimum recovery period.

Bus Idle — variable length (recessive)

After the intermission, the bus remains in the idle (recessive) state until a node initiates a new frame with an SOF bit.

Suspend Transmission — 8 bits (error-passive nodes only)

An error-passive node must wait an additional 8 recessive bit times after the intermission before it can start a new transmission. This gives error-active nodes priority access to the bus — a form of penalty for nodes that are accumulating errors.

10.2 Maximum Bus Utilization

The theoretical maximum bus utilization depends on the frame size and the interframe spacing. For a CAN 2.0A frame with 8 data bytes:

  • Minimum frame length (no stuffing, SOF through EOF): 108 bits
  • Interframe space: 3 bits (mandatory intermission)
  • Total minimum cycle (frame + IFS): 111 bits

The 108-bit frame length for a maximum-length classical CAN standard data frame (8 data bytes) breaks down as follows:

SOF(1) + ID(11) + RTR(1) + IDE(1) + r0(1) + DLC(4) + Data(64) + CRC(15) + CRC_del(1) + ACK(2) + EOF(7) = 108 bits

Adding the mandatory 3-bit IFS (Interframe Space) intermission gives the widely cited 111-bit minimum cycle:

Frame(108) + IFS(3) = 111 bits per frame cycle

Note: Data(64) means 8 bytes x 8 bits = 64 bits for a maximum-length data frame. The ACK field comprises the ACK slot (1 bit) and ACK delimiter (1 bit), totaling 2 bits.

def can_bus_utilization(bit_rate, frame_bits=108, ifs_bits=3, n_messages_per_sec=None):
    """Calculate CAN bus utilization.

    Args:
        bit_rate: Bus bit rate in bits per second
        frame_bits: Bits in the frame itself (SOF through EOF), default 108 for 8-byte CAN 2.0A
        ifs_bits: Interframe space bits (mandatory intermission), default 3
        n_messages_per_sec: If provided, return utilization percentage; otherwise return max frames/sec

    Returns:
        Max frames per second (if n_messages_per_sec is None) or utilization percentage
    """
    total_bits_per_cycle = frame_bits + ifs_bits  # 108 + 3 = 111 for standard 8-byte frame
    max_frames_per_sec = bit_rate / total_bits_per_cycle
    if n_messages_per_sec:
        utilization = (n_messages_per_sec * total_bits_per_cycle) / bit_rate * 100
        return utilization
    return max_frames_per_sec

# Maximum frames per second at 500 kbit/s
max_fps = can_bus_utilization(500000)
print(f"Max frames/sec at 500 kbit/s: {max_fps:.0f}")

# Bus utilization with 2000 messages per second
util = can_bus_utilization(500000, n_messages_per_sec=2000)
print(f"Bus utilization at 2000 msg/s: {util:.1f}%")
# Output
Max frames/sec at 500 kbit/s: 4505
Bus utilization at 2000 msg/s: 44.4%

💡 Tip: Keep CAN bus utilization below 70% for reliable real-time performance. Above this level, lower-priority messages experience increasing latency due to lost arbitrations. For safety-critical systems, 30–50% utilization is a common design target.

10.3 Worst-Case Frame Timing Calculator

The worst case for CAN frame timing occurs when bit stuffing is maximized. After every 5 consecutive same-value bits, a stuff bit of the opposite value is inserted. This calculator computes the maximum possible frame duration for both classical CAN and CAN FD frames.

def worst_case_frame_time_us(bitrate_kbps: int, dlc: int = 8, is_fd: bool = False) -> float:
    """Calculate worst-case CAN frame duration including maximum bit stuffing.

    Args:
        bitrate_kbps: Arbitration bit rate in kbit/s
        dlc: Data Length Code (0-8 for classical, 0-15 for CAN FD)
        is_fd: True for CAN FD frame

    Returns:
        Worst-case frame time in microseconds
    """
    # Data length mapping for CAN FD
    fd_dlc_to_bytes = {0:0, 1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8,
                       9:12, 10:16, 11:20, 12:24, 13:32, 14:48, 15:64}

    if is_fd:
        data_bytes = fd_dlc_to_bytes.get(dlc, 8)
    else:
        data_bytes = min(dlc, 8)

    data_bits = data_bytes * 8

    if not is_fd:
        # Classical CAN cycle: SOF(1) + ID(11) + RTR(1) + IDE(1) + r0(1) + DLC(4) + Data + CRC(15) + CRC_del(1) + ACK(2) + EOF(7) + IFS(3)
        fixed_bits = 1 + 11 + 1 + 1 + 1 + 4 + 15 + 1 + 2 + 7 + 3
        stuffable_bits = 1 + 11 + 1 + 1 + 1 + 4 + data_bits + 15  # SOF through CRC
        stuff_bits = stuffable_bits // 4  # worst case: 1 stuff bit per 4 data bits
        total_bits = fixed_bits + data_bits + stuff_bits
    else:
        # CAN FD simplified (arbitration phase only for this calculator)
        fixed_bits = 1 + 11 + 1 + 1 + 1 + 1 + 1 + 4  # SOF+ID+various control
        crc_bits = 17 if data_bytes <= 16 else 21
        stuffable_bits = fixed_bits + data_bits + crc_bits
        stuff_bits = stuffable_bits // 4
        total_bits = stuffable_bits + stuff_bits + 1 + 2 + 7 + 3  # + CRC_del + ACK + EOF + IFS

    bit_time_us = 1000.0 / bitrate_kbps
    return total_bits * bit_time_us

# Examples
for dlc in [0, 1, 4, 8]:
    t = worst_case_frame_time_us(500, dlc)
    print(f"Classical CAN @ 500 kbit/s, DLC={dlc}: {t:.1f} µs")

print()
for dlc in [8, 12, 15]:
    t = worst_case_frame_time_us(500, dlc, is_fd=True)
    print(f"CAN FD @ 500 kbit/s arb, DLC={dlc}: {t:.1f} µs")
# Output
Classical CAN @ 500 kbit/s, DLC=0: 110.0 µs
Classical CAN @ 500 kbit/s, DLC=1: 130.0 µs
Classical CAN @ 500 kbit/s, DLC=4: 190.0 µs
Classical CAN @ 500 kbit/s, DLC=8: 270.0 µs

CAN FD @ 500 kbit/s arb, DLC=8: 280.0 µs
CAN FD @ 500 kbit/s arb, DLC=12: 610.0 µs
CAN FD @ 500 kbit/s arb, DLC=15: 1410.0 µs

Troubleshooting

# Symptom Likely cause Diagnostic step Resolution
1 ACK errors on every frame No other node on the bus, or all receivers are in listen-only mode Verify at least one other active node is powered and connected Add a second node, or switch bus sniffer from listen-only to normal mode
2 CRC errors on received frames Bus signal integrity issue, incorrect bit timing Capture oscilloscope waveform; check bit timing settings match on all nodes Fix physical layer (see CAN-01), synchronize bit rate and sample point across all nodes
3 Frames with wrong DLC or data Mismatched DBC (DBC database file — see DBC-01) definition or firmware bug Compare raw frame bytes against the DBC file or specification Update DBC or firmware to match the actual frame format
4 Extended frames not received by some nodes Receiver has CAN 2.0A-only controller that discards extended frames Check controller datasheets for CAN 2.0B support Replace the controller or use only standard (11-bit) frames
5 Bus load too high, messages delayed Too many high-frequency messages, or message IDs not prioritized correctly Measure bus load with a CAN analyzer; identify highest-frequency messages Reduce transmission rates, redesign ID scheme for proper prioritization, consider CAN FD
6 Error frames during CAN FD data phase Classical CAN node on a CAN FD bus Check all nodes for CAN FD support Remove or replace the classical CAN node; CAN FD requires all nodes to be FD-capable
7 Intermittent lost messages under load Arbitration losses with no retry (firmware bug) or transmit buffer overflow Monitor TX error counters and buffer status Increase transmit buffer depth, ensure firmware handles arbitration loss gracefully

References

  1. ISO 11898-1:2015 — Road vehicles — Controller area network (CAN) — Part 1: Data link layer and physical signalling. International Organization for Standardization. Defines CAN 2.0 and CAN FD frame formats, arbitration, error detection, and bit stuffing.

  2. Robert Bosch GmbH (1991) — CAN Specification Version 2.0. The original CAN specification. Part A defines the standard frame; Part B defines the extended frame.

  3. Robert Bosch GmbH (2012) — CAN with Flexible Data-Rate Specification, Version 1.0. The original CAN FD specification before ISO standardization.

  4. CiA (CAN in Automation) — CAN FD — The basic idea. Technical overview of CAN FD features and backward compatibility considerations.

  5. Microchip Application Note AN713 — Controller Area Network (CAN) Basics. Introduction to CAN frame formats and arbitration.

  6. NXP Application Note AN12728 — CAN FD — Quick Start Guide. Practical guide to CAN FD implementation including frame format details.

  7. Vector Informatik — CAN Newsletter: CAN FD — Frame Format and Bit Timing. Detailed analysis of CAN FD frame structure and CRC changes.


Changelog

Version Date Author Summary of changes
1.0 2026-03-16 Telematics Tutorial Series Initial publication

```