Skip to content

11. Networking and Communications

Group Assignment

Two Projects Communication

Hero Shot

Summary

This week, we worked on implementing I2C communication between two microcontrollers: a RP2040 (acting as the master) and an ESP32 (acting as the slave).

We configured the I2C communication so that the RP2040 sends messages to the ESP32, which processes the data and forwards it to another RP2040. Additionally, we integrated WiFi communication between the ESP32 units to enable communication over a network. In this setup, one ESP32 receives data from the RP2040 via I2C and then transmits it over WiFi to another ESP32, which passes it to the second RP2040.

We also troubleshooted issues such as incorrect data type conversions (notably with Wire.write()) and ensured proper data formatting for reliable communication.

Work Process Detail

1000116426.jpg

🔄 Comparison of Communication Protocols: UART vs I²C vs SPI

Feature UART I²C SPI
Wires Required 2 (TX, RX) 2 (SDA, SCL) 4 (MOSI, MISO, SCK, SS)
Speed Up to 1 Mbps (standard); varies by implementation Up to ~3.4 MHz (Fast Mode Plus / High Speed Mode) Typically 10–50+ MHz
Complexity Simple, point-to-point Moderate; needs addressing, start/stop conditions, ACK/NACK handling Higher; more pins, but straightforward full-duplex communication
Device Support 1:1 communication Supports multiple devices via unique addresses on shared bus Supports multiple devices using separate SS lines
Data Direction Bi-directional (half/full-duplex) Bi-directional on SDA Full-duplex with separate MOSI and MISO lines
Clock Signal No (asynchronous) Yes (SCL line) Yes (SCK line)
Master-Slave Not strictly defined Yes (1 master, multiple slaves) Yes (1 master, multiple slaves)
Power Consumption Low Lower at idle; open-drain lines with pull-up resistors Higher at high speed, but more power-efficient during fast data transfers
Pin Efficiency High Very high—only 2 pins for many devices Lower—requires more pins, especially with multiple slaves
Range Short to medium (typically under 15 meters) Short (usually under 1 meter) Very short (under 1 meter)
Error Checking Optional parity bit Built-in ACK/NACK mechanism None inherently; must be implemented in software
Use Case Suitability Serial communication between two devices (e.g., PC ↔ microcontroller) Great for low-speed sensors, RTCs, EEPROMs, small OLEDs Best for high-speed peripherals like displays, ADCs, SD cards
Multi-master Support No Yes (but rarely used) No

🔧 Uploading Code to XIAO ESP32-C3 Using Arduino IDE

Step 1: Install ESP32 Board Support

  1. Open Arduino IDE.
  2. Go to File → Preferences.
  3. In the “Additional Boards Manager URLs” field, add:

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

If you have other URLs there, separate them with a comma.

  1. Click OK.

  2. Go to Tools → Board → Boards Manager.

  3. Search for esp32 and install “esp32 by Espressif Systems” (install the latest version).

Step 2: Select the XIAO ESP32-C3 Board

  1. Go to Tools → Board and select:

XIAO_ESP32C3

If not visible, scroll or search after installing the ESP32 core.

  1. Go to Tools → Port and choose the correct COM port for the board.

Step 3: Uploading Code (Tips)

  • If the upload fails, double-press the RESET button on the XIAO ESP32-C3.
  • The onboard LED should start pulsing — it’s now in bootloader mode.
  • Then click Upload again.

Test Example

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.println("Hello from XIAO ESP32-C3!");
  delay(1000);
}


I2C Communication Protocol

XIAO RP2040 —> XIAO ESP32-C3

This section explains how to connect an XIAO RP2040 to the XIAO ESP32-C3 using the I²C communication protocol.

Wiring:

The XIAO ESP32-C3 matches the XIAO RP2040’s logic level.

XIAO ESP32-C3 XIAO RP2040 Pin
VCC 3V3
GND GND
SDA D4
SCL D5

💡 Note: On the XIAO RP2040, the default I²C pins are: - SDA → D4
- SCL → D5

Code:

XIAO ESP32-C3 Transmitter

#include <Wire.h>

void setup() {
  Serial.begin(115200);
  Wire.begin(); // Default SDA = D4, SCL = D5 on XIAO ESP32-C3
}

