Skip to content

6. Embedded Programming

Welcome to this week’s documentation focusing on embedded programming, where we delve into the fascinating world of microcontrollers by programming the Quentorres board with the Xiao SAMD21 microcontroller to display a Morse code message using both Arduino IDE and CircuitPython workflows.

Learning Outcomes:

  • Implement programming protocols.

Group Assignment Summary:

For this week’s group assignment, our focus was on exploring microcontroller datasheets and comparing the performance and development workflows of various architectures. Here’s a brief overview of our findings:

Microcontroller Datasheet Exploration

We primarily focused on the Xiao SAMD21 microcontroller, which powers the Quentorres board. By analyzing the datasheets for both the microcontroller and the Quentorres board, we gained valuable insights into the hardware specifications, pin configurations, and peripheral capabilities.

Key points discovered: - The Xiao SAMD21 microcontroller features a 32-bit ARM Cortex-M0+ CPU running at up to 48MHz, with 256KB of flash memory and 32KB of SRAM. - The Quentorres board offers 11 PWM pins, 11 general digital pins, 11 analog pins, and 1 I2C interface, along with essential components like reset and user buttons, LEDs, and a USB connector.

Architectures Comparison

We compared the Xiao SAMD21 with other microcontrollers available in our lab, including Arduino Mega, Arduino Uno, and Raspberry Pi RP2040 Zero. Here’s a summary of our comparison:

Microcontroller Xiao SAMD21 Arduino Mega Arduino Uno Raspberry Pi RP2040 Zero
Bit Size 32-bit 8-bit 8-bit 32-bit
Max Clock 48MHz 16MHz 16MHz 133MHz
CPU/Family/Arch ARM Cortex-M0+ AVR ATMEGA2560 AVR ATMEGA328P ARM Cortex-M0+
Storage 256KB flash/32KB SRAM 256KB flash/8KB SRAM 32KB flash/2KB SRAM 2MB flash
I/O Pins 20 general digital, 11 PWM, 6 Analog 54 digital, 15 analog, 15 PWM 14 digital, 6 analog, 6 PWM 26 digital, 3 analog
Operating Voltage 3.3 volts 5 volts 5 volts 3.3 volts
Connectivity - - - Bluetooth, UART, SPI, I2C, GPIO
Price $5 $10 $5 $4
Source Datasheet Datasheet Datasheet Datasheet

Observations and Pros/Cons

  • Each microcontroller has its own strengths and weaknesses, making them suitable for different projects and applications.
  • Arduino Mega offers a high number of I/O pins and ample storage space but uses an 8-bit architecture.
  • Arduino Uno balances simplicity and functionality but has limited I/O pins and storage.
  • Xiao SAMD21 provides a 32-bit architecture with higher clock speed and ample I/O options considering its compact size.
  • Raspberry Pi RP2040 Zero offers enhanced performance and connectivity options at a competitive price.

Individual Assignment:

Introduction

This week’s individual assignment builds upon the Quentorres board, a device crafted and documented during the Electronics Production week. The Quentorres board is powered by the Xiao SAMD21 microcontroller, providing a compact yet powerful platform for embedded programming tasks. For this week’s assignment, we aim to utilize the capabilities of the Quentorres board by programming it to display a Morse code message using one of its built-in LEDs.

Objective

  • The primary objective of this assignment is to familiarize ourselves with embedded programming concepts using the Quentorres board and the Xiao SAMD21 microcontroller. By programming the board to display a Morse code message, we aim to understand the process of interfacing with hardware, writing code to control peripherals, and translating abstract concepts into tangible output.

To achieve this objective, I will be implementing two workflows:

  1. Programming with Arduino IDE: Utilizing the Arduino IDE to write and upload code to the Quentorres board. This workflow provides a familiar environment for embedded programming, enabling us to leverage the vast Arduino ecosystem and libraries.
  1. Programming with CircuitPython: In addition to Arduino IDE, we will explore programming the Quentorres board using CircuitPython. This workflow offers a high-level programming language and simplified syntax, making it accessible for beginners while still powerful enough for advanced projects.

