A very common troubleshooting situation is this: an I2C display, sensor, RTC, ADC or I/O expander works perfectly with an Arduino Uno, but the same module does not work with an ESP32. The I2C scanner may find nothing, the display may stay blank, or the sensor library may report that the device is missing.
This can be confusing because the module is clearly not dead. It already worked on the Uno. The problem is usually caused by different I2C pins, different voltage levels, pull-up resistors, 3.3V logic, board definitions, library assumptions or ESP32-specific pin behavior.
The Arduino Uno and ESP32 are both Arduino-compatible in software, but they are very different electrically.
Typical Symptoms
- The I2C module works on Arduino Uno but not on ESP32.
- The I2C scanner finds the device on Uno, but not on ESP32.
- The display lights up but shows no text or graphics.
- The sensor library reports “device not found.”
- The ESP32 resets when the I2C module is connected.
- The module works only after changing SDA/SCL pins in the sketch.
- The module works at 5V on Uno but fails at 3.3V on ESP32.
- The project works with one ESP32 board but not another ESP32 board.
First Important Point: Uno and ESP32 Use Different Default I2C Pins
On an Arduino Uno, the I2C pins are fixed:
- SDA: A4
- SCL: A5
On most classic ESP32 development boards, the common default pins are:
- SDA: GPIO21
- SCL: GPIO22
But ESP32 I2C pins are flexible. Many ESP32 boards can use other pins, but the sketch must match the wiring.
If the module is connected to GPIO22 and GPIO23, but the code starts I2C on GPIO21 and GPIO22, the bus will not work.
Define ESP32 I2C Pins Explicitly
On ESP32, it is often best to define SDA and SCL in the sketch instead of relying on board defaults.
#include <Wire.h>
#define I2C_SDA 21
#define I2C_SCL 22
void setup() {
Serial.begin(115200);
Wire.begin(I2C_SDA, I2C_SCL);
}
void loop() {
}
Change the pin numbers to match the actual ESP32 board and wiring.
Common Cause: Using Arduino Pin Names Instead of ESP32 GPIO Numbers
On Arduino Uno, labels such as A4 and A5 are simple and familiar. On ESP32 boards, the printed pin labels may be GPIO numbers, board-specific labels, or sometimes Arduino-style aliases.
This can cause confusion when copying code.
Examples:
- The board header may say D21, but the code should use 21.
- A pin labeled SDA may be mapped differently by a specific board package.
- A small module board may route I2C to non-default pins.
- XIAO-style boards use their own compact pinout and should be checked carefully.
Always check the pinout for the exact ESP32 board, not just a generic ESP32 pinout found online.
Common Cause: 5V I2C Module Pulls the Bus to 5V
The Arduino Uno uses 5V logic. The ESP32 uses 3.3V logic. This is one of the biggest differences.
Many I2C modules designed for Arduino Uno include pull-up resistors from SDA and SCL to 5V. This is usually fine for a 5V Uno, but unsafe for an ESP32 because ESP32 GPIO pins are not generally 5V tolerant.
If the I2C bus idles at 5V, the ESP32 pins may be stressed or damaged.
Before connecting a 5V I2C module to ESP32, check:
- Does the module pull SDA/SCL up to 5V?
- Can the module run fully from 3.3V?
- Does the module include level shifting?
- Does the ESP32 board expose 5V only as power, not logic?
Measure SDA and SCL Idle Voltage
A quick multimeter test can prevent many problems.
With the module powered and connected, but not actively communicating:
- Measure SDA to GND.
- Measure SCL to GND.
On an ESP32 I2C bus, both lines should normally idle near 3.3V. If they idle near 5V, the pull-ups are connected to 5V and the bus is not safe for direct ESP32 connection.
Common Cause: Module Works at 5V but Not at 3.3V
Some modules are happy at both 5V and 3.3V. Others are not.
A module that works on a 5V Uno may fail on ESP32 if:
- The sensor chip requires a higher supply voltage.
- The LCD backpack expects 5V logic.
- The display contrast circuit was designed for 5V.
- The module has a regulator with too much voltage drop.
- The pull-up resistors are connected to the wrong supply rail.
Many modern sensor ICs are 3.3V devices, but older display modules and LCD backpacks are often 5V-oriented.
Common Cause: I2C Pull-Ups Are Wrong for ESP32
The Uno may communicate successfully with weak or imperfect pull-ups because the wiring is short, the bus is 5V, and the example sketch uses standard settings.
On ESP32, the same module may fail because:
- There are no proper external pull-ups.
- Internal pull-ups are too weak.
- Pull-ups go to 5V instead of 3.3V.
- Several modules create too-strong combined pull-ups.
- The bus speed is too high for the wiring.
A good troubleshooting starting point is a 3.3V I2C bus with suitable pull-ups, often around 4.7kΩ for small setups.
Common Cause: ESP32 Default I2C Speed Is Too Fast for the Setup
Some libraries or examples may use a faster I2C speed. A module that works on Uno at 100 kHz may become unreliable on ESP32 if the library or board package uses 400 kHz and the wiring is not clean.
Try forcing standard mode:
Wire.begin(I2C_SDA, I2C_SCL);
Wire.setClock(100000); // 100 kHz
If the module starts working at 100 kHz, the issue is likely signal quality, wiring length, pull-ups or module timing.
Common Cause: Library Assumes AVR Arduino Behavior
Some older Arduino libraries were written mainly for AVR boards such as Uno and Nano. They may compile on ESP32 but still behave incorrectly.
Possible problems include:
- Direct access to AVR registers.
- Assumptions about pin numbering.
- Timing assumptions based on 16 MHz Arduino boards.
- Use of old Wire library behavior.
- Blocking code that triggers ESP32 watchdog resets.
If a library example works on Uno but fails on ESP32, check whether the library officially supports ESP32. Try a newer library or an example specifically written for ESP32.
Common Cause: ESP32 Board Variant Uses Different Pins
Not all ESP32 boards are the same. A large classic ESP32 DevKit, an ESP32-C3 board, an ESP32-S3 board, an ESP32-C6 board and a XIAO-style ESP32 module may all use different convenient I2C pins.
Generic examples may not match your board.
| Board Type | I2C Pin Situation | Practical Advice |
|---|---|---|
| Classic ESP32 DevKit | Often GPIO21 SDA, GPIO22 SCL | Still confirm your exact board pinout |
| ESP32-S3 boards | Pins vary widely by board | Do not assume classic ESP32 pin defaults |
| ESP32-C3 boards | Fewer pins; board-specific routing | Check pinout and avoid boot-sensitive pins |
| ESP32-C6 boards | Modern variants may use different default mappings | Use explicit Wire.begin(SDA, SCL) |
| XIAO ESP32 modules | Compact standardized header, board-specific pins | Use the XIAO pinout, not a generic ESP32 diagram |
Common Cause: Boot-Sensitive Pins Used for I2C
ESP32 boards have pins with special boot functions. If SDA or SCL is placed on a boot strapping pin and an I2C module pulls that pin high or low during reset, the ESP32 may fail to boot or behave strangely.
This can happen when:
- An I2C module has pull-ups on a boot pin.
- A sensor drives a pin during startup.
- A display or module holds a line low during reset.
- The selected pins are not safe for general I2C use.
Use known-safe pins whenever possible and avoid boot strapping pins unless you understand the startup behavior.
Common Cause: No Common Ground
If the ESP32 and the I2C module are powered from different supplies, their grounds must normally be connected together.
The I2C signals need a shared reference. Without common ground, the module may have power but the ESP32 may not be able to read SDA and SCL correctly.
This can cause the scanner to find nothing, or devices to appear and disappear randomly.
Common Cause: Powering the Module from the Wrong ESP32 Pin
Some ESP32 boards have pins labeled 3V3, 5V, VIN or VBUS. These do not all mean the same thing.
Common mistakes include:
- Powering a 5V LCD backpack from 3.3V when it needs 5V.
- Powering a 3.3V sensor from 5V by mistake.
- Using VIN as if it were always regulated 5V.
- Drawing too much current from the ESP32 3.3V regulator.
Measure the module supply voltage directly at the module pins.
Common Cause: OLED or LCD Library Uses the Wrong Wire Object
Some libraries allow choosing which I2C bus object to use, such as Wire or Wire1. If the ESP32 sketch initializes one bus but the library uses another, the device may not be found.
This is more common in projects using multiple I2C buses or board-specific examples.
Make sure the library and the scanner use the same I2C bus and the same pins.
Recommended Uno-to-ESP32 Troubleshooting Method
- Confirm the module still works on the Arduino Uno.
- Disconnect the module from the Uno.
- Connect the module to the ESP32 using short wires.
- Make sure GND is connected.
- Power the module with the correct voltage.
- Measure SDA and SCL idle voltage.
- Define SDA and SCL explicitly in the ESP32 sketch.
- Run an I2C scanner on the ESP32.
- Lower I2C speed to 100 kHz.
- Only after the scanner works, test the display or sensor library.
Quick Diagnostic Table
| Symptom | Likely Cause | First Thing to Try |
|---|---|---|
| Works on Uno, scanner finds nothing on ESP32 | Wrong ESP32 SDA/SCL pins | Use Wire.begin(SDA, SCL) with correct GPIOs |
| ESP32 I2C lines measure 5V | Module pull-ups go to 5V | Use level shifter or 3.3V pull-ups |
| LCD works on Uno, not ESP32 | 5V LCD backpack or logic-level issue | Check 3.3V compatibility and contrast |
| OLED detected but blank | Wrong library, address or reset setting | Confirm SSD1306/SH1106 and address |
| Works at 100 kHz, fails at 400 kHz | Pull-ups or wiring not good enough | Keep 100 kHz, shorten wires, check pull-ups |
| ESP32 will not boot with module connected | I2C pins interfere with boot pins | Move I2C to safer GPIO pins |
Simple ESP32 I2C Scanner Skeleton
Use a scanner that explicitly defines the I2C pins.
#include <Wire.h>
#define I2C_SDA 21
#define I2C_SCL 22
void setup() {
Serial.begin(115200);
delay(1000);
Wire.begin(I2C_SDA, I2C_SCL);
Wire.setClock(100000);
Serial.println("ESP32 I2C scanner started");
}
void loop() {
byte error;
byte address;
int count = 0;
for (address = 1; address < 127; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at 0x");
if (address < 16) {
Serial.print("0");
}
Serial.println(address, HEX);
count++;
}
}
if (count == 0) {
Serial.println("No I2C devices found");
}
delay(3000);
}
If this scanner finds the module, then the basic ESP32 I2C wiring is working. If the display or sensor library still fails afterward, the problem is likely address, library, controller type or initialization.
What Not to Do
- Do not assume Uno I2C wiring maps directly to ESP32.
- Do not connect 5V I2C pull-ups directly to ESP32 GPIO pins.
- Do not rely on a random ESP32 pinout image for your exact board.
- Do not start with the full project sketch before the scanner works.
- Do not assume a library is ESP32-compatible just because it compiles.
- Do not ignore common ground when using separate supplies.
CANABLOX Practical Note
CANABLOX is especially useful here because it makes the controller and I2C module wiring more predictable. A XIAO-style ESP32 module can be used as the controller, while CANABLOX modules keep power, ground, SDA and SCL organized in a consistent way.
Since CANABLOX can work with many XIAO-compatible controllers, including ESP32, ESP32-C3, ESP32-C6, ESP32-S3, RP2040, RP2350, nRF and others, it is still important to use the correct controller pin mapping. The modular wiring helps reduce mistakes, but the controller-specific I2C pin definition must still match the board.
Conclusion
If an I2C module works on Arduino Uno but not on ESP32, the module is probably not defective. The most likely causes are different SDA/SCL pins, 3.3V logic, pull-up voltage, library assumptions or ESP32-specific pin behavior.
Start with a simple ESP32 I2C scanner using explicit SDA and SCL pins. Measure the bus idle voltage. Keep the wiring short, use 100 kHz during troubleshooting, and make sure the module is safe for 3.3V logic.
Once the ESP32 scanner finds the device reliably, then move on to the display or sensor library.