void loop() {
  Wire.beginTransmission(0x08);      // Slave address

  // Send the string byte by byte
  const char* msg = "Hello from ESP32-C3!";
  while (*msg) {
    Wire.write(*msg);  // Write each character as a byte
    msg++;
  }

  Wire.endTransmission();

  Serial.println("Sent to RP2040");
  delay(1000);
}

XIAO RP2040 Receiver

#include <Wire.h>

void receiveEvent(int bytes) {
  while (Wire.available()) {
    char c = Wire.read();
    Serial.print(c);
  }
  Serial.println();
}

void setup() {
  Serial.begin(115200);
  Wire.begin(0x08);                // RP2040 as slave at address 0x08
  Wire.onReceive(receiveEvent);   // Callback on data received
}

void loop() {
}


Multi-Protocol Communication Between RP2040 and ESP32 Using I2C and WiFi

RP2040_1 --(I2C)--> ESP32_1 --(WiFi)--> ESP32_2 --(I2C)--> RP2040_2

Concept

  • RP2040_1 (Master) → sends a message to ESP32_1 (Slave) over I2C
  • ESP32_1 (WiFi Client) → sends that message over WiFi to ESP32_2 (WiFi Server)
  • ESP32_2 (Master) → sends that message to RP2040_2 (Slave) over I2C

This is fully possible and works as intended.

Simple Flow

Step Action
1 RP2040_1 sends text via I2C to ESP32_1
2 ESP32_1 connects over WiFi to ESP32_2 and sends message
3 ESP32_2 receives WiFi message and sends it via I2C to RP2040_2
4 RP2040_2 receives message and prints it

Programming Hints

🟢 RP2040_1 (I2C Master)

#include <Wire.h>

void setup() {
  Wire.begin();
}

void loop() {
  const char* message = "Hello FAB25!";
  Wire.beginTransmission(0x08);  // Address of ESP32_1
  Wire.write((const uint8_t*)message, strlen(message));
  Wire.endTransmission();
  delay(5000);
}

🟢 ESP32_1 (I2C Slave + WiFi Client)

#include <WiFi.h>
#include <Wire.h>

String i2cMessage = "";

void receiveI2C(int bytes) {
  while (Wire.available()) {
    i2cMessage += (char)Wire.read();
  }
}

void setup() {
  Wire.begin(0x08);       // I2C Slave address
  Wire.onReceive(receiveI2C);

  WiFi.begin("ESP32_SERVER", "12345678");
  while (WiFi.status() != WL_CONNECTED) delay(500);
}

void loop() {
  if (i2cMessage.length() > 0) {
    WiFiClient client;
    if (client.connect("192.168.4.1", 80)) {
      client.println(i2cMessage);
      client.stop();
      i2cMessage = "";
    }
  }
}

🟢 ESP32_2 (WiFi Server + I2C Master)

#include <WiFi.h>
#include <Wire.h>

WiFiServer server(80);

void setup() {
  Wire.begin();
  WiFi.softAP("ESP32_SERVER", "12345678");
  server.begin();
}

void loop() {
  WiFiClient client = server.available();
  if (client) {
    String data = client.readStringUntil('\n');
    Wire.beginTransmission(0x09); // Address of RP2040_2
    Wire.write((const uint8_t*)data.c_str(), data.length());
    Wire.endTransmission();
    client.stop();
  }
}

🟢 RP2040_2 (I2C Slave)

#include <Wire.h>

void receiveI2C(int bytes) {
  while (Wire.available()) {
    char c = Wire.read();
    Serial.print(c);
  }
}

void setup() {
  Serial.begin(115200);
  Wire.begin(0x09);        // I2C Slave address
  Wire.onReceive(receiveI2C);
}

void loop() {
  delay(100);
}

Learning Outcome

  • Mastered I2C communication setup between RP2040 and ESP32 microcontrollers.
  • Addressed data type conversions and ensured compatibility between devices.
  • Successfully integrated WiFi communication alongside I2C.
  • Enhanced troubleshooting and debugging skills related to data transfer and protocol compatibility.
  • Gained deeper understanding of serial communication protocols (I2C & WiFi) in embedded systems and their combined use for complex applications.

📁 Files


Last update: May 12, 2025