Skip to content

11. Embedded Networking and Communications

Group assignment:

  • Send a message between two projects.

  • Document your work to the group work page and reflect on your individual page what you learned

This week we tried to communicate between two microcontroller boards using the I2C connection (SDA and SCL) and also used UART connection (RX TX) to connect the DF mini player with our board. We used XIAO RP2040 as controller board(Master board) and on the other hand we used XIAO SAMD21 as peripheral board(Slave board) and tried communicating with each other by sending couple of messages from one laptop to another.

I2C communication between XIAO Rp2040 and XIAO SAMD21

For connecting devices with our boards we had referred to the pinout diagrams for the microcontrollers which is mentioned below.

I2C(Inter-Integrated Circuit)

  • Synchronous communication protocol is used to communicate between two boards which we had utilised in our group assignment.

  • Uses SDA(Data Line) and SCL(Clock Line)

  • Data can be transmitted and Received but not simultaneously on same data line.

For I2C communication, we had connected SDA and SCL pins of controller board(Master board) to SDA and SCL pins of the peripheral board (Slave board). Followed by that we had connected DF player mini with micro controller board using UART (RX TX) connection. Simultaneously we had also connected speaker and Led with XIAO SAMD21 which we had kept as our peripheral board(Slave board) for the communication.

The image shows the connection made between two microcontroller boards

Here are codes we used.

XIAO RP2040's code which worked as a controller board (Master board), which initiates the communiation with XIAO SAMD21

#include <Wire.h>

const int slaveAddress = 0x08; // I2C address of the slave device
String inputMessage = "";      // Variable to store user input

void setup() {
Wire.begin();                // Initialize I2C as master
Serial.begin(115200);        // Start Serial communication for input/output

Serial.println("Ready to send I2C messages.");
Serial.println("Type your message below and press Enter:");
}

void loop() {
// Wait for user input from Serial Monitor
if (Serial.available()) {
    inputMessage = Serial.readStringUntil('\n'); // Read message until Enter key

    inputMessage.trim(); // Remove any accidental whitespace or newline

    if (inputMessage.length() > 0) {
    // Begin I2C transmission
    Wire.beginTransmission(slaveAddress);
    Wire.write(inputMessage.c_str()); // Send as C-style string
    Wire.endTransmission();

    // Confirm message was sent
    Serial.print("Message sent to Dorji: ");
    Serial.println(inputMessage);
    }

    // Prompt for next message
    Serial.println("\nType another message:");
}
}

XIAO SAMD21's code which worked as a peripheral board (Slave board) where we can receive the messages sent by XIAO RP2040 which can be viewed in serial monitor

#include <DFRobotDFPlayerMini.h>
#include <SoftwareSerial.h>
#include <Wire.h>

// Pin Definitions
const int ledPin = D10;          // Pin connected to LED
const int I2C_ADDRESS = 0x08;    // I2C Address of this device (must match master)

// Software Serial for communication with DFPlayer Mini
SoftwareSerial mySerial(D2, D3); 
DFRobotDFPlayerMini myDFPlayer;   // Create DFPlayer object

void setup() {
// Start Serial communication for debugging
Serial.begin(115200);        
mySerial.begin(9600);        // Start SoftwareSerial for DFPlayer

// Initialize I2C communication as slave
Wire.begin(I2C_ADDRESS);      
Wire.onReceive(receiveEvent); // Register I2C receive event

// Initialize LED pin
pinMode(ledPin, OUTPUT);

// Initialize DFPlayer Mini
initializeDFPlayer();
}

void loop() {
// Main loop is empty because we're waiting for I2C data
}

// Function to initialize DFPlayer Mini
void initializeDFPlayer() {
Serial.println(F("Initializing DFPlayer..."));

if (!myDFPlayer.begin(mySerial)) {
    Serial.println(F("DFPlayer initialization failed!"));
    Serial.println(F("1. Check RX/TX connections (must be crossed)"));
    Serial.println(F("2. Insert SD card with MP3 files"));
    while (true);  // Halt if initialization fails
}

Serial.println(F("DFPlayer Mini ready!"));
Serial.println("Waiting for message from Roshan!");
myDFPlayer.volume(30);  // Set initial volume (0-30)
}

// Function that handles incoming I2C data
void receiveEvent(int bytesReceived) {
// Read the received data from I2C
String data = "";
while (Wire.available()) {
    data += (char)Wire.read();  // Read each byte and convert to character
}

// Check the received data and print it
Serial.print("Message from Roshan: ");
Serial.println(data);

handleReceivedmessage();  // Call function to display  the message

}

// Function to handle the "hello" message
void handleReceivedmessage() {
// Turn on LED
digitalWrite(ledPin, HIGH);
// Play tracks
myDFPlayer.play(1);  // Play the track

delay(3000);

// Turn off LED
digitalWrite(ledPin, LOW);
}

Explainantion on video and the code for the documentation

For the code, we had referred to a previous year's Fab Academy student's page and then we had editted on it as per our convenient

The code includes communication between two boards, one being the controller board (master board) which sends the messages and the other being the peripheral board (slave board) which receives the messages sent by controller board (master board). We had connected board boards differently using two laptops. And the messages typed on controller board (master board) can be delivered into peripheral board (slave board) which can be viewed on the serial monitor of peripheral board (slave board).

The reason of connecting DF mini player with our board is just to play notification sound or an alert tone to notify that the messages sent from controller board (master board) to peripheral board (slave board) has been sucessfully received and at the same time we also included LED to blink with notification tone.

Video shows the simulation between the connector and peripheral board sending and receiving messages