Home

Group Assignment: Week 4


EMBEDDED PROGRAMMING


Embedded Programming

Embedded programming involves writing a program to run on embedded systems, i.e. computing devices consisting typically of a (micro-)processor, memory and peripheral systems for input/output which is designed to perform dedicated functions within larger systems. During programming, a deep understanding of hardware constraints is required and good programming skills are beneficial.

A beginner-friendly embedded system is an Arduino board using the Arduino IDE for programming. For this weeks group assignment, we had to fulfil the following assignments:

  • Browse through the data sheet for your microcontroller
  • Compare the performance and development workflows for other architectures

As the Arduino IDE and its programming language is an easy way to programm a microcontroller, we chose this as a first instance. In addition, Frauke already used CircuitPython in her individual assignment, therefore we selected this as a second one.

Arduino IDE

Frauke programmed already two scripts in CircuitPython which both fulfil one part of the individual assignment. The first script is about interacting with I/O, the second about a serial communication with a host comuputer.

Interacting with I/O

In order to compare the CircuitPython script of Frauke to an Arduino script, we simply translated the python code into C++. Here, we simply went through the code line-by-line and translated the code. It differs only slightly, e.g. the setup has its own loop in Arduino but not so in (Circuit-)Python.

const int buttonPin = D0;     // the number of the pushbutton pin
const int ledPin =  D8;      // the number of the LED pin

int counter = 0;             // counter keeping track of button pushed

unsigned long startTime;      // variable for time when it is started to press the button
unsigned long stopTime;       // variable for time whhen it is stopped to press the button

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);

}

void loop() {
  // check if the pushbutton is pressed. If it is, the buttonState is LOW:
  if (digitalRead(buttonPin) == LOW) {

    // save the time of start pressing
    startTime = millis();

    // Advance counter
    counter = counter +1;
    
    // while the button is continued to being pressed
    while (digitalRead(buttonPin) == LOW){
      delay(100); // do nothing, wait
    }

    // Record time of stop pressing
    stopTime = millis();

    // if button was pressed for less than a second
    if ((stopTime-startTime) < 1000){
      // Blink the LED as many times as the counter
      for (int i = 0; i < counter; i++){
        digitalWrite(ledPin, HIGH);   // turn the LED on (HIGH is the voltage level)
        delay(150);                  // wait for a second
        digitalWrite(ledPin, LOW);    // turn the LED off by making the voltage LOW
        delay(150);                  // wait for a second
      }
    }
    else {
      // Reset counter
      counter = 0;
    }    
  }
}

Simply said, this script advances a counter by one every time the button is pressed. Additionally, everytime the button was pressed, an LED blink as many times as the value of the counter. Lastly, the counter can be reset. Here, the time between the start and stop of pressing the button is measured. In case it is longer than one second, the counter is reset to zero, otherwise it is advanced.

According to the output of the Arduino IDE, this script uses 34252 B of the maximum available 262144 B.

Serial Communication

The second script is about the serial communication between the microcontroller and a host computer. In case the microcontroller receives the message "1" and LED is switched on, and in case of a "0", the LED is switched off. This script is the very same that Frauke already used for her individual assignment.

// declare and initialize pin for LED
const int ledPin =  D8;// the number of the LED pin

String value;

// the setup function runs once when you press reset or power the board
void setup() {
    // initialize digital pin for LED as an output.
    pinMode(ledPin, OUTPUT);
    
    Serial.begin(9600); // Start serial communication
    while (!Serial); // Wait until Serial is open
    Serial.println("listening..."); // Send that Serial is open and listening
}

// the loop function runs over and over again forever
void loop() {
    if (Serial.available() > 0) {
        // read the incoming string
        value = Serial.readString();
        
        if (value == "1"){
            digitalWrite(ledPin, HIGH);   // turn the LED on
            Serial.println("Message '1' received. Turning LED on.");
        }
        else if (value == "0"){
            digitalWrite(ledPin, LOW);   // turn the LED off
            Serial.println("Message '0' received. Turning LED off.");
        }
        else {
            Serial.print("Unknown message '");
            Serial.print(value);
            Serial.println("'. Use '1' and '0' to turn LED on and off.");
        }
    }
}

According to the output of the Arduino IDE, this script uses 35164 B of the maximum available 262144 B.

  

CircuitPython

As for the Arduino IDE, two scripts were programmed in Python, namely the first one regarding the interaction with input and output and the second one about the serial communication with a host computer.

Interacting with I/O

This script is a copy of Frauke's CircuitPython script. It does the very same thing as the first script programmed with Arduino (see above).

import time
import board
from digitalio import DigitalInOut, Direction

# Declare and initialize led and button pins
led = DigitalInOut(board.D8)
button = DigitalInOut(board.D0)

# Set led pin to output and button pin to input
led.direction = Direction.OUTPUT
button.direction = Direction.INPUT

# Declare and initialize counter
counter = 0

while True:
    if button.value == False:
        start = time.monotonic() # Time at start of pressing button
        # if button is pressed (INVERTED)
        counter += 1 	# Advance counter
        while button.value == False:
            time.sleep(0.01)
        stop = time.monotonic() # Time at stopping pressing button   
        if stop-start <= 1:
            # If button was pressed less than a second
            for i in range(counter):
                # For as many times as the value of counter, do
                led.value = True	# Turn led off LED (INVERTED!)
                time.sleep(0.15)	# Wait 1s
                led.value = False	# Turn led on
                time.sleep(0.15)	# Wait 1s
        else: 
            # Reset counter
            counter = 0  

