CAN
Controller Area Network — the backbone of in-vehicle communication.
Overview
CAN is a robust, message-based serial bus introduced by Bosch. ECUs broadcast frames identified by an arbitration ID; lower IDs win arbitration. CRC, ACK, and bit-stuffing make it extremely reliable for hard real-time control such as engine, transmission and ABS.
Frame format
| Field | Bits | Description |
|---|---|---|
| SOF | 1 | Start of Frame (dominant) |
| Identifier | 11 / 29 | Standard or extended message ID |
| RTR | 1 | Remote transmission request |
| Control | 6 | IDE + reserved + DLC (data length code) |
| Data | 0–64 | Up to 8 bytes of payload |
| CRC | 16 | 15-bit CRC + delimiter |
| ACK | 2 | Acknowledge slot + delimiter |
| EOF | 7 | End of Frame (recessive) |
All CAN Frame Formats (ISO 11898-1)
Five frame types defined by the CAN protocol. Bit values: 0 = dominant, 1 = recessive.
Standard Data Frame (CAN 2.0A — 11-bit ID)
44 + 8·DLC bits (max 108 bits with 8-byte payload)Transports application payload using an 11-bit identifier.
| Field | Bits | Value | Description |
|---|---|---|---|
| SOF | 1 | 0 | Start Of Frame — dominant bit, marks frame start. |
| Identifier | 11 | 0x000–0x7FF | Message ID; lower value = higher priority. |
| RTR | 1 | 0 | Remote Transmission Request — dominant for data frame. |
| IDE | 1 | 0 | Identifier Extension — dominant = standard format. |
| r0 | 1 | 0 | Reserved bit, transmitted as dominant. |
| DLC | 4 | 0–8 | Data Length Code — number of payload bytes. |
| Data | 0–64 | payload | Application payload, 0 to 8 bytes. |
| CRC | 15 | computed | Cyclic Redundancy Check over preceding fields. |
| CRC Delimiter | 1 | 1 | Recessive delimiter bit. |
| ACK Slot | 1 | 1→0 | Transmitter sends recessive; receivers pull dominant. |
| ACK Delimiter | 1 | 1 | Recessive delimiter bit. |
| EOF | 7 | 1111111 | End Of Frame — seven recessive bits. |
| IFS | ≥3 | 111 | Inter-Frame Space — minimum gap before next frame. |
Extended Data Frame (CAN 2.0B — 29-bit ID)
64 + 8·DLC bits (max 128 bits)Same as standard but with 29-bit identifier (used by SAE J1939, OBD-II 29-bit).
| Field | Bits | Value | Description |
|---|---|---|---|
| SOF | 1 | 0 | Start Of Frame. |
| Base ID (ID-A) | 11 | upper 11 bits | Most significant 11 bits of 29-bit identifier. |
| SRR | 1 | 1 | Substitute Remote Request — recessive in extended frame. |
| IDE | 1 | 1 | Identifier Extension — recessive = extended format. |
| Extended ID (ID-B) | 18 | lower 18 bits | Lower 18 bits of 29-bit identifier. |
| RTR | 1 | 0 | Remote Transmission Request — dominant for data frame. |
| r1 | 1 | 0 | Reserved bit. |
| r0 | 1 | 0 | Reserved bit. |
| DLC | 4 | 0–8 | Data Length Code. |
| Data | 0–64 | payload | 0 to 8 bytes. |
| CRC | 15 | computed | CRC over preceding fields. |
| CRC Delimiter | 1 | 1 | Recessive. |
| ACK Slot | 1 | 1→0 | Acknowledged by any receiver. |
| ACK Delimiter | 1 | 1 | Recessive. |
| EOF | 7 | 1111111 | End Of Frame. |
| IFS | ≥3 | 111 | Inter-Frame Space. |
Remote Frame (RTR)
44 bits (standard) / 64 bits (extended)Requests a data frame with the same identifier from another node. No payload is transmitted.
| Field | Bits | Value | Description |
|---|---|---|---|
| SOF | 1 | 0 | Start Of Frame. |
| Identifier | 11 or 29 | target ID | ID of the data frame being requested. |
| RTR | 1 | 1 | RECESSIVE — distinguishes remote from data frame. |
| IDE | 1 | 0/1 | Standard (0) or Extended (1) format. |
| r0 (+r1) | 1 or 2 | 0 | Reserved bits. |
| DLC | 4 | expected length | Length of the requested data — no actual payload sent. |
| Data | 0 | — | No data field in a remote frame. |
| CRC | 15 | computed | CRC over the remote frame. |
| CRC Delimiter | 1 | 1 | Recessive. |
| ACK Slot + Delim | 2 | 0,1 | Acknowledgement. |
| EOF | 7 | 1111111 | End Of Frame. |
Error Frame
12–18 bits (variable)Signals a detected bus error (bit, stuff, CRC, form, or ACK error). Aborts the current frame for all nodes.
| Field | Bits | Value | Description |
|---|---|---|---|
| Error Flag (active) | 6 | 000000 | Six consecutive DOMINANT bits transmitted by an error-active node. Violates bit-stuffing → all nodes detect. |
| Error Flag (passive) | 6 | 111111 | Six consecutive RECESSIVE bits transmitted by an error-passive node. |
| Error Flag Echo | 0–6 | 000000 | Other nodes append their own error flags after detecting the violation (superposition). |
| Error Delimiter | 8 | 11111111 | Eight recessive bits marking the end of the error frame. |
| IFS | ≥3 | 111 | Inter-Frame Space before bus returns to normal arbitration. |
Note: Error states: Error-Active (TEC<128 & REC<128), Error-Passive (≥128), Bus-Off (TEC≥256). Bus-off requires reset/recovery sequence (128×11 recessive bits).
Overload Frame
14–20 bitsForces extra delay between data/remote frames when a receiver is not ready or detects illegal IFS bits.
| Field | Bits | Value | Description |
|---|---|---|---|
| Overload Flag | 6 | 000000 | Six dominant bits, similar to active error flag. |
| Overload Flag Echo | 0–6 | 000000 | Other nodes superimpose their own overload flags. |
| Overload Delimiter | 8 | 11111111 | Eight recessive bits ending the overload frame. |
| IFS | ≥3 | 111 | Inter-Frame Space resumes normal bus operation. |
Note: Triggered by: (a) receiver internal conditions, or (b) detection of dominant bit during IFS / EOF (last bit) / inter-frame gap.
| Frame type | Identifier | Payload | RTR | IDE | Purpose |
|---|---|---|---|---|---|
| Standard Data | 11-bit | 0–8 B | 0 | 0 | Send payload |
| Extended Data | 29-bit | 0–8 B | 0 | 1 | J1939, OBD 29-bit |
| Remote | 11/29-bit | — | 1 | 0/1 | Request data |
| Error | — | — | — | — | Signal bus error |
| Overload | — | — | — | — | Force extra delay |
| DLC (dec) | DLC (hex / 4 bits) | Classic CAN bytes | CAN-FD bytes | Notes |
|---|---|---|---|---|
| 0 | 0x0 | 0 | 0 | Empty payload (valid; ACK only). |
| 1 | 0x1 | 1 | 1 | |
| 2 | 0x2 | 2 | 2 | |
| 3 | 0x3 | 3 | 3 | |
| 4 | 0x4 | 4 | 4 | |
| 5 | 0x5 | 5 | 5 | |
| 6 | 0x6 | 6 | 6 | |
| 7 | 0x7 | 7 | 7 | |
| 8 | 0x8 | 8 | 8 | Maximum payload for Classic CAN. |
| 9 | 0x9 | 8* | 12 | Classic CAN: clamped to 8 bytes (DLC 9–15 transmitted but data length stays 8). |
| 10 | 0xA | 8* | 16 | CAN-FD only beyond 8 bytes. |
| 11 | 0xB | 8* | 20 | |
| 12 | 0xC | 8* | 24 | |
| 13 | 0xD | 8* | 32 | |
| 14 | 0xE | 8* | 48 | |
| 15 | 0xF | 8* | 64 | Maximum payload for CAN-FD. |
Legal frame with no data bytes. Used for handshakes / triggers (e.g., wakeup). CRC is still computed over header + (empty) data.
Receiver MUST clamp data length to 8 bytes. Some legacy controllers (e.g., older SJA1000) transmit DLC=15 but only 8 data bytes; others reject. Test stacks should accept and normalize.
If the application supplies fewer bytes than DLC indicates, controllers typically pad with 0x00 (CAN_PAD_DATA), 0xCC, or undefined memory. Always pad explicitly in test scripts.
Lengths like 9, 10, 11 bytes are NOT representable. Application must pad up to next valid length: 12, 16, 20, 24, 32, 48, 64. ISO-TP/CAN-TP stacks insert padding bytes (often 0xCC or 0xAA).
Classic CAN: SF up to 7 data bytes (1 byte PCI + 7 data). CAN-FD: SF up to 62 bytes via escape PCI (2-byte PCI + up to 62). Beyond → multi-frame (FF/CF).
When payload length ∈ {9, 10, 11, 13, 14, 15, 17–19, 21–23, 25–31, 33–47, 49–63}, the stack MUST pad to next valid DLC. Common padding: 0xCC (Vector), 0xAA (some OEMs), 0x00 (default).
Remote frames carry DLC = expected response length but transmit ZERO data bytes. Receivers must not interpret any bytes after the DLC/CRC sequence as payload.
After 5 identical consecutive bits, transmitter inserts an opposite stuff bit. Worst case adds ~24% overhead; effective frame length varies, complicating exact bus-load calculation.
CAN Frame Validator
Enter the bit-level fields of a CAN frame; each format is checked against ISO 11898-1 rules.
- ID fits 11 bits (≤ 0x7FF)0x123 = 9 bits
- IDE = 0 (standard)
- RTR = 0 (data frame)
- DLC 0–15 (data clamped to 8)effective length = 8 bytes
- Data bytes match effective lengthprovided 8, expected 8
- ACK slot = 0 (dominant)
- CRC present (15-bit)
- ID fits 29 bits (≤ 0x1FFFFFFF)9 bits used
- IDE = 1 (extended)
- RTR = 0 (data frame)
- DLC 0–15 (data clamped to 8)effective length = 8 bytes
- Data bytes match effective lengthprovided 8, expected 8
- ACK slot = 0 (dominant)
- CRC present (15-bit)
- ID fits 11 bits
- IDE = 0 (standard)
- RTR = 1 (remote)
- DLC 0–8 (requested length)
- Data field empty (no payload)provided 8 bytes
- ACK slot = 0 (dominant)
- CRC present (15-bit)
- ID fits 29 bits
- IDE = 1 (extended)
- RTR = 1 (remote)
- DLC 0–8 (requested length)
- Data field empty (no payload)provided 8 bytes
- ACK slot = 0 (dominant)
- CRC present (15-bit)
- No identifier (N/A)Error frames have no ID/DLC fields — cannot match a user-supplied frame.
- No identifier (N/A)Overload frames have no ID/DLC fields — cannot match a user-supplied frame.
CAN Test Case Generator
Generates a functional + boundary + negative test matrix for the CAN frame you describe. Adapts to Classic CAN vs CAN-FD and 11-bit vs 29-bit identifiers.
Happy path — valid data frame
Remote frame request
Minimum payload (DLC=0)
Maximum 11-bit identifier
Maximum Classic CAN payload (8 B, DLC=8)
ID out of range
DLC mismatch — fewer data bytes than DLC claims
RTR with payload (illegal)
Bus-off recovery
CAN Test Script Generator
Emits runnable Python (python-can) and CAPL (Vector CANoe) scripts that send a CAN request, wait for the expected response, and report pass/fail.
"""
Auto-generated CAN test script (python-can)
Request : 0x7E0 -> 02 10 03
Expected: 0x7E8
Bus : can0 @ 500000 bps (Classic CAN)
"""
import can
import sys
REQ_ID = 0x7E0
RESP_ID = 0x7E8
REQ_DATA = [0x02, 0x10, 0x03]
EXTENDED = False
TIMEOUT_S = 1.00
def main() -> int:
bus = can.interface.Bus(
channel="can0",
bustype="socketcan",
bitrate=500000,
fd=False,
)
msg = can.Message(
arbitration_id=REQ_ID,
data=REQ_DATA,
is_extended_id=EXTENDED,
is_fd=False,
)
print(f"TX {hex(REQ_ID)} {bytes(REQ_DATA).hex(' ')}")
bus.send(msg)
rx = bus.recv(timeout=TIMEOUT_S)
if rx is None:
print("FAIL: timeout waiting for response")
return 1
print(f"RX {hex(rx.arbitration_id)} {bytes(rx.data).hex(' ')}")
if rx.arbitration_id != RESP_ID:
print(f"FAIL: expected ID {hex(RESP_ID)}, got {hex(rx.arbitration_id)}")
return 2
print("PASS")
return 0
if __name__ == "__main__":
sys.exit(main())
Byte structure — request & response
Classical CAN — ISO 11898-1
[SOF:1b][ID:11b][RTR:1b][IDE:1b][r0:1b][DLC:4b][Data:0–8B][CRC:15b][CRC-Del:1b][ACK:1b][ACK-Del:1b][EOF:7b]| Off | Size | Field | Value | Description |
|---|---|---|---|---|
| 0 | 11 bit | Arbitration ID | 0x123 | Message identifier (lower = higher priority). |
| — | 1 bit | RTR | 0 | 0 = data frame, 1 = remote request. |
| — | 4 bit | DLC | 0x8 | Data length code (0–8). |
| 0…7 | 0–8 B | Data | 11 22 33 44 55 66 77 88 | Payload bytes (max 8). |
| — | 15 bit | CRC | auto | CRC over SOF…Data. |
| — | 1 bit | ACK slot | 0 | Receivers pull dominant to acknowledge. |
| Off | Size | Field | Value | Description |
|---|---|---|---|---|
| 0 | 11 bit | Arbitration ID | 0x124 | Reply uses a different broadcast ID (CAN has no per-message reply concept). |
| — | 4 bit | DLC | 0x2 | Number of data bytes. |
| 0…1 | 2 B | Data | 0F 01 | Application response payload. |
| — | 1 bit | ACK | 0 | Other nodes acknowledge bit. |
CAN is broadcast: there is no inherent request/response. Higher protocols (UDS, J1939) layer Q/R semantics on top of two CAN IDs (e.g. 0x7E0 → 0x7E8).
Use cases
- · Powertrain control
- · Body electronics
- · ABS / ESP
- · Instrument cluster
Pros
- Deterministic arbitration
- Mature ecosystem
- Robust error detection
Cons
- Max 8 bytes payload
- Bandwidth limited to 1 Mbit/s
- No native security
Request / Response examples
Engine RPM broadcast (ID 0x0C9)
Bytes 2–3 (0x0FA0) decode to 4000 RPM using factor 0.25 RPM/bit.
Door lock command (ID 0x3B0)
Byte 0 = command (lock all), byte 1 = mask. ECU echoes the new lock state.