By exploring both workflows, we aim to gain a comprehensive understanding of embedded programming paradigms and choose the most suitable approach for our future projects.

Materials:

Materials required for the assignment:

  • Quentorres board
  • Xiao SAMD21 microcontroller
  • USB cable
  • Computer with Arduino IDE and CircuitPython installed

Workflow 1: Programming with Arduino IDE

1. Setup

follow steps from link

  • Connect the Quentorres board to your computer using the USB cable.
  • Add Seeed Studio XIAO RP2040 board package to your Arduino IDE

Navigate to File > Preferences, and fill Additional Boards Manager URLs with the url below:

https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json

  • Select your board and port.

2. Writing Morse Code Program

    // Pin Definitions
    #define BUTTON_PIN D1 // Change to the pin you're using for the button
    #define LED_PIN D0   // Change to the pin you're using for the LED

    // Morse Code Definitions
    const int dotDelay = 250;  // Time for a dot
    const int dashDelay = 3 * dotDelay;  // Time for a dash
    const int spaceDelay = 3 * dotDelay; // Time between letters
    const int wordDelay = 7 * dotDelay;  // Time between words

    // Morse Code Dictionary
    const char* morseCode[] = {
      ".-",    // A
      "-...",  // B
      "-.-.",  // C
      "-..",   // D
      ".",     // E
      "..-.",  // F
      "--.",   // G
      "....",  // H
      "..",    // I
      ".---",  // J
      "-.-",   // K
      ".-..",  // L
      "--",    // M
      "-.",    // N
      "---",   // O
      ".--.",  // P
      "--.-",  // Q
      ".-.",   // R
      "...",   // S
      "-",     // T
      "..-",   // U
      "...-",  // V
      ".--",   // W
      "-..-",  // X
      "-.--",  // Y
      "--.."   // Z
    };

    void setup() {
      pinMode(BUTTON_PIN, INPUT_PULLUP);
      pinMode(LED_PIN, OUTPUT);
    }

    void loop() {
      if (digitalRead(BUTTON_PIN) == HIGH) { // Check if button is pressed
        sendMessage("Naim Al Haj Ali"); // Change the message here
        delay(1000); // debounce
      }
    }

    void sendMessage(const char* message) {
      for (int i = 0; message[i] != '\0'; i++) {
        if (message[i] == ' ') {
          delay(wordDelay);
        } else {
          char c = toupper(message[i]);
          int index = c - 'A';
          if (index >= 0 && index < 26) {
            flashMorseCode(morseCode[index]);
          }
          delay(spaceDelay);
        }
      }
    }

    void flashMorseCode(const char* morse) {
      for (int i = 0; morse[i] != '\0'; i++) {
        if (morse[i] == '.') {
          digitalWrite(LED_PIN, HIGH);
          delay(dotDelay);
          digitalWrite(LED_PIN, LOW);
        } else if (morse[i] == '-') {
          digitalWrite(LED_PIN, HIGH);
          delay(dashDelay);
          digitalWrite(LED_PIN, LOW);
        }
        delay(dotDelay); // Space between elements of the same letter
      }
    }

3. Explanation of the Code

  • Pin Definitions: Defines the pins for the button and LED on the Quentorres board.
  • Morse Code Definitions: Sets the time durations for dots, dashes, spaces between letters, and spaces between words.
  • Morse Code Dictionary: Stores the Morse code representations for each letter of the alphabet.
  • Setup(): Initializes the pins for input (button) and output (LED).
  • loop(): Checks if the button is pressed and sends the message when it is.
  • sendMessage(): Converts the specified message into Morse code and flashes the LED accordingly.
  • flashMorseCode(): Flashes the LED based on the Morse code representation of a single character.

4. Uploading the Program

a. Select the appropriate board and port in the Arduino IDE. b. Compile and upload the program to the Quentorres board. c. Verify the functionality of the LED displaying the Morse code message.