After saving this in the code.py file on the microcontroller that is configured for CircuitPython, the memory size it uses is determined by right-clicking on the file and selecting "properites". Here, it says that the file uses in total 1003 B.

To determine the available memory size of the device, we firstly deleted the script again such that nothing except for the default files are saved on the microcontroller. Then we right-clicked on the device and selected "properties" as well opening a small dialog. Here, it is displayed, that the device has a memory size of 45056 B available.

Serial Communication

The last script is again about the serial communication written in CircuitPython. It again is a copy of one of Frauke's script and it achieves the very same behavior as the second script programmed with Arduino (see above).

import supervisor
import board
from digitalio import DigitalInOut, Direction

# Declare and initialize led pin
led = DigitalInOut(board.D8)
# Set led pin to output
led.direction = Direction.OUTPUT

print("listening...")

while True:
    if supervisor.runtime.serial_bytes_available:
        value = input().strip()
        # Sometimes Windows sends an extra (or missing) newline - ignore them
        if value == "":
            continue
        elif value == "1":
            led.value = True
            print("Message '{}' received. Turning LED on.".format(value))
        elif value == "0":
            led.value = False
            print("Message '{}' received. Turning LED off.".format(value))
        else:
            print("Unknown message '{}'. Use '1' and '0' to turn LED on and off".format(value))

When right-clicking on this file and selecting "properties", it shows in a dialog that this script uses 740 B in total.

  

Comparison of Arduino and CircuitPython

Performance

Regarding the performance, we investigated the uptake of the memory as well as the general performance of the scripts during running.

For the memory uptake, we looked at the maximum available memory on the device as well as at the memory uptake of the scripts. These values are shown for both Arduino and Python scripts in the table below, for both the script for interacting with input and output and the serial communication.

Script Programming Language Memory Uptake Memory Available Percentage
Interacting with I/O Arduino 34252 B 262144 B 13.1 %
CircuitPython 1003 B 45056 B 2.2%
Serial Communication Arduino 35164 B 262144 B 13.4 %
CircuitPython 740 B 45056 B 1.7 %

As you can see, the Python scripts consume a lot less memory, i.e. about 13.25% for the Arduino vs. 1.95% for Python. However, the device has less memory available when configured for CircuitPython. Instead of about 262 KB, the device only has about 45 KB available. This shows that the configuration for CircuitPython in general take up more memory, e.g. due to the bootloader.

In addition to the memory, we also investigated the performance of the microcontroller during running the script. The first scripts we were using interacted with I/O. As expected, these scripts worked exactly as expected. The LED blinked as many times as we have pressed the button previously. In addition, the counter can be reset by pressing the button for more than a second.

Interacting with I/O: Blink according to Counter

Interacting with I/O: Resetting the Counter

For the scripts to interact with I/O, we were therefore not able to see any differences in the preformance visually.

This is however not true for the second script when using a serial communication between the host computer and the microcontroller. The performances when sending messages "1" and "0" can be seen below.

Serial Communication using the Arduino IDE

Serial Communication using CircuitPython

Potentially, the most obvious difference is the blinking of a blue built-in LED when using the Arduino IDE. Every time a serial message is received or sent, the blue LED lights up. In addition, the serial communication with the Arduino IDE take a lot longer. Here, a delay of maybe half a second between sending a message to the microcontroller and receiving a response from the microcontroller that the message was received by the microcontroller is very obvious for the Arduino IDE. This delay is however not present when using CircuitPython. Also, no blue LED blinks.

Presumably, there is a lot more overhead involved when using the Arduino IDE in contrast to CircuitPython.

Development Workflow

The development workflows when using the Arduino IDE and C++ vs. CircuitPython is quite different. Here, we listed and compared the workflows in less detail for an overview. For more details on the exact workflows please refer to Frauke's individual assignment about embedded programming.

For the Arduino IDE, everything is more or less configured. After opening it, the user only has to set the right board and port to communicate/upload sketches and maybe install some libraries that are required. The Arduino is furthermore well developed, maintenance is continuously applied and support is offered. Therefore, the Arduino IDE is really beginner-friendly and easy to use making it advantageous over CircuitPython with regards to the aspects above.

For CircuitPython, the microcontroller firstly had to be configured to be used with this programming language. When using basic programming e.g. interacting with I/O, this is nevertheless easily done. After entering the bootloader mode, the bootloader has to be dragged on the device. For more advanced programming, e.g. serial communication with the host computer, the IDE has also the be configured for CircuitPython. In this case, we used VS Code, which simply has an extension available for CircuitPython. This should have been really easy but we ran into an issue with the latest version and had to install a previous one. However, all-in-all, when using the Arduino IDE, the configuration is very easily achieved, more easily than for CircuitPython. Furthermore, the CircuitPython community is still growing and gains popularity. However, this also means that the support is not so ubiquitous and up to date as for Arduino.

When comparing the uploading behaviour, CircuitPython clearly is advantageous over Arduino. For Arduino, a sketch has to be edited in the Arduino IDE and before uploading, the sketch is verified and compiled. This consumes quite a lot of time in comparison to CircuitPython. Here, the code.py file on the device can simply be opened with an IDE of your choice (we used VS Code). Then, the code can be edited and just by saving the code is uploaded to the device. Here, it must be mentioned, that Python is usually a more compact language than C++. However, it is a preference of the programmer which language to choose.

In total, using the Arduino IDE and C++ or CircuitPython are both beneficial in some aspects and disadvantageous in others. Therefore, it seems to be a choice everybody has to make for themselves.