Skip to main content

Week 11 — Group Assignment: Networking and Communications

warning

PCB CNC milling not available at time of writing at the workspace. Thus, tests were mainly done on breadboard. The final result — with the CNC milling — could be seen further below.

Networking refers to the connection of multiple devices that enables communication and the exchange of data between them. This approach offers several advantages as it enables modularity:

  • Reduce interference of signals i.e. separating voltage and signal buses
  • Allowing individual parts of a system to be developed, tested, and replaced

Week 11 assignment could be categorized as follows:

  • Group assignment

    • Direct wired/wireless communication between two nodes
  • Individual assignment

    • Wired/wireless integration (to designed embedded microcontroller system)
Basics of hardware communications

Hardware communication can be categorized into wired and wireless methods.

  • Wired

    • Communication method (how bits are transmitted):

      • Peripherals

        • PIO : Programmable processor inside (certain) microcontrollers for custom I/O behavior (e.g. want more than one I2C/SPI bus)
        • GPIO : Basic digital pins. Can be used for bit-banging (method of sending and receiving data manually through software and the GPIOs instead of using dedicated hardware peripheral and so could behave like the PIO)
        • Hardware specific peripherals :
          • UART/USART
          • I2C
          • SPI
      • Asynchronous serial communication (UART)

        • No shared clock signal between devices. Instead both sides must agree in advance on parameters such as the baud rate (number of bits transmitted per second). 9600 baud means each bit takes approximately 1 / 9600 ≈ 0.000104 sec (104 µs) to transmit.
        • Standards :
          • RS - 232 : Older standard using higher voltage levels (12 V)
          • RS - 485 : Used in industry
        • Communication schemes for multiple devices (methods or rules that define how devices exchange data on a network):
          • Serial broadcast : sending a message to all nodes on a network/bus. The master sends command through TX and all microcontrollers for example receive it on RX. IDs are assigned to devices so that it is clear if the message is meant for them or not.

          • Hop-count : sending message based on the number of devices that it has passed through. First device for example sends a message with hop = 0. Each device then increments the hop count as it forwards the message. Advantage of this method is that no device IDs or address is needed (e.g. LED strips).

          • Broad-hop : Combination of serial broadcast and hop-count. Each devices could activate immediately and at the same time no device IDs or address is needed.

      • Synchronous serial communication

        • Receiver/slave and sender/master is used interchangeably.
        • Shared clock signal between devices. Master control the pulses/timing of the connected devices.
        • Types :
          • I2C/TWI :
            • Variations : QWIC from SparkFun, STEMMA (Adafruit)
            • Uses two lines :
              • SDA (serial data Line) : Carries data
              • SCL (serial clock line)
              • Implication : Data can go both direction, but only one direction at a time
            • Communication steps :
              • Start. Master initiates communication. SDA low. SCL high (high always mean that device should read, low means reject).
              • Master sends 7-bit address of the slave (i.e. select which device) and the R/W (read or write) bit. This is required because data can only go one direction at a time
              • At the 9th bit, the slave/received responds with ACK (i.e. acknowledged) or NACK (i.e. not acknowledged) and is represented by SDA low and SDA high respectively
              • Stop. SDA high. SCL high.
          • SPI :
            • Uses four lines :
              • MOSI (master out, slave in) : Carries data from master to slave
              • MISO (master in, slave out) : Carries data from slave to master
              • CS (chip select) : slave select i.e. activates a specific slave device
              • SCK : serial clock
              • Implication : Data can go both direction and at the same time
            • Communication steps :
              • Master selects slave. CS low
              • MOSI and MISO can run at the same time, and so the equivalent of ACK at I2C is simply the response from example the MISO
              • Stop signal. CS high
      • Communication protocol (rules, structure and system behaviour. Built on top of communication method):

        • USB :
          • Human interface device (HID) : keyboard, mouse, game controller, etc
          • Musical instrument digital interface (MIDI) : synthesizers, drumpads. Instead of raw data, it sends musical messages or instructions to create sound (Note ON, note OFF, velocity or how hard the button is pressed, control changes such as knobs and sliders)
        • Ethernet : widely used for local area networks (LANs). Operates at the layer 2 of the OSI (i.e. MAC) model
          • Note : Use the modules, not the chips.
        • CAN/LIN : Industrial application
        • MODBUS : Industrial application
        • DMX : Commonly used for street lighting systems

