I²C, SPI, UART, CAN — when to use which
The bus decision tree. What each protocol is good at, where each falls over, and the gotchas that separate working systems from inscrutable bugs.
Every component on your robot — sensor, motor controller, MCU, computer — talks via some bus. Pick the wrong one and your IMU drops messages, your motor commands lag, your CAN bus collapses under contention. Four protocols cover 95% of robotics; each has a clear sweet spot. Knowing the differences saves weeks of debugging.
The four protocols
| Protocol | Speed | Wires | Distance | Devices |
|---|---|---|---|---|
| I²C | 100 kHz – 1 MHz | 2 (+ pwr) | ~1 m | Up to 127 |
| SPI | 1 – 50 MHz | 3+CS each | ~30 cm | Limited by CS pins |
| UART | 9600 – 921600 | 2 (TX/RX) | ~10 m | Point-to-point |
| CAN | 125 k – 1 Mbit | 2 differential | ~40 m | Up to ~30 nodes |
I²C: the chip-to-chip bus
Two wires (SDA + SCL) plus power. Multiple devices share the bus, addressed by 7-bit numbers. Open-drain with pull-ups.
Use for:
- IMU, magnetometer, barometer (low-rate sensors).
- OLED displays, EEPROMs.
- Multi-channel ADCs / DACs.
Strengths: many devices on two wires. Standardized addresses. Supported by every MCU.
Weaknesses: slow. Fragile to noise / long cables. Pull-up sizing matters (10 kΩ for 100 kHz; 2.2 kΩ for 400 kHz). Address conflicts when two of the same chip on one bus.
Gotchas: missing pull-ups → bus locks up. Bad pull-up sizing → corrupt data. Devices clock-stretching → master must support it.
SPI: the high-speed link
Four wires per device: MOSI, MISO, SCK, CS. Master drives clock; selected device responds.
Use for:
- SD cards, flash memory.
- High-resolution ADCs (24-bit at MHz rates).
- Absolute encoders (BiSS-C, EnDat over SPI).
- OLED / TFT displays.
- Inter-MCU links.
Strengths: fast (10–50 MHz easy). Full-duplex. Simple protocol — no addressing.
Weaknesses: needs one CS pin per device. No standard for what's "command" vs "data" — every chip has its own. Distance limited (~30 cm before signal integrity degrades).
Gotchas: SPI mode mismatch (CPOL / CPHA). Bit order (MSB vs LSB first). Chips that need a specific delay between CS-low and first SCK edge.
UART: the legacy serial
Two wires. TX from one side, RX to the other. Asynchronous (no clock — both sides must agree on baud rate).
Use for:
- Debug consoles (printf to a USB-UART adapter).
- GPS modules, cellular modems.
- MCU-to-MCU communication.
- RC servo control via Dynamixel-style protocols.
Strengths: simple. Works over long distances with RS-485 transceivers. Universal — every MCU has it.
Weaknesses: point-to-point only (in basic form). No flow control by default; can drop bytes. Baud-rate mismatch is invisible (gibberish output).
Gotchas: TX and RX are crossed between devices (TX → RX, RX → TX). 5V vs 3.3V level mismatch fries the chip. Baud rate slightly off → corruption every Nth byte.
CAN: the multi-node bus
Two-wire differential. Multiple nodes share the bus; messages have IDs (no source/dest). Designed for automotive; harsh-environment-tolerant.
Use for:
- Multi-actuator robot bus (BLDC controllers per joint).
- Industrial / automotive integration.
- Long-distance high-reliability links.
- Real-time critical control distribution.
Strengths: differential signaling = noise-immune. Built-in priority arbitration. Long cable runs (40 m at 1 Mbps; 1 km at 50 kbps). 30+ nodes on one bus.
Weaknesses: needs CAN transceiver chips ($1–5 per node). Bus topology requires terminating resistors at both ends (120 Ω). Fixed message size (8 bytes for classic CAN; 64 bytes for CAN-FD).
Gotchas: missing termination → reflections, errors. Mismatched bit-rates → no nodes communicate. CAN-FD vs classic CAN tolerance — mixing them fails.
The decision tree
- Two chips, low-rate sensors, same PCB → I²C.
- Need MHz throughput, < 30 cm → SPI.
- One device far away (GPS, RS-485) → UART.
- Multiple actuators on a robot, distributed → CAN.
- Computer ↔ MCU integration → USB (a UART variant) or Ethernet.
Other protocols you'll meet
- Ethernet: when CAN's bandwidth runs out. EtherCAT for industrial real-time; standard Ethernet for general networking.
- USB: for desktop computer ↔ device. CDC-ACM = serial-over-USB; HID = devices like joysticks.
- RS-485: like UART but differential, multi-drop. Used in older industrial systems.
- 1-Wire: single-wire bus with daisy-chained devices. Used for Dallas temperature sensors.
- I²S: I²C-flavored bus for audio data. Used in mic arrays, speakers.
EtherCAT: the industrial real-time standard
For serious multi-axis robots (UR, KUKA, Stäubli), EtherCAT is the bus of choice. Standard Ethernet hardware (cheap), real-time guarantees (sub-microsecond synchronization across many nodes), 100 Mbit. Open-source masters exist (igh-ethercat); requires a Linux PC with PREEMPT_RT.
For hobby / mid-tier production: CAN. For industrial real-time: EtherCAT. The gap in between is shrinking as ROS 2 + Cyclone DDS over standard Ethernet matures.
Choosing for a typical robot
A 6-DOF arm in 2026 might use:
- I²C: IMU on the wrist.
- SPI: absolute encoder per joint.
- UART: debug console; serial connection to GPS or external module.
- CAN: motor controllers per joint, daisy-chained back to the main MCU.
- USB: connection to the on-board Jetson.
- Ethernet: Jetson to external computer / network.
One robot, six protocols. Each does what it's best at.
Common production gotchas
- Cable length matters: 5 m of I²C cable rarely works at any speed.
- Wire twisting reduces noise: especially for differential pairs (CAN, RS-485).
- Always test under load: a protocol that works during dev might collapse with motors switching nearby.
- Logic-level converters: 3.3V MCU with 5V sensor. Add a level shifter or use a chip with 5V-tolerant inputs.
- Termination forgotten: CAN, USB, Ethernet — all need terminating resistors. Forgetting them is a top-3 robotics electronics bug.
Exercise
For a robot you've built or are designing, list every component and identify the protocol it uses. Sketch the bus topology. Note any shared buses (I²C with multiple devices). Identify which protocol bears the highest data rate; check the wire is short enough. The 30 minutes save a week of "why does this not work?"
Next
Real-time firmware: when you outgrow setup()/loop() and need an RTOS.
Comments
Sign in to post a comment.