Skip to content

Connecting chips: I2C and SPI

The 2 buses that connect sensors, displays and memory chips to your MCU.

Explanation

Many useful parts, such as accelerometers, real time clocks, small displays and temperature sensors, are chips with a digital interface. Nearly all of them use one of 2 buses: I2C or SPI. Once you know both, you can use most breakout boards.

I2C uses 2 wires shared by every device on the bus: SDA for data and SCL for the clock. Each device has a 7-bit address. The master starts every transfer by sending that address shifted left by one, with the read/write bit in the lowest position: address 0x48 for a write becomes 0x90 on the wire. The lines are open-drain, meaning a device can only pull them low, so the bus needs pull-up resistors, typically 4.7 kOhm, to bring the lines high again. Missing pull-ups are the most common reason an I2C bus does not respond at all. Many breakout boards already include them.

SPI is faster and simpler but needs more wires: SCK for the clock, MOSI for data from the master to the device, MISO for data back, and one chip select line per device. It is full duplex: during the same 8 clock pulses, the master shifts a byte out on MOSI while the device shifts a byte back on MISO. There are no addresses; the chip select line selects the device.

To choose between them, use I2C for a few slow devices on 2 wires, and SPI for speed and for displays. With either bus, begin a new part by reading its datasheet for the register map. Then read one known register, such as a chip ID, and print it. When that value matches the datasheet, the connection works, and you read the other registers the same way.

Key points

  • I2C: 2 shared wires, 7-bit addresses, and open-drain lines that need pull-ups.
  • The first byte on I2C is the address shifted left, plus the read/write bit.
  • SPI: clock, MOSI, MISO and one chip select per device; full duplex.
  • Begin with a new chip by reading its ID register and printing it.

Check your understanding

4 questions on this lesson. An explanation follows each answer.

Sign in to answer the questions. Your answers count towards your level.

Sign in

You can read the lesson and the project without an account.

Project

Read a real sensor over I2C

What you need

  • Your board with serial output working.
  • An I2C breakout board. Good first choices are the BMP280 or BME280 (pressure and temperature), the MPU6050 (accelerometer) or a DS3231 clock. Most include pull-ups.
  • Optional: a small SSD1306 OLED display, also I2C.

Steps

  1. 1Wire SDA, SCL, 3.3 V and ground. Write or use an I2C scanner that tries every address from 0x08 to 0x77 and prints the ones that respond. Confirm that the address matches the datasheet.
  2. 2Read the chip ID register, print it and compare it with the datasheet: on the BMP280, register 0xD0 reads 0x58; on the BME280 it reads 0x60; on the MPU6050, register 0x75 reads 0x68. The DS3231 has no ID register. Read its seconds register 0x00 twice, one second apart, and check that it counts.
  3. 3Read the measurement registers and print a value in real units once a second. For the MPU6050, divide the raw accelerometer value by 16384 to get g. For the BMP280 or BME280, the raw value needs the chip's calibration constants and a compensation formula from the datasheet. You may use the manufacturer's library for that part and keep your own code for the ID read.
  4. 4If you have the display, show the value on it. You then have 2 devices on the same 2 wires.

Done when

The serial output shows a temperature or acceleration that changes when you warm or tilt the sensor, and you found the address with your own scanner.