CAN Bus

Controller Area Network is the backbone of in-vehicle communication. Learn the differential bus and termination, frame format (identifier, DLC, data, CRC, ACK), arbitration by priority, bit timing, error handling and bus-off, bus-load calculation, DBC signal databases and CAN FD.

Since the late 1980s, CAN has let ECUs share data over two wires instead of point-to-point wiring. It's robust against noise, prioritises urgent messages automatically, and detects errors reliably — the reason it's still in every car.

Engineers design message schedules so buses stay below safe load, and use tools like CANalyzer and DBC files to decode signals.

An analogy

CAN is like a meeting where anyone may speak, but if two start at once, the one with the higher-priority title automatically continues and the other politely waits — nobody's words get garbled.

Physical layer

Two twisted wires, CAN_H and CAN_L, carry a differential signal — noise affects both equally and cancels. Recessive (logical 1): both ≈ 2.5 V; dominant (logical 0): CAN_H ≈ 3.5 V, CAN_L ≈ 1.5 V. 120 Ω terminators at both ends prevent reflections (measure 60 Ω across the bus when powered off).

Frames and arbitration

A data frame: SOF, identifier, control (DLC), up to 8 data bytes, 15-bit CRC, ACK, EOF. All nodes transmit identifier bits simultaneously; a dominant 0 overwrites a recessive 1, so the lowest identifier (highest priority) wins without collision — non-destructive arbitration.

Error handling

Bit, stuff, CRC, form and ACK errors are detected; the detecting node sends an error frame and the message is retransmitted. Error counters move nodes from error-active to error-passive to bus-off, isolating faulty nodes automatically.

Scheduling, CAN FD and CAN XL

Bus load is typically kept below 50–70 % for latency margin; worst-case response-time analysis verifies deadlines. CAN FD raises data-phase bit rate to 2–8 Mbit/s and payload to 64 bytes; CAN XL reaches 10–20 Mbit/s and 2048 bytes. Security via SecOC message authentication.

Formulas

Worked example: Bus load

Given: 500 kbit/s bus; 20 messages every 10 ms + 30 messages every 100 ms; ≈ 125 bits per frame

Find: Bus load.

Answer: ≈ 58 % — acceptable but little room to add messages

Worked example: Arbitration

Given: Node A sends ID 0x120, node B sends ID 0x0C8 simultaneously

Find: Who wins?

Answer: Node B (0x0C8)

Sending a frame with Linux SocketCAN (C)

#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>

int main(void) {
    int s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    struct ifreq ifr; strcpy(ifr.ifr_name, "can0");
    ioctl(s, SIOCGIFINDEX, &ifr);
    struct sockaddr_can addr = { .can_family = AF_CAN, .can_ifindex = ifr.ifr_ifindex };
    bind(s, (struct sockaddr *)&addr, sizeof addr);

    struct can_frame f = { .can_id = 0x0C8, .can_dlc = 8 };
    uint16_t rpm_raw = 3000 * 4;              /* signal scaling 0.25 rpm/bit */
    f.data[0] = rpm_raw & 0xFF;               /* little-endian (Intel) signal */
    f.data[1] = rpm_raw >> 8;
    write(s, &f, sizeof f);
    close(s);
    return 0;
}

The DBC file defines each signal's start bit, length, byte order, scale and offset — both sender and receiver must agree.

DBC signal definition

BO_ 200 EngineData: 8 ECM
 SG_ EngineSpeed : 0|16@1+ (0.25,0) [0|16383.75] "rpm" TCM,BCM,IC
 SG_ CoolantTemp : 16|8@1+ (1,-40) [-40|215] "degC" IC
 SG_ ThrottlePos : 24|8@1+ (0.4,0) [0|102] "%" TCM

Message 200 (0x0C8), 8 bytes from the ECM: EngineSpeed starts at bit 0, 16 bits, Intel byte order, unsigned, 0.25 rpm/bit.

Common mistakes

Applications

Key takeaways

Going further