Embedded

SPI vs I2C vs UART

By CourseTron Team ·  8 min read ·  Updated Oct 2026 💬 𝕏 in f
Table of Contents
    🖨  Download / Print this guide (PDF)

    In short: spi vs i2c vs uart comes down to three trade-offs — speed, pin count, and how many devices share the bus. SPI is the fastest and simplest to clock but needs a chip-select line per peripheral; I2C uses just two shared wires and device addresses but tops out slower; UART is a cheap, clockless point-to-point link ideal for connecting two chips or a console.

    What Is spi vs i2c vs uart?

    SPI (Serial Peripheral Interface), I2C (Inter-Integrated Circuit) and UART (Universal Asynchronous Receiver/Transmitter) are the three serial communication protocols you will meet on almost every microcontroller and embedded board. They all move data one bit at a time over a small number of wires, but they differ in how they clock that data, how they address peripherals, and how fast and how far they can push bits.

    The quick mental model: UART is a two-wire conversation between exactly two parties with no shared clock. I2C is a two-wire shared bus where many devices listen and a controller calls each one by address. SPI is a four-wire bus built for raw speed, where the controller selects one peripheral at a time with a dedicated line.

    How Each One Is Wired

    Wiring is the single clearest way to tell these protocols apart, because the pin count drives most of the other trade-offs.

    UART — two wires, crossed

    UART needs just TX (transmit) and RX (receive), plus a common ground. The TX of one device connects to the RX of the other and vice versa. There is no clock line, so both ends must agree in advance on a baud rate. It is inherently point-to-point: one device talks to exactly one other.

    I2C — two wires, shared

    I2C uses SDA (serial data) and SCL (serial clock), both open-drain and pulled high by resistors. Every device hangs off the same two lines, so adding a tenth sensor costs no extra pins on the controller — only a unique address.

    SPI — four wires plus a select per device

    SPI uses SCLK (clock), MOSI (controller out, peripheral in), MISO (peripheral out, controller in) and one CS/SS (chip-select) line per peripheral. Five peripherals means five chip-selects, which is SPI's main scaling cost.

    Wiring: UART, I2C and SPIUARTABTX → RXRX ← TX2 wires plus groundNo clock linePoint-to-pointI2CSCLSDACtrlDev 1Dev 22 wires, open-drainShared busUnique address per deviceSPICtrlPeriphSCLKMOSIMISOCS4 wires plus one CSper extra peripheralTX/RX cross over in UART; SPI adds a chip-select line for every device.CourseTron · coursetron.com
    Wiring of the three protocols: UART crosses TX and RX between two devices, I2C shares SCL and SDA among many, SPI uses SCLK, MOSI, MISO and a CS per peripheral.

    Why It Matters: Speed, Duplex and Addressing

    Choosing the wrong bus shows up later as missed deadlines, bus contention, or a redesign when you run out of pins. Three properties decide the fit.

    Clocking and speed

    SPI is synchronous — the controller drives SCLK, so the peripheral never has to guess timing, and clock rates of 10–50+ MHz are routine, making SPI the go-to for displays, SD cards and high-rate ADCs. I2C is also synchronous but open-drain pull-ups limit standard modes to 100 kHz, 400 kHz, 1 MHz (Fast-mode Plus) and 3.4 MHz (High-speed). UART is asynchronous with no clock wire; common baud rates run 9,600 to 115,200, with higher rates possible but sensitive to clock-accuracy mismatch.

    Full vs half duplex

    SPI is full duplex: MOSI and MISO carry data in both directions simultaneously, and in fact a bit is shifted out and in on every clock edge. I2C is half duplex: one shared SDA line means a device either sends or receives at a given moment, never both. UART is full duplex because TX and RX are separate wires, though many simple links only use one direction.

    SPI is full duplex: one bit each way per SCLK edgeControllerPeripheralSCLKMOSI →← MISOA read and a write happen in the same transactionCourseTron · coursetron.com
    Animated: on every SCLK edge one bit leaves MOSI while one bit arrives on MISO, so SPI reads and writes at once.

    Addressing and device count

    I2C wins on scaling — a 7-bit address field allows up to 112 usable addresses on two wires. SPI has no addressing; the controller asserts a chip-select to pick a device, so device count is bounded by available GPIO. UART has no addressing at all and connects exactly two endpoints (barring extra transceiver hardware like RS-485).

    SPI vs I2C vs UART at a glanceSPII2CUARTClockSynchronous (SCLK)Synchronous (SCL)Asynchronous, noneSpeed10–50+ MHz100 kHz to 3.4 MHz9,600–115,200 baudDuplexFullHalfFullAddressingCS line per device7-bit, 112 usableNone, 2 endpointsCourseTron · coursetron.com
    Side-by-side comparison of clocking, speed, duplex and addressing for SPI, I2C and UART.
    Key fact: SPI transfers are inherently full duplex — on every SCLK edge one bit leaves MOSI and one bit arrives on MISO, so a read and a write happen in the same transaction. I2C, sharing a single SDA line, can only be half duplex.

    How Engineers Choose in Practice

    There is no universally "best" protocol — the right choice follows the peripheral and the board constraints.

    • Pick SPI when throughput matters: TFT/OLED displays, SD/microSD cards, high-speed sensors (IMUs sampling fast), and external flash. Accept the extra chip-select pins as the price of speed and full duplex.
    • Pick I2C when you have many low-rate peripherals and few pins: temperature/humidity sensors, EEPROMs, RTCs, small OLEDs, and port expanders. The two-wire bus and addressing keep wiring trivial as the device list grows.
    • Pick UART for point-to-point links and human-facing interfaces: debug consoles, GPS modules, GSM/LTE and Bluetooth classic modules, and chip-to-chip links where only two devices talk.

    Common failure modes are protocol-specific too. On I2C, a forgotten or wrong-value pull-up resistor is the number-one cause of a dead bus, and two devices sharing one address force you to use an address-select pin or an I2C mux. On UART, a baud-rate mismatch or wrong framing (data bits, parity, stop bits) produces garbage characters. On SPI, the usual culprit is a wrong mode (CPOL/CPHA) so the controller samples on the wrong clock edge.

    How Industry Tools Handle It

    Professional bring-up rarely relies on guesswork. A logic analyzer (Saleae, or an open-source sigrok/PulseView setup) captures the raw lines and decodes SPI, I2C and UART frames in software, so you can confirm an I2C address acknowledgment (ACK/NACK) or read the actual bytes on MOSI. An oscilloscope with protocol decode verifies signal integrity — rise times on I2C pull-ups, clean SPI clock edges. On the firmware side, vendor HALs (STM32 HAL/LL, ESP-IDF, Zephyr, Linux's `spidev` and `i2c-dev`) expose each bus through driver APIs, and device trees or board files declare which pins and clock rates a peripheral uses. Mastering these decode-and-verify tools is what separates a datasheet reader from an engineer who can debug a bus at 2 a.m.

    Learn this hands-on

    Real projects and industry tool flows, with certification.

    Explore CourseTron Courses →

    spi vs i2c vs uart — Interview FAQ

    Which is faster: SPI, I2C or UART, and why?

    SPI is the fastest. Its push-pull clock line has no open-drain pull-up limiting rise time, so it clocks comfortably at tens of MHz. I2C is capped by its open-drain bus (typically up to 400 kHz or 1 MHz Fast-mode Plus, 3.4 MHz High-speed). UART, being asynchronous, is limited by clock-accuracy tolerance between the two ends and usually runs well below 1 Mbps.

    Why does I2C need pull-up resistors but SPI does not?

    I2C lines are open-drain: devices can only pull SDA/SCL low, so an external pull-up resistor restores the high level and lets any device signal without bus contention. SPI uses push-pull drivers that actively drive both high and low, so it needs no pull-ups.

    Is UART synchronous or asynchronous, and what must both sides agree on?

    UART is asynchronous — there is no shared clock wire. Both ends must independently agree on the baud rate plus the frame format: number of data bits, parity, and stop bits. A start bit lets the receiver synchronize to each frame.

    How do you select a specific device on each bus?

    On SPI, the controller asserts that device's dedicated chip-select (CS/SS) line. On I2C, the controller sends the device's 7-bit (or 10-bit) address at the start of a transaction and the matching device ACKs. On UART there is no addressing — it is inherently point-to-point between two devices.

    Related: a related topic · the VLSI Glossary · all courses.

    Advertisement