I2C Protocol: A Comprehensive Overview with ESP32 (Arduino Core)

Nandan Ghawate
4 min readMar 8, 2023

--

The Inter-Integrated Circuit (I2C) protocol is a popular communication protocol for connecting multiple devices on a single bus. It is widely used in embedded systems, particularly in sensors, displays, and other peripherals that require short-range communication. In this article, we will explore the basics of the I2C protocol, its working, and its implementation on ESP32, a popular microcontroller development board.

I2C Protocol Theory:

The I2C protocol was developed by Philips (now NXP Semiconductors) in the 1980s as a simple and low-cost communication protocol for connecting peripherals to a microcontroller. The I2C protocol uses only two wires, SDA (Serial Data) and SCL (Serial Clock), for transmitting data between the devices.

In an I2C communication, there are two types of devices — Master and Slave. The Master device initiates the communication and sends commands to the Slave device. The Slave device responds to the Master’s commands and sends data back to the Master. Multiple Slaves can be connected to the same bus, but they all share the same SDA and SCL lines.

The I2C protocol uses a start and stop bit to indicate the beginning and end of a communication transaction. The Master device initiates the communication by sending a start bit on the SDA line. After that, the Master sends the Slave’s address on the SDA line, followed by a read or write bit, depending on whether the Master wants to read or write data from the Slave. The Slave device acknowledges the Master’s address by sending an acknowledgment bit on the SDA line.

Once the communication is established, the Master sends data to or reads data from the Slave, one byte at a time. After each byte, the Slave device sends an acknowledgment bit to indicate that it has received the byte. Once the communication is complete, the Master sends a stop bit to end the transaction.

I2C on ESP32:

The ESP32 is a powerful microcontroller development board that supports various communication protocols, including I2C. The ESP32 has two I2C interfaces, I2C0 and I2C1, which can be configured as Master or Slave devices. The I2C0 interface is connected to GPIO pins 21 and 22, while the I2C1 interface is connected to GPIO pins 18 and 19.

To use the I2C protocol on ESP32, we need to include the “Wire.h” library in our code. This library provides functions for initializing the I2C interface and for sending and receiving data on the bus.
Here is an example code for scanning the I2C bus and listing all the devices connected to it:

#include <Wire.h>

void setup() {
Wire.begin();
Serial.begin(9600);
while (!Serial);
Serial.println("\nI2C Scanner");
}

void loop() {
byte error, address;
int nDevices;

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

nDevices = 0;
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(" !");

nDevices++;
}
else if (error == 4) {
Serial.print("Unknow error at address 0x");
if (address < 16) {
Serial.print("0");
}
Serial.println(address, HEX);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found\n");
}
else {
Serial.println("Scan complete\n");
}
delay(5000);
}

In this code, we first initialize the I2C interface using the “Wire.begin()” function. Then, we scan the I2C bus for all the devices connected to it by iterating through all the possible device addresses (1 to 127) using a “for” loop.

For each address, we start a transmission using the “Wire.beginTransmission()” function and check for any errors using the “Wire.endTransmission()” function. If the error is zero, it means that a device is present at that address, and we print the device’s address on the serial monitor using the “Serial.print()” function. If there is an error, we print an error message.

Applications of I2C on ESP32:

There are many applications of I2C on ESP32, including interfacing with various sensors and displays. Here are some examples:

1. OLED Display: The ESP32 can be used to interface with OLED displays that use the I2C protocol, such as the SSD1306. The display can be controlled using the “Adafruit_SSD1306.h” library, which provides functions for initializing the display, drawing shapes and text, and updating the display.

2. AHT10 Sensor: The ESP32 can be used to interface with the AHT10 temperature and humidity sensor, which uses the I2C protocol. The sensor can be controlled using the “AHT10.h” library, which provides functions for reading the temperature and humidity data from the sensor.

The I2C protocol is a widely used communication protocol for connecting multiple devices on a single bus. The ESP32 microcontroller development board supports the I2C protocol, and its implementation is relatively easy using the “Wire.h” library. The I2C protocol can be used for many applications, including interfacing with sensors and displays. The example code provided in this article can be used as a starting point for implementing the I2C protocol on ESP32.

--

--

Nandan Ghawate

Electronics Product Designer | Project Manager | Embedded Systems | Internet Of Things (IOT) | Battery Management Systems (BMS)