ESP32 I2C Master and Slave Communication (Arduino) | Random Nerd Tutorials (2024)

In this guide, you’ll learn how to exchange data between two ESP32 boards using I2C communication protocol. One ESP32 board will be set as an I2C master and the other board as an I2C slave. The ESP32 boards will be programmed using Arduino IDE.

ESP32 I2C Master and Slave Communication (Arduino) | Random Nerd Tutorials (1)

Do you need a wireless communication protocol? Try ESP-NOW communication protocol with the ESP32 to exchange data between boards.

Table of Contents

In this guide, we’ll cover the following topics:

  • Introducing I2C
    • ESP32 I2C Bus Interfaces
  • ESP32 Master and ESP32 Slave
  • Connecting two ESP32 Boards via I2C
    • I2C Communication Between 2 ESP32 boards
  • ESP32 I2C Slave – Arduino Code
  • ESP32 I2C Master – Arduino Code
  • Exchange Data Between Two ESP32 Boards via I2C – Demonstration

Introducing I2C

I²C meansInterIntegratedCircuit (it’s pronounced I-squared-C), and it is a synchronous, multi-master, multi-slave communication protocol. You can connect :

  • Multiple slaves to one master:for example, your ESP32 reads from a BME280 sensor using I2C and writes the sensor readings in an I2C OLED display.
  • Multiple masters controlling the same slave:for example, two ESP32 boards writing data to the same I2C OLED display.

ESP32 I2C Bus Interfaces

The ESP32 supports I2C communication through its two I2C bus interfaces that can serve as I2C master or slave, depending on the user’s configuration. Accordingly to the ESP32 datasheet, the I2C interfaces of the ESP32 supports:

  • Standard mode (100 Kbit/s)
  • Fast mode (400 Kbit/s)
  • Up to 5 MHz, yet constrained by SDA pull-up strength
  • 7-bit/10-bit addressing mode
  • Dual addressing mode. Users can program command registers to control I²C interfaces, so that they have more flexibility

For a more detailed introduction to I2C communication with the ESP32, read our guide:

  • ESP32 I2C Communication: Set Pins, Multiple Bus Interfaces and Peripherals (Arduino IDE)

ESP32 Master and ESP32 Slave

For I2C communication between two ESP32 boards, we’ll use

  • The default Wire.h library
  • The default I2C pins on both boards (these may vary depending on your board model)

Connecting two ESP32 Boards via I2C

Start by connecting the two ESP32 boards with each other. Use the default I2C pins for the boards you’re using. Don’t forget to connect the GND pins together.

ESP32 I2C Master and Slave Communication (Arduino) | Random Nerd Tutorials (2)
ESP32 MasterESP32 Slave
SDA (GPIO 21)*SDA(GPIO 21)*
SCL (GPIO 22)*SCL (GPIO 22)*
GNDGND

* in my case, I’m testing this with the ESP32 DOIT V1 board. The default I2C pins are GPIO 21 (SDA) and GPIO 22 (SCL). If you’re using an ESP32-C3, ESP32-S3, or other model, the default I2C pins might be different. Please check the pinout for the board you’re using.

I2C Communication Between 2 ESP32 boards

Here’s how I2C communication between two ESP32 boards works:

ESP32 MasterESP32 Slave
Sets its I2C address
Sets callback functions:
– to read received messages;
– to handle requests.
Initializes I2C bus on the slave I2C address
Starts I2C communication on the I2C bus
Sends a message via I2C (Starts transmission)
Reads the received message
Requests data from the slave
Sends data to the master

ESP32 I2C Slave – Arduino Code

To test setting the ESP32 as an I2C slave, we’ll use the default example from the Wire.h library.

/********* Rui Santos & Sara Santos - Random Nerd Tutorials Complete project details at https://RandomNerdTutorials.com/esp32-i2c-master-slave-arduino/ ESP32 I2C Slave example: https://github.com/espressif/arduino-esp32/blob/master/libraries/Wire/examples/WireSlave/WireSlave.ino*********/#include "Wire.h"#define I2C_DEV_ADDR 0x55uint32_t i = 0;void onRequest() { Wire.print(i++); Wire.print(" Packets."); Serial.println("onRequest"); Serial.println();}void onReceive(int len) { Serial.printf("onReceive[%d]: ", len); while (Wire.available()) { Serial.write(Wire.read()); } Serial.println();}void setup() { Serial.begin(115200); Serial.setDebugOutput(true); Wire.onReceive(onReceive); Wire.onRequest(onRequest); Wire.begin((uint8_t)I2C_DEV_ADDR);/*#if CONFIG_IDF_TARGET_ESP32 char message[64]; snprintf(message, 64, "%lu Packets.", i++); Wire.slaveWrite((uint8_t *)message, strlen(message)); Serial.print('Printing config %lu', i);#endif*/}void loop() { }

