Talking to other chips: I2C and SPI
The two buses that connect sensors, displays and memories to your MCU.
Read this first
Most interesting parts, an accelerometer, a real time clock, a small display, a temperature sensor, are chips with a digital interface. Nearly all of them speak one of two buses: I2C or SPI. Learn both and the whole catalogue of breakout boards opens up.
I2C uses two wires shared by every device on the bus: SDA for data and SCL for the clock. Each device has a 7-bit address, and 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 nothing 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: in the same eight clock pulses, the master shifts a byte out on MOSI while the device shifts a byte back to the master on MISO. There are no addresses; the chip select tells which device is being talked to.
Choosing between them: I2C for a handful of slow devices on two wires, SPI for speed and for displays. Either way, the first thing to do with a new part is read its datasheet for the register map, then read one known register, like a chip ID, and print it. When that number matches the datasheet, everything else is just more registers.
To remember
- I2C: two shared wires, 7-bit addresses, 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.
- Start with a new chip by reading its ID register and printing it.
Check what you read
4 questions from the question bank on the ideas above. Each one comes with an explanation after you answer.
Sign in to answer the questions. Your answers count towards your level.
Sign inThe lesson text and the project are free to read without an account.
Build this
Read a real sensor over I2C
You need
- Your board with serial output working.
- One I2C breakout board. Good first ones: BMP280 or BME280 (pressure and temperature), MPU6050 (accelerometer), or a DS3231 clock. Most include pull-ups.
- Optional: a small SSD1306 OLED display, also I2C.
Steps
- Wire 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 answer. Confirm the address matches the datasheet.
- Read the chip ID register and print it, then compare 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, a second apart, and check that it counts.
- Read 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; it is fine to use the manufacturer's library for that part and keep your own code for the ID read.
- If you have the display, show the value on it. That is two devices on the same two 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.