ESP32 I2C pins, custom pins and a second bus
Intermediate
Or see every lesson.
- 455parts on the bench
- 43boards running now
- 1.00xreal time, on every board
The ESP32 has no fixed I2C pins. Its I2C controllers reach the pads through the GPIO matrix, so Wire.begin() uses the board’s default pins and Wire.begin(sda, scl) uses any two you name. On the classic ESP32 DevKit the defaults are GPIO 21 for SDA and GPIO 22 for SCL. The chip has two I2C controllers, so it can run two separate buses at once.
The circuit above is an ESP32-C3 with two pressure sensors on its default pins, GPIO 8 and 9: a BME280 at address 0x76 and a BMP280 at 0x77. It printed "0x76: BME280, id 0x60" and "0x77: BMP280, id 0x58", two devices sharing two wires because their addresses differ. Below are the default pins on each ESP32, custom pins, and a second bus for when two devices have the same address.
The default I2C pins on each ESP32
SDA and SCL are constants the core defines for each board, and Wire.begin() with no arguments uses them. Printed on each board here, they were 21 and 22 on the classic ESP32, 8 and 9 on the ESP32-C3 and the ESP32-S3, and 23 and 22 on the ESP32-C6. Those are the pins most module tutorials assume, and the ones to try first.
With an SSD1306 OLED and an LCD backpack on GPIO 21 and 22 of the DevKit, the scanner below printed "Wire: found 0x27" and "Wire: found 0x3C". The same two modules moved to GPIO 16 and 17 printed "Wire: nothing" until Wire.begin() became Wire.begin(16, 17), and then found both again.
#include <Wire.h>
void scan(TwoWire &bus, const char *name) {
int found = 0;
for (byte address = 1; address < 127; address++) {
bus.beginTransmission(address);
if (bus.endTransmission() == 0) {
Serial.print(name);
Serial.print(": found 0x");
if (address < 16) Serial.print("0");
Serial.println(address, HEX);
found++;
}
}
if (found == 0) {
Serial.print(name);
Serial.println(": nothing");
}
}
void setup() {
Serial.begin(115200);
Wire.begin(16, 17); // SDA, SCL
scan(Wire, "Wire");
}
void loop() {
}Which pins can be SDA and SCL
Data comes first in Wire.begin(sda, scl), which is the opposite order from some other libraries, so a module that answers on the defaults and not on your pins is often just swapped. GPIO 33 and 32 worked as well. Both lines are open drain, so each pin needs an output driver: with SCL on GPIO 34, an input-only pin, the scan found nothing.
Leave out GPIO 6 to 11, which are the flash, GPIO 1 and 3, which are the USB serial port, and the strapping pins 0, 2, 5, 12 and 15, which a module’s pull-up resistors can hold at the wrong level at power on. In Mokxi, Wire is software that drives the two pins, the same on every board, rather than a model of the ESP32’s I2C controller, so it shows which pins and addresses work, and its timing is its own. A scan of the 126 addresses took 19059 microseconds at the default 100 kHz and 9987 after Wire.setClock(400000).
Two devices with the same address: a second I2C bus
Two identical modules on one bus answer to the same address at the same time, and the sketch cannot tell them apart. Two SSD1306 OLEDs on GPIO 21 and 22 printed only "Wire: found 0x3C". Some modules have a jumper for a second address; when they do not, or when you need more of them than there are addresses, give the second one its own bus.
The ESP32 core names the second controller Wire1. Mokxi’s Wire.h does not declare Wire1 yet, and a sketch that uses it stops with use of undeclared identifier 'Wire1'; did you mean 'Wire'?. Making your own bus works on both: TwoWire I2Ctwo = TwoWire(1); and I2Ctwo.begin(25, 26, 400000), with SDA, SCL and the clock. With one OLED on each bus the scan printed "Wire: found 0x3C" and "I2Ctwo: found 0x3C".
A library that takes a bus takes it as a pointer when the object is made. With Adafruit_SSD1306 right(128, 64, &I2Ctwo, -1); both displays started: each begin(SSD1306_SWITCHCAPVCC, 0x3C) printed 1. Libraries that only ever use Wire cannot reach a second bus, which is worth checking before you wire one.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
TwoWire I2Ctwo = TwoWire(1);
Adafruit_SSD1306 left(128, 64, &Wire, -1);
Adafruit_SSD1306 right(128, 64, &I2Ctwo, -1);
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
I2Ctwo.begin(25, 26);
Serial.println(left.begin(SSD1306_SWITCHCAPVCC, 0x3C));
Serial.println(right.begin(SSD1306_SWITCHCAPVCC, 0x3C));
left.clearDisplay();
left.setTextColor(SSD1306_WHITE);
left.setTextSize(2);
left.print("Wire");
left.display();
right.clearDisplay();
right.setTextColor(SSD1306_WHITE);
right.setTextSize(2);
right.print("I2Ctwo");
right.display();
}
void loop() {
}Pull-up resistors and 5 V modules
I2C lines are only ever pulled low by the devices; a resistor to the supply pulls them high. Most breakout boards carry their own, often 4.7 k or 10 k, which is why two modules on a bus usually just work. The ESP32’s internal pull-ups are tens of kilohms, too weak for anything but a short bus at 100 kHz. With a bare chip and no module, add 4.7 k from each line to 3.3 V.
The ESP32’s pins are not 5 V tolerant. A module powered from 5 V pulls SDA and SCL up to 5 V through its own resistors, so power it from 3.3 V when it works there, as most OLEDs and sensors do, or put a level shifter between it and the board.
Questions
What are the I2C pins on an ESP32?
GPIO 21 (SDA) and GPIO 22 (SCL) on the classic ESP32 DevKit, GPIO 8 and 9 on the C3 and S3, and GPIO 23 and 22 on the C6. Any other output pins work with Wire.begin(sda, scl).
How do I use two I2C buses on an ESP32?
Declare a second bus with TwoWire I2Ctwo = TwoWire(1); start it with I2Ctwo.begin(sda, scl), and pass &I2Ctwo to the library of the device on it. The core also predeclares it as Wire1.
Can I connect multiple I2C devices to one ESP32?
Yes, on the same two wires, as long as each has a different address. Two devices with the same address need a second bus or an address jumper.
Do I need pull-up resistors for I2C on an ESP32?
Yes, but most modules have them. For a bare chip, add 4.7 k from SDA and SCL to 3.3 V; the internal pull-ups are too weak to rely on.
Why does my ESP32 I2C scanner find nothing?
Check the pins first: the module is on pins other than the ones Wire.begin() names, SDA and SCL are swapped, or one is an input-only pin. Then power and ground.
Keep going
Where the facts on this page come from
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.