I2C
Two wires, up to a hundred sensors, and one number per device that the factory chose for you. Everything that goes wrong with I2C is either that number colliding, or the two resistors that make the bus work at all.
Two wires and a name each
Every device on the bus has a 7-bit address. The board calls one out, that device answers, everybody else stays quiet. There is no negotiation and no way to change an address in software — it is set at the factory, sometimes with one pin you can tie high or low.
The two resistors
SDA and SCL are never driven high. Devices only pull them down, and a pair of resistors pulls them back up — which is what lets several devices share a wire without destroying each other.
Almost every breakout board has 4.7 kΩ resistors on it already. That is fine for one board and a problem for four, because they end up in parallel: four modules means about 1.2 kΩ, which is strong enough that a device cannot pull the line low properly. Unsolder the pairs from all but one.
On the ESP32 specifically
- Any two pins.
Wire.begin(sda, scl)— you are not stuck with fixed ones. - Two buses.
WireandWire1, entirely independent. This is the cleanest fix for an address collision. - Start at 100 kHz. Move to 400 kHz once it works, not before. Half of "I2C is unreliable" is a bus running at 400 kHz on wires meant for 100.
The code
Run this before any sensor library, every time. It answers one question - is the device electrically there - and it separates wiring problems from software ones in ten seconds.
#include <Wire.h>
void setup() {
Serial.begin(115200);
Wire.begin(21, 22); // SDA, SCL - any pins you like
Wire.setClock(100000); // start slow. 400000 once it works
Serial.println("scanning...");
for (uint8_t a = 1; a < 127; a++) {
Wire.beginTransmission(a);
if (Wire.endTransmission() == 0)
Serial.printf("found 0x%02X\n", a);
}
}
void loop() {}Wire.begin(sda, scl) lets you pick any two pins on the ESP32, which most Arduino boards cannot do. Wire1 gives you a second, entirely separate bus.
One line, and you can type it at the REPL with the sensor in your hand - which makes finding a loose wire genuinely fast.
from machine import I2C, Pin
i2c = I2C(0, sda=Pin(21), scl=Pin(22), freq=100000)
print([hex(a) for a in i2c.scan()])
# read 2 bytes from register 0x00 of a device at 0x76
# print(i2c.readfrom_mem(0x76, 0x00, 2))An empty list means SDA and SCL swapped, no pull-ups, or no power - in that order of likelihood. It very rarely means a dead sensor.
When it does not work
Check three things in this order - SDA and SCL swapped, no pull-up resistors on the bus, and the module not actually powered. A dead sensor is almost never the answer.
They share an address. The scanner still shows one entry, so the bus looks healthy while both chips answer at once. Move one with its address jumper, or put it on Wire1.
Capacitance. The pull-ups cannot charge the line fast enough between clock edges. Drop to 100 kHz, use stronger pull-ups, or shorten the cable - I2C was designed for centimetres.
The bus is stuck, usually because a device was reset mid-transaction and is still holding SDA low. Toggling SCL nine times releases it - most libraries have a recover function that does exactly that.
I2C trades speed for wires. The next page is the other end of that trade - four wires, and a hundred times the throughput.
SPI →Edit this page — content/esp32/i2c.mdx
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.