View raw code

How does the code work?

Let’s take a quick look at how the slave code works.

Including the Wire Library

First, you need to include the Wire.h library.

#include "Wire.h"

Define the I2C address you want to give to your I2C device. In this case, it’s 0x55, but you can define any other address as long as you use the same one on the master device.

#define I2C_DEV_ADDR 0x55

Assign Callback Functions

In the setup(), you must assign two callback functions: one for when the board receives data from the master and another one for when the board receives a request from the master (send data to the master).

Wire.onReceive(onReceive);Wire.onRequest(onRequest);

onReceive() Callback Function

The onReceive() function will read the data sent from the master and prints it on the Serial monitor.

void onReceive(int len) { Serial.printf("onReceive[%d]: ", len); while (Wire.available()) { Serial.write(Wire.read()); } Serial.println();}

You check if there’s data available to read using Wire.available().

while (Wire.available()) {

Then, you read the received bytes with Wire.read().

Serial.write(Wire.read());

onRequest() Callback Function

The onRequest() function will send data to the Master when requested.

void onRequest() { Wire.print(i++); Wire.print(" Packets."); Serial.println("onRequest"); Serial.println();}

To send data to the master, we use Wire.print().

Wire.print(i++);Wire.print(" Packets.");

In the documentation, it mentions that you need to use Wire.slaveWrite() in the case of the ESP32, so that it writes the response to the buffer before receiving a message from the master. However, in our case, it works well without Wire.slaveWrite() (that’s why we have that section commented).

Depending on your board, you may need to use the slaveWrite() method as follows.

/*#if CONFIG_IDF_TARGET_ESP32 char message[64]; snprintf(message, 64, "%lu Packets.", i++); Wire.slaveWrite((uint8_t *)message, strlen(message)); Serial.print('Printing config %lu', i);#endif*/

Initialize I2C

In the setup(), you must also initialize I2C communication on the I2C address defined earlier. Use the begin() method as follows. This will initialize I2C on the ESP32 default I2C pins.

Wire.begin((uint8_t)I2C_DEV_ADDR);

You can also pass the I2C pins and bus frequency to this method:

bool Wire.begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency);

ESP32 I2C Master – Arduino Code

To test setting the ESP32 as an I2C master, we’ll use the default example from the Wire.h library.

/********* Rui Santos & Sara Santos - Random Nerd Tutorials Complete project details at https://RandomNerdTutorials.com/esp32-i2c-master-slave-arduino/ ESP32 I2C Master Example: https://github.com/espressif/arduino-esp32/blob/master/libraries/Wire/examples/WireMaster/WireMaster.ino*********/#include "Wire.h"#define I2C_DEV_ADDR 0x55uint32_t i = 0;void setup() { Serial.begin(115200); Serial.setDebugOutput(true); Wire.begin();}void loop() { delay(5000); // Write message to the slave Wire.beginTransmission(I2C_DEV_ADDR); Wire.printf("Hello World! %lu", i++); uint8_t error = Wire.endTransmission(true); Serial.printf("endTransmission: %u\n", error); // Read 16 bytes from the slave uint8_t bytesReceived = Wire.requestFrom(I2C_DEV_ADDR, 16); Serial.printf("requestFrom: %u\n", bytesReceived); if ((bool)bytesReceived) { //If received more than zero bytes uint8_t temp[bytesReceived]; Wire.readBytes(temp, bytesReceived); log_print_buf(temp, bytesReceived); }}

View raw code

How does the code work?

Let’s take a quick look at how the ESP32 I2C Master code works.

Including the Wire Library

First, you need to include the Wire.h library.

#include "Wire.h"

Slave I2C Address

Set the I2C address of the slave device (set on the previous code):

#define I2C_DEV_ADDR 0x55

Initialize I2C

