I2C vs SPI vs UART: Choosing the Right Serial Protocol for Embedded Hardware
Why Protocol Selection Matters
Every sensor, display, memory chip, or co-processor you connect to a microcontroller uses one of a handful of serial communication protocols. Choosing the wrong one increases wiring complexity, limits data throughput, or creates timing conflicts. Understanding the trade-offs between I2C, SPI, and UART saves hours of debugging.
Protocol Comparison Overview
| Property | I2C | SPI | UART | | :--- | :--- | :--- | :--- | | Wires | 2 (SDA + SCL) | 4+ (MOSI, MISO, CLK, CS per device) | 2 (TX + RX) | | Max Speed | 400 kHz (Fast) / 3.4 MHz (HS) | 10–80 MHz | Up to 115200 baud (typical) | | Multi-device | Yes, software addressing (127 devices) | Yes, one CS pin per device | No (point-to-point) | | Duplex | Half-duplex | Full-duplex | Full-duplex | | Hardware Complexity | Low | Medium | Very low |
When to Use I2C
I2C uses only 2 wires and supports up to 127 devices on the same bus via 7-bit addresses. It is ideal when:
- You have limited GPIO pins available
- Multiple sensors of the same type need addressing (e.g. four BME280 sensors on one bus — though address conflicts require external multiplexers)
- Throughput requirements are below 400kHz (temperature, pressure, accelerometer readings)
// ESP32 I2C read example
#include <Wire.h>
#define BME280_ADDR 0x76
Wire.begin(SDA_PIN, SCL_PIN);
Wire.beginTransmission(BME280_ADDR);
Wire.write(0xF3); // Status register
Wire.endTransmission();
Wire.requestFrom(BME280_ADDR, 1);
uint8_t status = Wire.read();
When to Use SPI
SPI is the fastest option but requires more wires — one Chip Select (CS) line per peripheral. Use SPI when:
- You need high throughput (TFT displays, SD card readers, ADCs)
- Full-duplex simultaneous read/write is required
- Low-level protocol timing matters (e.g. SPI Mode 0 vs Mode 3)
When to Use UART
UART is the simplest point-to-point protocol. Use it when:
- Communicating with one dedicated peripheral (GPS module, GSM modem, fingerprint scanner)
- Debugging via serial monitor
- Bridging two microcontrollers across longer cable runs
Practical Rule of Thumb
- Many slow sensors on few pins → I2C
- High-speed single peripherals (displays, SD cards) → SPI
- One external module with its own protocol → UART
Designing custom hardware with multiple peripherals? Let's talk →
Frequently Asked Questions
Q:Can I use both I2C and SPI on the same ESP32?
Yes. The ESP32 supports two independent I2C buses and three SPI buses simultaneously. You can mix protocols freely across different GPIO pins.
Q:What causes I2C bus lockup and how do I fix it?
I2C lockup usually happens when a slave device holds SDA low during a failed transaction. Send 9 clock pulses on SCL manually, then issue a STOP condition. Many I2C libraries have a bus recovery function for this.
Related Engineering Notes
Related Project Cases
Matching Services Tracks
Working on something similar?
Let's collaborate to design custom PCB schematics, write deterministic FreeRTOS threads, or configure secure Next.js databases.