Skip to content

11. Networking and Communications

Hero Shot!


Group Assignment

You can find more details on our lab site: TechWorks - Networking and Communications

Learning Outcomes:

  • Understand the differences between communication protocols: UART, I²C, SPI
  • Apply these protocols in real embedded systems
  • Evaluate their pros and cons based on project requirements

Overview of Communication Protocols

UART

  • Universal Asynchronous Receiver-Transmitter
  • Uses two wires (TX and RX)
  • No clock signal — devices must agree on the baud rate
  • Used for simple serial communication between two devices

I²C

  • Inter-Integrated Circuit
  • Uses two lines: SDA (data) and SCL (clock)
  • Allows multiple slave devices with unique addresses
  • Slower but requires fewer pins and supports multi-master

SPI

  • Serial Peripheral Interface
  • Uses four lines: MOSI, MISO, SCK, SS (chip select)
  • Faster communication than I²C
  • Ideal for high-speed sensors and displays but uses more GPIOs

🔄 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

💡 Summary: - UART: Great for simple two-device serial communication. - I²C: Best when you want to connect many devices with minimal wiring. - SPI: Preferred for high-speed and high-performance communication, especially for displays and storage devices.


UART Communication Protocol

XIAO RP2040 —> Arduino Uno

I started by connecting the Arduino Uno R3 and the XIAO RP2040. Since the Arduino works at 5V and the XIAO at 3.3V, I needed a voltage divider circuit to avoid damaging the XIAO.

Voltage Divider Circuit

Designed in Altium Designer:

  1. Install: 1x3 header footprint from JLCPCB.
  2. Calculate resistor values R1 “”1k”” and R2 “1k+1k” to divide 5V into 3.3V.
  3. Simulate and fabricate using MODS as done in Electronics Production Week

Images:





Testing the voltage divider using a multimeter:


Wiring: Arduino Uno —> XIAO RP2040

UART Code:

Arduino_Transmitter_UART

#include <SoftwareSerial.h> //to create another serial port on different pins.
SoftwareSerial ArduinoSerial(10, 11); // RX, TX

void setup() {
  Serial.begin(9600);
  ArduinoSerial.begin(9600);
  Serial.println("Arduino ready");

}

void loop() {
  ArduinoSerial.println("Hello from Arduino!");
  delay(1000);
}

XIAO_Reciver_UART

void setup() {
  // Start serial communication on both Serial (for debug) and Serial1 (for UART)
  Serial.begin(9600);   // Serial monitor
  Serial1.begin(9600);  // UART communication with Arduino Uno
}

void loop() {
  // Check if data is available on Serial1 (connected to Arduino)
  if (Serial1.available()) {
    // Read data from Serial1 and send it to Serial monitor
    String data = Serial1.readString();
    Serial.println("Received: " + data);
  }
}


Communication Test:


I²C Communication Protocol

OLED Display with Arduino Uno “For Testing”

Wiring:

  • VCC → 5V
  • GND → GND
  • SDA → A4
  • SCL → A5

Code:

Used Adafruit_SSD1306 and Adafruit_GFX libraries to initialize and print to the OLED. I used the ssd1306_128x64_i2c example provided in the Arduino IDE.

  1. Install Libraries:
  2. Open the Library Manager and install:

    • Adafruit SSD1306
    • Adafruit GFX
  3. Open Example:

  4. Navigate to:
    File > Examples > Adafruit SSD1306 > ssd1306_128x64_i2c

  5. Set Board:

  6. Select board: Arduino Uno
  7. Choose the correct COM port

  8. Upload and Run

OLED Address Check

#include <Wire.h>

void setup() {
  Wire.setSDA(6); // GPIO6 = D4
Wire.setSCL(7); // GPIO7 = D5
Wire.begin();

  Serial.begin(9600);
  while (!Serial); // Wait for serial to be ready
  Serial.println("\nI2C Scanner");
}

void loop() {
  byte error, address;
  int nDevices = 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("  !");

      nDevices++;
    }
    delay(5);
  }

  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(2000);
}

SSd1306 OLED Check

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  Serial.begin(9600);
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    while (1);
  }

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 10);
  display.println(F("SSD1306 Test"));
  display.display();
}

void loop() {}


XIAO RP2040 —> OLED Display

This section explains how to connect an SSD1306-based OLED display to the XIAO RP2040 using the I²C communication protocol.

Wiring:

Ensure your OLED display operates at 3.3V (to match the XIAO RP2040’s logic level).

OLED Pin 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:

Included OLED initialization, I²C address setup, and message display.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1  // No reset pin
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
  Wire.setSDA(4);  // SDA on D4
  Wire.setSCL(5);  // SCL on D5
  Wire.begin();

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;); // Infinite loop if display not found
  }

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 10);
  display.println(F("Hello XIAO!"));
  display.display();
}

void loop() {}


Conclusion

Understanding the communication protocols UART, I²C, and SPI is essential for embedded systems. Choosing between I²C and SPI depends on your speed, wiring, and complexity requirements. For displays, I²C is simple and effective for basic OLEDs, while SPI is better for high-performance displays requiring fast data throughput.


Files

Electronics

Codes