30% off your first 3 months

Get the deal

I2C, SPI and UART: how parts talk to each other

by DuckyHelperNov 12, 20265 min read
Robotics

TL;DR:

  • UART is two wires, no clock, and both sides must agree on a baud rate. I2C is two shared wires with an address per device. SPI is four-plus wires and fast, with one chip select per device.

  • A shared clock (I2C, SPI) lets the receiver know exactly when to sample. UART instead relies on both sides agreeing on timing.

  • Pick by what the part supports first, then by speed, wire count and how many parts share the bus.

A small robot has an inertial measurement unit (IMU) that reports turning and acceleration, a GPS receiver that reports position, and a microcontroller that wants both. The parts are on different chips and need to exchange bytes. There are a few standard ways to do that, and each part you buy will support one or two of them.

Wires, speed and addressing

Feature

UART

I2C

SPI

Wires

TX and RX (plus ground), crossed between two devices

SDA (data) and SCL (clock), shared by all devices, plus ground

SCK (clock), MOSI (out), MISO (in), plus one chip-select line per device, plus ground

Clock

None. Both sides agree on a baud rate

Shared clock from the controller

Shared clock from the controller

Devices

Two, point to point

Many on the same two wires

Many, each needing its own chip-select pin

Addressing

None needed

Each device has an address

Chip-select selects the device

Typical speed

Often 9600 to 115200 baud for hobby parts

100 kHz standard, 400 kHz fast, higher modes exist

Often several MHz, the fastest of the three

A comparison of the three common links. Always check each part's datasheet for its actual limits.

UART sends bytes one bit at a time with a start bit and a stop bit around each byte, usually 8 data bits, so 10 bits on the wire per byte. With no clock line, both ends must be set to the same baud rate (bits per second) or they read gibberish.

I2C lets one controller talk to many devices over two wires. Each device has a 7-bit address, and every transfer starts with the controller sending that address. The lines are open-drain, which means devices only pull them low, so each line needs a pull-up resistor to the supply to return high. Many breakout boards already include them.

SPI uses a clock from the controller and separate lines for data out and data in, so it can send and receive at once. To choose a device, the controller pulls that device's chip-select line low. That costs one pin per device but gives the highest speed and simple logic.

Worked example: an IMU on I2C and a GPS on UART

Connect an IMU to the I2C pins and a GPS module to a UART. A common IMU address is 0x68, but read your own part's documentation. Power both at the voltage they are rated for.

  1. To read the IMU, the controller sends a start condition, then the address with a write bit, then the number of the first register it wants, then a repeated start, then the address again with a read bit.

  2. The IMU answers with bytes, one after another, and the controller acknowledges each. Say you read 14 bytes: accelerometer, temperature and gyroscope values.

  3. Count the clock cycles. Each byte on I2C takes 9 clocks (8 data bits and 1 acknowledge). The address, register and address again are 3 bytes: 3 × 9 = 27. The 14 data bytes: 14 × 9 = 126. Total: 27 + 126 = 153 clocks, ignoring the start and stop conditions.

  4. At the fast 400 kHz clock: 153 / 400000 ≈ 0.38 ms per read. At 100 kHz it would be 1.53 ms. Either is comfortably quick enough to read the IMU at 100 times a second.

Now the GPS. Many modules send text lines called NMEA sentences continuously at 9600 baud. Each byte is 10 bits on the wire, so the link carries 9600 / 10 = 960 bytes per second. A typical sentence is around 80 bytes, so one sentence takes about 80 / 960 ≈ 0.083 s. That limit is why GPS data is slow to arrive and why you read it by listening for a full line instead of asking.

The two links fit the parts. The IMU needs a quick register read on request, and addressable I2C does that. The GPS just streams text, and a simple UART does that. Notice the GPS's data rate is determined by the baud rate set at both ends, not by the controller's own clock.

Choosing one

  • Use what the part offers. Many sensors support only one, so the choice is often made for you.

  • Lots of slow parts, few pins: I2C. Two pins serve many devices.

  • Fast data (displays, memory cards, high-rate sensors): SPI.

  • Two devices streaming text or commands, or a computer-to-microcontroller link: UART.

  • Long cables: I2C and SPI are meant for short runs on a board. For longer runs use differential links such as RS-485 or CAN, which are separate standards.

Where it goes wrong

  • Address clash. Two I2C parts with the same address cannot share a bus unless one can change its address.

  • Missing pull-ups. I2C does not work, or works only sometimes.

  • TX to TX. UART lines must cross: TX of one goes to RX of the other.

  • Wrong baud rate. Garbled text almost always means a mismatch.

  • Voltage mismatch. A 5 V device driving a 3.3 V pin can damage it. Use level shifting.

  • Floating chip-select. A missing pull-up on SPI chip-select can make a device wake at random.

Safety: Power the board off while you change wiring, check the supply voltage of every part before connecting, and keep to low-voltage supplies. Never connect any of these pins to mains power.

How real robots use it

A typical robot controller uses all three at once: I2C for small sensors, SPI for faster parts like memory or radios, and UART for the link to a bigger computer. How much those parts draw from the battery matters too, which is the topic of power budgets.

Try it yourself

Connect two microcontroller boards by UART (TX to RX, RX to TX, shared ground) and send a word from one to the other at 9600 baud. Change one side to 115200 and watch the garbage appear. Then run an I2C scanner sketch on a board with a sensor attached and read off its address.

Frequently asked questions

Why does I2C need pull-up resistors?

Devices only pull the line low. Something has to pull it back high when nobody is driving, and that is the resistor.

Can I use more than one device on a UART?

Not directly. UART is point to point. To talk to several, you use extra UARTs or a different bus.

Get started

DuckyHelper can
do more

It sees your screen and works in any app you use. Try it for 10 minutes, no card.

Get it for Mac, Windows or Linux

Share

Questions and jobs

Do anything

Ask it a question or hand it a job, in any app.

Doing jobs for you is in early access on Mac. Asking works on Mac, Windows and Linux.