7 layers of networking :

This table maps the 7 OSI layers to embedded networking technologies, with the role descriptions included inline.

OSI LayerRoleEmbedded / Networking Examples
7. ApplicationUser-level protocol; what the device/application actually usesHTTP (web, runs with TCP), MODBUS TCP, MQTT (usually for IoT and low power devices), USB HID/MIDI
6. PresentationHandles encryption, compression, and data representationSSL/TLS (HTTPS), JSON / XML, MIDI packet formatting
5. SessionKeeps track of ongoing conversations between devicesTCP sessions, MQTT persistent sessions, WebSocket sessions
4. TransportEnsures data is delivered correctly and in order; manages ports (tells OS which application/service should handle incoming or outgoing network traffic. Without port numbers, computer will not know whether incoming data is meant for browser, email, or some other app, because all share the same IP address).TCP (client establishes a connection with server, data is sent in packets and each packet is acknowledged, lost packets are retransmitted), UDP (client sends packets to server no ACK, server receives what it can and missing packets are ignored); Modbus TCP; socket = combination of IP + port + transport protocol. Analogy: user's apartment number
3. NetworkDetermines how data reaches the correct device across networksIPv4/IPv6 (e.g. 192.168.1.1), DNS (human-readable IP names, e.g. www.tim.com), routing tables, Zigbee network addresses. Analogy: street address of the apartment
2. Data Link / MACPrevents collisions, wraps data in frames, decides who talks when, unique identifier assigned to a network chip. Analogy is the apartment door name at the mailboxEthernet MAC addresses, I²C/SPI master-slave rules, Wi-Fi CSMA/CA (listen first, transmit if idle; if busy, wait random time). Analogy: apartment door/mailbox name
1. PhysicalThe hardware layer; bits moving over wires or wireless signalsEthernet cables, fiber optics, SPI/I²C/UART signals, Wi-Fi radio
  • Lower layers (1–2) → mostly handled by hardware (SPI, I²C, Ethernet, CAN controller)

  • Middle layers (3–4) → handled by hardware + software stacks (IP stack, TCP/UDP stack). Stacks here is defined as collection of software components that works together to implement a certain functionality.

  • Upper layers (5–7) → handled in firmware or application code (HTTP, MQTT, USB HID/MIDI)

  • Note :

    • Fabacademy generally focuses on layer 1 to 3
    • Virtual private network (VPN) :
      • Creates a secure, encrypted tunnel over the public Internet
      • Internet service providers may intentionally slow down specific traffic (throttling) and so with VPN it could be faster
      • Steps :
        • Your device sends data → VPN software encrypts it
        • Encrypted data is sent through the Internet to a VPN server
        • VPN server decrypts the data
        • VPN server forwards the request to the destination server (e.g. website)
        • Response comes back → VPN server encrypts it again
        • Your device receives and decrypts it
  • Wireless :

    • Frequency

      • Higher frequency, shorter wavelength. Carry more data but absorbed or reflected by obstacles more easily (e.g. 2.4 GHz Wi-Fi), could be even just line of sight.
      • Lower frequency, longer wavelength. Carry less data, but travels farther and through walls (e.g. 433 MHz LoRa)
    • Capacity

      • Amount of data that a channel can carry reliably. Measured in bits per second (bps or Mbps).
      • Bandwidth : Range of frequencies a channel can use to transmit data. Measured in Hz.
      • Signal-to-noise ratio (SNR) : Strength of desired signal vs background noise. Measured in dB.
      • High capacity = High bandwidth, high SNR
      • Note : In the ocean not much interference
    • Band : Range of radio frequencies grouped together for a specific type of communication. Example 2.400-2.4835 is equals to 2.4 GHz ISM band

      • Industrial, scientific, medical (ISM) bands are frequency ranges reserved for unlicensed use. Meaning anyone can use it without special government license.
      • IEEE standards for wireless communication :
    • Network model :

      • Client - server : device request data (client) or a device hosts data (server). Requires access points (AP) like Wi-Fi routers that manages wireless clients to connect to a network (e.g. converts digital data to radio waves at physical layer, then manages MAC addresses, prevents collisions, schedules timing of the communication between clients at the data link layer). Example: An ESP32 Wi-Fi module requests the current time from a server on the Internet. The request goes through a Wi-Fi router (AP), which forwards the data and sends back the response.
      • Mesh networking : Devices (nodes) communicate directly with each other without requiring a central AP. Data can hop through multiple intermediate nodes to reach its destination. Some nodes, called meshcore, manage routing and may connect the mesh to the Internet (e.g. Raspberry pi), while meshtatic or edge nodes relay data and perform sensing or actuation.
    • Technology :

      TechnologyTypeRangeFrequencyData RatePower UsageInternet Support
      Wi-FiRF50–100 m2.4 / 5 GHz10–600 Mbps100–1000 mWYes
      Bluetooth (BLE)RF10–50 m2.4 GHz125 kbps–2 Mbps1–10 mWIndirect (via phone/gateway)
      RFID / NFCRF0.04–0.1 m13.56 MHz / 125–134 kHz106–424 kbps~0 mW (passive)No
      LoRaRF2–15 km433 / 868 / 915 MHz0.3–50 kbps10–100 mWNo (requires LoRaWAN)
      Optical (IR)Light1–10 m400–800 THz10–100 kbps10–50 mWNo
      • Radio Frequency (RF)

        • Wi-Fi

          • Requires access point (router)
          • Wireless local network (also LAN, see ethernet). Internet comes from the internet service provider and router/access point acts as a gateway between the two.
        • Bluetooth :

          • Bluetooth Low Energy (BLE) is a subset. nRF Toolbox by Nordic can be used for testing and communication
        • Radio Frequency Identification (RFID):

          • Near Field Communication (NFC) is a subset. No battery required. Harvest energy from the reader's electromagnetic field.
        • LoRA (Long Range)

          • LoRAWAN is a network protocol built on LoRA. Can be deployed as private or public networks
      • Optical (Light-based communication). Higher frequency than RF

        • Uses infrared or visible light
        • No licensing