In the setup(), initialize I2C communication using Wire.begin(). This will initialize I2C on the default I2C pins.

Wire.begin();

You can also pass the I2C pins and bus frequency to this method:

bool Wire.begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency);

Start Communication with the Slave

In the loop(), we send a message to the slave to inform that we’ll start I2C transmission:

// Write message to the slaveWire.beginTransmission(I2C_DEV_ADDR);Wire.printf("Hello World! %lu", i++);uint8_t error = Wire.endTransmission(true);Serial.printf("endTransmission: %u\n", error);

First, you need to call the beginTransmission() method and pass the slave address before writing a message.

Wire.beginTransmission(I2C_DEV_ADDR);

Then, you write a message to the buffer using the printf() method.

Serial.printf("endTransmission: %u\n", error);

Finally, to send the buffered message, you need to use the endTransmission() method.

uint8_t error = Wire.endTransmission(true);

Request Data From the Slave

Then, we request data from the slave using Wire.requestFrom(). Pass as argument the address of the slave and the number of requested bytes.

// Read 16 bytes from the slaveuint8_t bytesReceived = Wire.requestFrom(I2C_DEV_ADDR, 16);

Then, concatenate all the bytes and print the received data.

Serial.printf("requestFrom: %u\n", bytesReceived);if ((bool)bytesReceived) { //If received more than zero bytes uint8_t temp[bytesReceived]; Wire.readBytes(temp, bytesReceived); log_print_buf(temp, bytesReceived);}

Exchange Data Between Two ESP32 Boards via I2C – Demonstration

Upload the master and slave I2C sketches to your ESP32 boards. Open two instances of the Arduino IDE to see the Serial Monitor for both boards simultaneously.

You should see the master initializing a communication with the slave and receiving the data packets.

This is what you should get on the slave (a Hello World message! followed by a counter and the onRequest function being triggered):

ESP32 I2C Master and Slave Communication (Arduino) | Random Nerd Tutorials (3)

On the Master, you’ll receive the packets sent from the slave.

ESP32 I2C Master and Slave Communication (Arduino) | Random Nerd Tutorials (4)

Wrapping Up

In this tutorial, we’ve shown you how to set the ESP32 as an I2C slave and as an I2C master and how to exchange data between two EPS32 boards using I2C communication protocol.

For more details about using the Wire library for I2C communication, check the official documentation: Arduino-ESP32 I2C API Documentation.

We have other I2C tutorials with the ESP32 that you may find useful:

  • ESP32: I2C Scanner (Arduino IDE) – Finding the Address of I2C Devices
  • ESP32 I2C Communication: Set Pins, Multiple Bus Interfaces and Peripherals (Arduino IDE)

If you want to exchange data between two ESP32 boards wirelessly, we recommend using ESP-NOW instead:

  • Getting Started with ESP-NOW (ESP32 with Arduino IDE)
  • ESP-NOW Two-Way Communication Between ESP32 Boards
  • ESP-NOW with ESP32: Send Data to Multiple Boards (one-to-many)
  • ESP-NOW with ESP32: Receive Data from Multiple Boards (many-to-one)

We hope this tutorial is useful. Learn more about the ESP32 with our resources:

  • Learn ESP32 with Arduino IDE (2nd Edition)
  • SMART HOME with Raspberry Pi, ESP32, ESP8266
  • Build Web Servers with ESP32 and ESP8266
  • Firebase Web App with the ESP32 and ESP8266
  • Free ESP32 Projects, Tutorials and Guides
ESP32 I2C Master and Slave Communication (Arduino) | Random Nerd Tutorials (2024)

References

Top Articles
Latest Posts
Article information

Author: Horacio Brakus JD

Last Updated:

Views: 5963

Rating: 4 / 5 (71 voted)

Reviews: 94% of readers found this page helpful

Author information

Name: Horacio Brakus JD

Birthday: 1999-08-21

Address: Apt. 524 43384 Minnie Prairie, South Edda, MA 62804

Phone: +5931039998219

Job: Sales Strategist

Hobby: Sculling, Kitesurfing, Orienteering, Painting, Computer programming, Creative writing, Scuba diving

Introduction: My name is Horacio Brakus JD, I am a lively, splendid, jolly, vivacious, vast, cheerful, agreeable person who loves writing and wants to share my knowledge and understanding with you.