After uploading the code and testing it, the following message is displayed in the Arduino IDE:

Sketch uses 34404 bytes (13%) of program storage space. Maximum is 262144 bytes.

This indicates that the program utilizes 13% of the available program storage space on the Quentorres board, ensuring efficient usage of resources.

5. Running the Program

Upon viewing the demonstration, it is evident that the Quentorres board accurately displays the Morse code for “Naim Al Haj Ali” through its built-in LED. The blinking patterns have been cross-referenced with a Morse code chart to ensure precision and correctness.

“NAIM AL HAJ ALI” in Morse code is: -. .- .. – / .- .-.. / .... .- .— / .- .-.. ..

6. Communicating With The Board

For this part, I chose to alter the code to communicate with the controller using the serial monitor in the Arduino IDE so that the user can input the message through the serial monitor, which would then be changed into Morse code.

Edited Morse Code Program to utilize Serial Input
// Pin Definitions
#define BUTTON_PIN D1 // Change to the pin you're using for the button
#define LED_PIN D0   // Change to the pin you're using for the LED

// Morse Code Definitions
const int dotDelay = 250;  // Time for a dot
const int dashDelay = 3 * dotDelay;  // Time for a dash
const int spaceDelay = 3 * dotDelay; // Time between letters
const int wordDelay = 7 * dotDelay;  // Time between words

// Morse Code Dictionary
const char* morseCode[] = {
  ".-",    // A
  "-...",  // B
  "-.-.",  // C
  "-..",   // D
  ".",     // E
  "..-.",  // F
  "--.",   // G
  "....",  // H
  "..",    // I
  ".---",  // J
  "-.-",   // K
  ".-..",  // L
  "--",    // M
  "-.",    // N
  "---",   // O
  ".--.",  // P
  "--.-",  // Q
  ".-.",   // R
  "...",   // S
  "-",     // T
  "..-",   // U
  "...-",  // V
  ".--",   // W
  "-..-",  // X
  "-.--",  // Y
  "--.."   // Z
};

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(9600); // Initialize serial communication
}

void loop() {
  if (Serial.available() > 0) { // Check if serial data is available
    String message = Serial.readStringUntil('\n'); // Read the message from serial monitor
    sendMessage(message); // Send the message in Morse code
  }
}

void sendMessage(const char* message) {
  for (int i = 0; message[i] != '\0'; i++) {
    if (message[i] == ' ') {
      delay(wordDelay);
    } else {
      char c = toupper(message[i]);
      int index = c - 'A';
      if (index >= 0 && index < 26) {
        flashMorseCode(morseCode[index]);
      }
      delay(spaceDelay);
    }
  }
}

void flashMorseCode(const char* morse) {
  for (int i = 0; morse[i] != '\0'; i++) {
    if (morse[i] == '.') {
      digitalWrite(LED_PIN, HIGH);
      delay(dotDelay);
      digitalWrite(LED_PIN, LOW);
    } else if (morse[i] == '-') {
      digitalWrite(LED_PIN, HIGH);
      delay(dashDelay);
      digitalWrite(LED_PIN, LOW);
    }
    delay(dotDelay); // Space between elements of the same letter
  }
}
Explanation of the Modified Code

In this modified version of the code, the Arduino IDE program waits for input from the serial monitor. Once a message is received, it converts the message to Morse code and displays it using the LED. This modification enhances user interaction and allows for dynamic message display on the Quentorres board.

  • Pin Definitions: Defines the pins used for the button and LED on the Quentorres board.
  • Morse Code Definitions: Specifies the durations for dots, dashes, spaces between letters, and spaces between words in Morse code.
  • Morse Code Dictionary: Stores the Morse code representations for each letter of the alphabet.
  • Setup(): Initializes the pins for input (button) and output (LED), and begins serial communication.
  • loop(): Continuously checks for serial input. When a message is received from the serial monitor, it triggers the sendMessage() function.
  • sendMessage(): Converts the received message into Morse code using the Morse code dictionary and calls flashMorseCode() to flash the LED accordingly.
  • flashMorseCode(): Flashes the LED based on the Morse code representation of a single character, with appropriate delays for dots, dashes, and inter-character spacing.