Source: ChatGPT by OpenAI, April 2026

Direct wired/wireless communication between two nodes

In previous weeks, wired communication has already been explored multiple times. Therefore, the experiment this time primarily focuses on testing wireless communication between nodes. The XIAO ESP32C3 supports Bluetooth Low Energy (BLE), and so its functionality is tested to evaluate its usability and communication range.

The I2C communication with the microcontroller will be further investigated — building on the work from week 6 :Electronics design — using a logic analyzer to better understand and decode the data.

Bluetooth communication (2x XIAO ESP32C3)

A node consist of a XIAO ESP32C3 and is connected to an OLED display to show the status of the connection (i.e. connected or disconnected). The task of the corresponding nodes are as follows :

  • One acts as the server, advertising its presence and responding to data requests through services. Characteristics are individual pieces of information within those services, which clients can read or write.
  • One acts as the client. Scans nearby BLE devices and connects to the server.

It could be seen that the two devices could disconnect if a certain distance threshold is passed.

The code used for this experiment is primarily based on the official Seeed Studio example for BLE communication on the XIAO ESP32C3. It is adapted to fit the experiment setup and the code could be seen at the collapsible blocks below. Since it works with the "pointers" concept, some explanations are also given below.

Basic info about pointers / scope resolution operator

A pointer is a variable that does not store a value directly, but instead stores the memory address of another variable or object. An example is given below:

BLEServer* pServer;
pServer = BLEDevice::createServer();
pServer->createService(SERVICE_UUID);

Where:

  • BLEServer a blueprint for a BLE server object. Essential to be called.
  • * is a pointer (stores the address of a BLEServer object)
  • pServer is variable name. Can also be other name
  • -> is a function that basically request the variable to access the address and use the function of the object
  • :: uses the original function of an object by the developer

Source: ChatGPT by OpenAI, April 2026

Server OLED x XIAO ESP32C3 BLE code

Server waits for client to connect, reacts through callbacks and updates the OLED respectively, and can notify client of any changes in the characteristic value.

For more details on the code i.e. programming language, please refer to resources online.

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// ----- OLED (128x64 I2C) -----
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define OLED_ADDRESS 0x3C
#define PIN_SDA 6
#define PIN_SCL 7

// ----- BLE UUIDs -----
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define DEVICE_NAME "thexiao"

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

BLEServer* pServer;
BLECharacteristic* pCharacteristic;

bool deviceConnected = false;
bool lastState = false; // track OLED updates

