Skip to main content
ESPBoards

How to Use an I2C Scanner with ESP32 – A Step-by-Step Guide

Learn how to find I2C addresses of connected devices on the ESP32 with this simple scanner guide. Perfect for beginners looking to set up I2C communication with sensors and peripherals!


The I2C (Inter-Integrated Circuit) protocol is widely used in electronics to connect microcontrollers with various peripherals like sensors, displays, and other modules. It’s popular for its simplicity and flexibility, allowing multiple devices to communicate over just two wires: SDA (data line) and SCL (clock line). When working with the ESP32, a powerful microcontroller with built-in I2C support, it's essential to identify the correct I2C address of each device to ensure reliable communication.

Using an I2C scanner is a quick and efficient way to find the addresses of all I2C devices connected to the ESP32. In this article, we’ll explore how to set up and run an I2C scanner on the ESP32, helping you locate device addresses with ease and streamline your project setup.

Default ESP32 I2C Pins - SCL and SDA #

By default, the ESP32’s I2C interface uses:

  • GPIO 22 as the SCL (clock line) pin
  • GPIO 21 as the SDA (data line) pin
These default pins work for many ESP32 development boards, and they’re preconfigured in most libraries, making it straightforward to set up I2C communication.

However, some ESP32 boards may have different default I2C pins based on their specific design. Therefore, it’s a good idea to check your ESP32 development board's pinout to confirm the correct I2C pins. This small step can prevent issues with I2C communication and ensure that your devices are connected correctly. If needed, you can also reassign these pins in the code to match your board’s layout.

I2C Scanner ESP32 with Arduino IDE #

Each I2C device has a unique address, which the ESP32 uses to communicate with it. By running a simple scanner script, you can discover all active I2C addresses on the bus, ensuring correct communication setup without needing to check device datasheets. In this section, we'll walk through setting up and running an I2C scanner on the ESP32 using the Arduino IDE.

#include <Wire.h>

void setup() {
Wire.begin(); // Initialize I2C with default pins (SDA=21, SCL=22 for ESP32)
Serial.begin(115200);
Serial.println("\nI2C Scanner");
}

void loop() {
byte error, address;
int devicesFound = 0;

Serial.println("Scanning...");

for (address = 1; address < 127; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();

if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address < 16) Serial.print("0");
Serial.print(address, HEX);
Serial.println(" !");

devicesFound++;
}
else if (error == 4) {
Serial.print("Unknown error at address 0x");
if (address < 16) Serial.print("0");
Serial.println(address, HEX);
}
}
if (devicesFound == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");

delay(5000); // Wait 5 seconds before scanning again
}

I2C Scanner ESP32 with ESP-IDF #

For those working directly with the ESP32 SDK, the ESP-IDF (Espressif IoT Development Framework) offers powerful control over I2C communication. Using ESP-IDF, you can set up an I2C scanner to detect all connected devices on the I2C bus, allowing you to find their unique addresses quickly and accurately.

#include <stdio.h>
#include "driver/i2c.h"
#include "esp_log.h"

#define I2C_MASTER_SCL_IO 22 // SCL pin
#define I2C_MASTER_SDA_IO 21 // SDA pin
#define I2C_MASTER_NUM I2C_NUM_0 // I2C port number for master
#define I2C_MASTER_FREQ_HZ 100000 // I2C clock frequency
#define I2C_MASTER_TX_BUF_DISABLE 0 // I2C master does not need buffer
#define I2C_MASTER_RX_BUF_DISABLE 0 // I2C master does not need buffer

static const char *TAG = "I2C Scanner";

void i2c_master_init() {
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = I2C_MASTER_SCL_IO,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
// .clk_flags = 0, // Optional for some ESP32 variants
};
i2c_param_config(I2C_MASTER_NUM, &conf);
i2c_driver_install(I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}

void i2c_scanner() {
ESP_LOGI(TAG, "Starting I2C scan...");

int devices_found = 0;
for (int address = 1; address < 127; address++) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_WRITE, true);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 10 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);

if (ret == ESP_OK) {
ESP_LOGI(TAG, "I2C device found at address 0x%02x", address);
devices_found++;
} else if (ret == ESP_ERR_TIMEOUT) {
ESP_LOGW(TAG, "Timeout at address 0x%02x", address);
}
}

if (devices_found == 0) {
ESP_LOGI(TAG, "No I2C devices found\n");
} else {
ESP_LOGI(TAG, "Scan complete. %d devices found.\n", devices_found);
}
}

void app_main() {
// Initialize I2C
i2c_master_init();

// Run I2C scanner
while (1) {
i2c_scanner();
vTaskDelay(5000 / portTICK_PERIOD_MS); // Delay 5 seconds before next scan
}
}

Connecting an I2C Device to ESP32 #

Connecting an I2C device to the ESP32 is straightforward, but following a few best practices will ensure reliable communication.

  1. Connect SDA and SCL Pins:

    • Link the SDA (data line) of your I2C device to the ESP32’s SDA pin (GPIO 21 by default).
    • Connect the SCL (clock line) of your device to the ESP32’s SCL pin (GPIO 22 by default).
    • If your ESP32 board has different default I2C pins, refer to the board's pinout diagram and adjust your connections accordingly.
  2. Add Pull-Up Resistors (if required):

    • Many I2C devices and breakout boards have built-in pull-up resistors, but if yours does not, connect a 4.7kΩ resistor between SDA and the 3.3V line and another between SCL and 3.3V.
    • Pull-up resistors help maintain signal integrity, ensuring reliable data transmission over the I2C bus.
  3. Double-Check Connections:

    • Double-check all connections to confirm they’re secure and correctly aligned with the ESP32’s I2C pins. Misconnections or loose wiring can prevent proper communication or even damage components.

Running the Scanner and Interpreting Results #

Once you’ve set up and uploaded the I2C scanner code, you can start detecting connected I2C devices and their addresses. Here’s how to run the scanner and interpret the results:

  1. Upload and Open Serial Monitor:

    • After uploading the scanner code to the ESP32, open the Serial Monitor in the Arduino IDE (or ESP-IDF Monitor in ESP-IDF) to view the output.
    • Set the baud rate to 115200 (or as specified in the code) to match the serial communication rate.
  2. Interpreting the Output:

    • As the scanner runs, it will attempt to communicate with each possible I2C address (from 0x01 to 0x7F) and output any successful connections.
  3. Common Output Scenarios:

    • No Devices Found: If no devices are detected, you’ll see a message indicating no I2C devices were found. This might mean the connections aren’t secure, the devices are not powered, or they’re not functioning properly. Double-check wiring and ensure pull-up resistors are in place if needed.

    • Addresses Found in Hexadecimal: When a device is detected, its I2C address will be displayed in hexadecimal format (e.g., 0x3C). Each detected address corresponds to a connected I2C device. Use these addresses in your code to establish communication with each device.

The scanner will keep checking every few seconds, allowing you to connect or disconnect devices as needed. This process helps ensure each I2C device’s address is known and ready for programming.

Conclusion #

By running a simple scanner script—whether through the Arduino IDE or ESP-IDF — you can avoid the hassle of looking up addresses in datasheets and instead see the addresses directly on your ESP32’s serial output.

Having these addresses on hand also makes it easier to troubleshoot and configure each device, especially when working with more complex setups involving multiple I2C devices.