Uplading the Program

The program was uploaded in the same way as the previous version.

Running the Program

Message is inserted in the serial monitor and used as an inout for the program to run.

Workflow 2: Programming with CircuitPython

1. Setup

follow steps from link

  • Entering the DFU bootloader mode by using a jumper to short connect RST Pins twice quickly.
  • An external drive named Arduino should appear in your PC. Drag the the downloaded CircuitPython uf2 files to the Arduino drive.

  • Once loaded the CircuitPython bootloader, unplug the USB Type-C and re-connect. A new external drive called CIRCUITPY should appear.

  • Write you python program and name it main.py and drag it onto the CIRCUITPY drive.

I used VS Studio

  • Intsall Circuit Python extension.
  • Open main.py and edit code.

2. Writing Morse Code Program

import time
import board
import digitalio

# Define button and LED pins
button_pin = board.BUTTON_A
led_pin = board.D13

# Morse Code Definitions
dot_delay = 0.25   # Time for a dot
dash_delay = 3 * dot_delay   # Time for a dash
space_delay = 3 * dot_delay  # Time between letters
word_delay = 7 * dot_delay   # Time between words

# Morse Code Dictionary
morse_code = {
    'A': '.-',     'B': '-...',   'C': '-.-.', 
    'D': '-..',    'E': '.',      'F': '..-.',
    'G': '--.',    'H': '....',   'I': '..',
    'J': '.---',   'K': '-.-',    'L': '.-..',
    'M': '--',     'N': '-.',     'O': '---',
    'P': '.--.',   'Q': '--.-',   'R': '.-.',
    'S': '...',    'T': '-',      'U': '..-',
    'V': '...-',   'W': '.--',    'X': '-..-',
    'Y': '-.--',   'Z': '--..',   ' ': ' '
}

# Initialize button and LED
button = digitalio.DigitalInOut(button_pin)
button.direction = digitalio.Direction.INPUT
button.pull = digitalio.Pull.UP

led = digitalio.DigitalInOut(led_pin)
led.direction = digitalio.Direction.OUTPUT

def flash_morse_code(morse):
    for char in morse:
        if char == '.':
            led.value = True
            time.sleep(dot_delay)
        elif char == '-':
            led.value = True
            time.sleep(dash_delay)
        led.value = False
        time.sleep(dot_delay)  # Space between elements of the same letter

def send_message(message):
    for char in message:
        char_upper = char.upper()
        if char_upper in morse_code:
            flash_morse_code(morse_code[char_upper])
            time.sleep(space_delay)
        else:
            # If the character is not in Morse code dictionary, ignore it
            pass
    time.sleep(word_delay)  # Wait between words

# Main loop
while True:
    if not button.value:  # Check if button is pressed
        send_message("NAIM AL HAJ ALI")  # Change the message here
        time.sleep(0.5)  # debounce

3. Explanation of the Code

  • This CircuitPython code defines the button and LED pins, Morse code definitions, and initializes the button and LED.
  • The flash_morse_code() function flashes the LED according to the Morse code patterns.
  • The send_message() function converts the message to Morse code and flashes the LED accordingly.
  • The main loop continuously checks if the button is pressed and sends the message “NAIM AL HAJ ALI” in Morse code when pressed.

4. Uploading the Program

  • Select the appropriate board and port in your code editor.
  • Save the CircuitPython program to the Quentorres board.
  • Verify the functionality of the LED displaying the Morse code message.

5. Running the Program

Upon viewing the demonstration, it is evident that the Quentorres board accurately displays the Morse code for “Naim Al Haj Ali” through its built-in LED. The blinking patterns have been cross-referenced with a Morse code chart to ensure precision and correctness.

“NAIM AL HAJ ALI” in Morse code is: -. .- .. – / .- .-.. / .... .- .— / .- .-.. ..