// OLED helper
void oledShow(const char* a, const char* b, const char* c, const char* d) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(a);
display.println(b);
display.println(c);
display.println(d);
display.display();
}

// BLE callbacks
class ServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* server) override {
deviceConnected = true;
Serial.println("Device Connected");
}

void onDisconnect(BLEServer* server) override {
deviceConnected = false;
Serial.println("Device Disconnected");

// Restart advertising
delay(100);
pServer->getAdvertising()->start();
Serial.println("Advertising restarted");
}
};

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

// Initialize OLED
Wire.begin(PIN_SDA, PIN_SCL);
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {
Serial.println(F("SSD1306 begin failed"));
while (true) delay(1000);
}
oledShow("thexiao", "booting...", "", "");

// BLE init
BLEDevice::init(DEVICE_NAME);
pServer = BLEDevice::createServer();
pServer->setCallbacks(new ServerCallbacks());

BLEService* pService = pServer->createService(SERVICE_UUID);

// BLE characteristic with READ, WRITE, NOTIFY
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY
);

pCharacteristic->setValue("you found me!!");
pCharacteristic->addDescriptor(new BLE2902()); // required for NOTIFY

pService->start();

// Start advertising
BLEAdvertising* adv = BLEDevice::getAdvertising();
adv->addServiceUUID(SERVICE_UUID);
adv->setScanResponse(true);
BLEDevice::startAdvertising();

oledShow("thexiao", "hiding in RF", "find me...", "");
}

void loop() {
// Only update OLED when connection state changes
if (deviceConnected != lastState) {
lastState = deviceConnected;

if (deviceConnected) {
oledShow("YOU FOUND ME", "ok u win", "hello!", "");
} else {
oledShow("thexiao", "still hiding", "...", "...");
}
}
delay(100);
}
Client OLED x XIAO ESP32C3 BLE code

Client seeks the server, connects when found, reads data and shows status on OLED, and keeps trying if disconnected.

For more details on the code i.e. programming language, please refer to resources online.

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <BLEClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define OLED_ADDRESS 0x3C
#define PIN_SDA 6
#define PIN_SCL 7

#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

#define DEVICE_NAME_TARGET "thexiao"

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

BLEScan *pBLEScan = nullptr;
BLEClient *pClient = nullptr;

volatile bool wantConnect = false;
volatile bool connected = false;
BLEAddress *pTargetAddr = nullptr;

// Store last seen device info
String lastName = "";
int lastRSSI = 0;

// OLED helper
void oledShow(String a, String b, String c, String d) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(a);
display.println(b);
display.println(c);
display.println(d);
display.display();
}

// Client callbacks
class ClientCallbacks : public BLEClientCallbacks {
void onConnect(BLEClient *c) {
connected = true;
}

void onDisconnect(BLEClient *c) {
connected = false;
wantConnect = false;

if (pTargetAddr) {
delete pTargetAddr;
pTargetAddr = nullptr;
}

if (pBLEScan) {
pBLEScan->clearResults();
pBLEScan->start(0, false);
}
}
};

// Scan callbacks
class ScanCallbacks : public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {

// Save last seen device for display
if (advertisedDevice.haveName()) {
lastName = advertisedDevice.getName();
} else {
lastName = "(no name)";
}
lastRSSI = advertisedDevice.getRSSI();

// Show scanning activity on OLED
if (!connected && !wantConnect) {
oledShow("Scanning...",
lastName,
"RSSI: " + String(lastRSSI),
"");
}

// Check for target
if (connected || wantConnect) return;
if (!advertisedDevice.haveName()) return;

if (advertisedDevice.getName() != DEVICE_NAME_TARGET) return;

// FOUND TARGET
if (pBLEScan) pBLEScan->stop();

if (pTargetAddr) {
delete pTargetAddr;
pTargetAddr = nullptr;
}

pTargetAddr = new BLEAddress(advertisedDevice.getAddress());
wantConnect = true;
}
};

void setup() {
Serial.begin(115200);
Wire.begin(PIN_SDA, PIN_SCL);

if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {
Serial.println(F("SSD1306 begin failed"));
while (true) delay(1000);
}

oledShow("seeker mode", "scanning...", "", "");

BLEDevice::init("");

pClient = BLEDevice::createClient();
pClient->setClientCallbacks(new ClientCallbacks());

pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new ScanCallbacks());
pBLEScan->setActiveScan(true);
pBLEScan->setInterval(500);
pBLEScan->setWindow(49);

pBLEScan->start(0, false);
}

void loop() {
static unsigned long lastScanRestart = 0;

if (wantConnect && !connected && pTargetAddr != nullptr) {
oledShow("WAIT WAIT", "target locked", "connecting...", "");

if (pClient->connect(*pTargetAddr)) {
wantConnect = false;

BLERemoteService *svc = pClient->getService(SERVICE_UUID);
if (svc != nullptr) {
BLERemoteCharacteristic *ch = svc->getCharacteristic(CHARACTERISTIC_UUID);
if (ch != nullptr && ch->canRead()) {
Serial.println(ch->readValue());
}
}

oledShow("THERE U ARE", "got u thexiao", "connected!", "!!!");
} else {
wantConnect = false;
delete pTargetAddr;
pTargetAddr = nullptr;

if (pBLEScan) {
pBLEScan->clearResults();
lastScanRestart = millis();
}

oledShow("scan retry...", "", "", "");
}
}

else if (connected) {
oledShow("still linked", "to thexiao", "", "");
}

if (!connected && pBLEScan && (pTargetAddr == nullptr) && (millis() - lastScanRestart > 50)) {
pBLEScan->start(0, false); // restart scanning immediately
lastScanRestart = millis();
}

delay(50); // smaller delay for faster responsiveness
}

The XIAO ESP32C3 has built-in BLE and Wi-Fi capabilities; however without the antennas, the microcontrollers only create small electrical signal. The antennas in fact converts it into radio waves and direct it to specific frequencies. Newer XIAO ESP32s (e.g. ESP32C6) include built-in internal antenna that is perhaps strong enough and comparable to the C3 with antennas.

info

Connecting the IPEX Antenna to XIAO ESP32C3 takes patience. Align and apply gentle pressure straight down until it clicks.

A comparison on the range could be seen below.

10 cm

Another stress test perhaps could be done to check the maximum range of the two antenna in the future.

Overall, it is clear that this experiment is more complex compared to previous work (i.e. one direction communication, wired). This is due not only to the increased uncertainty introduced by wireless communication, but also to the need to manage communication between two microcontrollers, including defining the response of the devices to the other.

I2C communication (XIAO ESP32C3 x OLED)

The setup and a segment of the overall signal captured from the XIAO ESP32C3 acting as a BLE client using the logic analyzer is shown below:

Note because it is keep on searching signal so that it give signal frequently.

Converting Binary to Hexadecimal

Hexadecimal Basics:

  • Hexadecimal is a base-16 number system.
  • It uses digits 0–9 and letters A–F, where A = 10, B = 11, ..., F = 15.
  • One hexadecimal digit represents exactly 4 binary bits.

Steps to convert binary to hexadecimal:

  1. Group the binary digits into sets of four, starting from the right.
  2. Convert each 4-bit group to its hexadecimal equivalent.

Example:

Binary: 01001001
Step 1: Split into 4-bit groups → 0100 1001
Step 2: Convert each group → 0100 = 4, 1001 = 9
Hexadecimal: 0x49

Source: ChatGPT by OpenAI, April 2026

Two packets were identified and the interpretation of it are as follows:

  • 1st packet:

    • 0x3C WR = This is the 7-bit address of the OLED device (0x3C) combined with a write (WR) operation.
    • 0x40 = The following bytes are interpreted as data bytes for the OLED.
    • 0x00 (binary: 00000000) = This byte represents pixel data with all pixels turned off.
    • 0x26 (binary: 00100110) = This byte turns on the 3rd, 4th, and 6th pixels.
    • 0x49 (binary: 01001001) = This byte turns on two pixels separated by gaps.
    • 0x49 (binary: 01001001) = The same pattern repeats for the next pixel row.
  • 2nd packet:

    • 0X23 WR : Appears to be another I2C device. This is typically the address of a BH1750 light sensor; however, since this sensor is not present in the experimental setup, the signal is likely caused by noise.
    • 0x80
    • 0x0F
    • 0xC1
    • 0x43
    • 0x45

Despite the noticeable noise on the second I2C operation (i.e. the second packet), it appears that the communication is still functioning correctly, which is evident from the first packet with the expected data bytes and the intended device, as well as the acknowledgement (ACK) bit.