Skip to content

Week 4 Embedded Programming

This page documents the group assignment for week 04 of Högni, Jóhannes and Ólöf.

  • Demonstrate and compare the toolchains and development workflows for available embedded architectures
  • Document your work to the group work page and reflect on your individual page what you learned

Glossary

This week's projects include words/concepts that are new to us and we decided to explain a few of them for better understanding.

Architecture of an embedded system

Means the abstract structure of interacting elements of an embedded system (both hardware and software).
Embedded Systems Architecture; Noergaard, Tammy 2005

Architecture of microprocessors

Microcontrollers use either HARVARD or VON-NEUMANN architecture, which describes how the processor exchanges data with the memory. Harvard architecture (RISC) is what is used in modern microcontrollers. It allows a higher speed compared to the VON-NEUMANN architecture (CISC).
Philadelphia University

Bootloader

A small programm on a separate storage area of a microcontroller, that enables the microcontroller to receive a new program.
Proteus

Core

Enables the compatibility of a type of microcontroller with the IDE.
Arduino Documentation

Embedded System

An applied computer system with limited hardware and/or software functionality and designed for a specific function and high reliability.
Embedded Systems Architecture; Noergaard, Tammy 2005

IDE

An integrated development environment (IDE) is a software application that provides comprehensive facilities for software development.
Wikipedia

Library

Package containing code / functions that are ready-to-use for a certain purpose.
Digikey

Package
Defines the size and mounting type of an electronical component.
Wikipedia
Processor

An electrical components that performs an operation on an external data source.
Wikipedia

Toolchains

All the tools that are used together, and form a chain or sequence, to transform a code into an operating firmware.
Machines that Make

Word size

The number of bits a processor can process in a single cycle. (usually 8, 16, 32 or 64 bits).
Ktpql

ATtiny412

The ATtiny412 microcontroller with an 8-bit AVR processor that can run up to 20MHz and has a 256B memory. Information on ATtiny on DigiKey.

Datasheet and pinout

Datasheet and pinout

Datasheet and pinout for ATtiny412 here. The image below is a screenshot from the datasheet.

Pinout from datasheet

More abot the pins on ATtiny412

This screenshot below is taken from Spence Konde and it shows well the function of each pin.

Pinout from Spence Konde

To understand the pins better I looked at how Adrián Torres explained the pins according to these screeshots above. Adrián Torres lists the pins this way:

VDD: Supply voltage

GND: Ground

Digital pins: PA0, PA1, PA2, PA3, PA4, PA5, PA6 = 7 pins.

Analog pins: PA1, PA2, PA3, PA4, PA5, PA6 = 6 pins.

UPDI Programming pins: PA0 (Physical pin nr. 6).

External Clock Pin: PA3

Adrián Torres also mentiones that all I/O pins can be configured with internal pullup resistance. He also defines which pins can use USART/SPI/TWI communications, but since they have pins in common, they cannot use different communications at the same time:

USART - Universal Synchronous and Asynchronous Receiver and Transmitter: RX(PA1) and TX(PA2).

SPI - Serial Peripheral Interface: MOSI(PA1), MISO(PA2) and SCK(PA3).

TWI - Two Wire Interface (12C): SDA(PA1) and SCL(PA2).

Programming the ATtiny

Ólöf programmed the ATtiny in Pre-Fab. You can read more about it here and here below is how it went:

Andri Sæmundsson made a series of videos for Fab Lab Reykjavík, where he explaines all the steps in producing a circuit board with ATtiny412. I followed his directions and here I describe how I programmed the ATtiny412.

Programming the ATtiny412 - video

Here Andri Sæmundsson explaines how to program ATtiny 412 - video.

In the Arduino IDE app I clicked on Tools, Board and then Board manager. Then I wrote megatinycore in the upper left window and chose Install. Then I clicked on Tools, Board and then megaTinyCore and then ATtiny412. After that I clicked on Tools, Programmer and then SerialUPDI SLOW: 57600 baud.

I used C++ in the Arduino IDE app. I created a new sketch. According to the pinout datasheet for ATtiny412 and the PCB board design the LED is on pin 4 and the button is on pin 0. Therefore I began by defining that the LED was on pin 4 and the button on pin 0 in Arduino by writing #define LED 4 and in the next line below #define BUTTON 0. When // is added in front of text, the computer ignores it. That way you can use text to explain what is going to happen in each step.

Here you can see how I followed the instructions from Andri (added some explanations myself) and wrote this code:

//Defining which pin to use for LED and button
    #define LED 4
    #define BUTTON 0

    //Variable to keep track of how many button presses
    uint8_t buttonPresses = 0;

    //Defining what is input and what is output or input and pullup

    void setup() { 
        pinMode(LED, OUTPUT);
        pinMode(BUTTON, INPUT_PULLUP);
    }

    //Creating a loop that follows a pattern and then repeats itself
    void loop() { 
      //Defining what happens if button is pressed  
      if (digitalRead(BUTTON) == HIGH) {  
        //Increment buttonPresses
        buttonPresses++;

    //If buttonPresses is greater than 4, reset it to 0
    if (buttonPresses > 4) {
      buttonPresses = 0; 
    }

    // Blink LED based on buttonPresses count
    for (uint8_t i = 0; 1 <buttonPresses; i++) {
      digitalWrite(LED, HIGH);
      delay(200);
      digitalWrite(LED, LOW);
      delay(200);
    }  

    // Wait for button to be released
       while (digitalRead(BUTTON) == HIGH) {
       } 
     }  
    }

Arduino IDE interface

Here you can see what the Arduino IDE interface looks like. When you've written the code, you click on the checkmark on the left to compile the code. You have to make sure that you choose the right port. Then you click on the arrow to upload the code.

Arduino IDE interface

To connect the board to a computer I needed a serial UPDi-3 pin, and Svavar Konráðsson told us that it was designed by prof. Neil Gershenfeld. I also needed a FTDI cord (USB to TTL Serial Cable) to make a connection from the pins on the board to USB on the computer.

By clicking on Tools and Port I could see a list of ports. Then I connected the cord to the computer and checked out which port had beed added to this list. That was the port that I wanted to use, so I clicked on it.

I clicked on Sketch and Upload using programmer. Everything worked except that the LED blinked constantly, as can be seen in the video below. The code was obviously not correct.

Video of ATtiny - mistake in code

Constant blinking - ATtiny412

Þórarinn Bjartur Breiðfjörð advised me to change the time of the delay from 200 to 2000. That way it was easier to see how the LED was behaving. Then I took a better look at the code and saw that in one place I had written the number 1 instead of the letter i. I fixed that and then everything worked as it should.

This is the new code that I fixed:

 //Defining which pin to use for LED and button
    #define LED 4
    #define BUTTON 0

    //Variable to keep track of how many button presses
    uint8_t buttonPresses = 0;

    //Defining what is input and what is output or input and pullup

    void setup() { 
        pinMode(LED, OUTPUT);
        pinMode(BUTTON, INPUT_PULLUP);
    }

    //Creating a loop that follows a pattern and then repeats itself
    void loop() { 
      //Defining what happens if button is pressed  
      if (digitalRead(BUTTON) == HIGH) {  
      // Increment buttonPresses
        buttonPresses++;

    //If buttonPresses is greater than 4, reset it to 0
    if (buttonPresses > 4) {
      buttonPresses = 0; 
    }

    // Blink LED based on buttonPresses count
    for (uint8_t i = 0; i < buttonPresses; i++) {
      digitalWrite(LED, HIGH);
      delay(200);
      digitalWrite(LED, LOW);
      delay(200);
  }  

    // Wait for button to be released
       while (digitalRead(BUTTON) == HIGH) {
       } 
     }  
  }

Video of ATtiny blinking a LED

ATtiny412

ESP32-S3

The ESP32-S3 is a modern microcontroller by Espressif with a dual-core 32 bit processor running at 240 MHz. It includes connectivity via Wifi and Bluetooth (including BLE) and has 512 kB SRAM memory. There are 45 GPIO pins on the chip and many different peripherals are supported including UART, SPI, PWM, ADC, PulseCounter, Touch Sensor and LCD/Camera Interface.

The supply voltage used by the chip is 3,3 V and it supports four different power modes for energy-saving applications.

It has two ULP coprocessors (RISC-V and FSM) and one of them can be active during sleep mode at a time.

The current draw in deep-sleep can be as low as 7 µA.

The programming can be done via the USB-Port, so there is no other hardware required.

Datasheet and Pinout

Here is a link to the ESP32-S3 Datasheet and below is a diagram showing the pinout of the chip.

ESP32-S3 Pinout

Programming

For testing programming the ESP32-S3 we got a development board from Waveshare. It connects via USB-C to the computer.

We demonstrate two ways of programming the ESP32-S3. One is using the C++ and VSCode and the other is using Micropython and Thonny.

Below is a simple visualization of two possible toolchains (but there are of course many more).

ESP32-S3 toolchain

C++ / VSCode

For VSCode (and also Arduino IDE) there is a good tutorial on the Waveshare website.

In VSCode you need to install the ESD-IDF extension. Then you can create a new project and choose an example program or template if you like.

ESP-IDF new project

It didn't work in the first place, because we added the example project into the GIT repository of this site. That seemed to create some conflicts, so when trying again in another location of the c-drive it worked without any issues.

We selected the hello-world example, but before being able to compile the program and send it to the microcontroller some configurations needed to be made.

Note

Select UART as Flash Method, the appropriate COM-Port (COM11 in our case) and the right chip type, before clicking on Build, Flash and Monitor.

The example is written in C++ and is located in the main folder of the project named hello_world_main.c.

VSCode ESP32 Hello world

As you can see in the terminal the microcontroller sends a "Hello world!" and identifies itself, before counting to 10 s and restarting the program.

The example code looks like this:

hello_world_main.c
/*
 * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: CC0-1.0
 */

#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"

void app_main(void)
{
    printf("Hello world!\n");

    /* Print chip information */
    esp_chip_info_t chip_info;
    uint32_t flash_size;
    esp_chip_info(&chip_info);
    printf("This is %s chip with %d CPU core(s), %s%s%s%s, ",
           CONFIG_IDF_TARGET,
           chip_info.cores,
           (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "",
           (chip_info.features & CHIP_FEATURE_BT) ? "BT" : "",
           (chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "",
           (chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : "");

    unsigned major_rev = chip_info.revision / 100;
    unsigned minor_rev = chip_info.revision % 100;
    printf("silicon revision v%d.%d, ", major_rev, minor_rev);
    if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {
        printf("Get flash size failed");
        return;
    }

    printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024),
           (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");

    printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size());

    for (int i = 10; i >= 0; i--) {
        printf("Restarting in %d seconds...\n", i);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    printf("Restarting now.\n");
    fflush(stdout);
    esp_restart();
}

Micropython / Thonny

For using Micropython, the Thonny application was recommended.

We found a good tutorial on how to programm the ESP32 with Thonny.

First you install Thonny.

Then you need to install the correct firmware on the ESP32-S3 to enable it to understand Micropython, which can be downloaded here as a *.bin file.

Select and install the firmware using Options - Interpreter in Thonny.

Thonny firmware

Thonny firmware

This takes some minutes to finish, but once done, you should be able to talk to the ESP32-S3 with Micropython.

Let's try sending help() in the Shell. It works!

Thonny Shell help

Now let's make the onboard LED blink. But how to address the RGB LED? It's not just a simple Pin.OUT.

We found this site explaining the NeoPixel module in Micropython and adapted the code to make a loop and have the LED blink.

Also we know, that the RGB LED is connected to GPIO 38. To make a loop with a 0,5 s delay, we then also need to import the time library.

rgb_led.py
from machine import Pin
import time
from neopixel import NeoPixel

pin = Pin(38, Pin.OUT)      # set GPIO38 to output to drive NeoPixels
np = NeoPixel(pin, 1)       # create NeoPixel driver on GPIO38 for 1 LED/pixel

for i in range(60):
    np[0] = (255, 255, 255) # set the LED to white
    np.write()              # write data to LED
    time.sleep(0.5)
    np[0] = (0, 0, 0)       # set the LED to off
    np.write()              # write data to LED
    time.sleep(0.5)    

That works as well!

Raspberry Pi Pico

Information and pinout datasheet for Raspberry Pi Pico here.

Datasheet for Raspberry Pi Pico here.

Datasheet for RP2040 here.

RP2040pinout

RaspberryPiPicoPinout

One of the tasks was to get a program physically into the microcontroller and I was able to do that using the Raspberry Pi Pico. I connected it to my computer using a USB A port connected to USB C on the Raspberry Pi Pico.
was able to turn on the built in LED by using the following program that I found here

from machine import Pin

led = Pin("LED", Pin.OUT)
led.on()
This turns the LED on. I then modified the program to turn it on, leave it on for 5 seconds and then turn it off.

from machine import Pin import time

led = Pin("LED", Pin.OUT)
led.on()
time.sleep(5)
led.off()

ATmega328P

The Arduino Uno board is no longer in Fab Lab Inventory, but this board can be helpful when trying things out. That is why we added ATmega328P and the Arduino Uno board to this comparison. Here are some basic information on the Arduino Uno board. The Arduino Uno board is based on the ATmega328P microcontroller with 6 analog inputs and 14 digital input/output pins. Amongst those pins are 6 pins that can be used as PWM outputs. It can be connected to a computer through a USB A/B cable.

Datasheet and pinout for ATmega328P

Datasheet and pinout for ATmega328P here. The screenshot below is from the datasheet.

ATmega328P pinout

Datasheet and pinout for Arduino Uno

Information and pinout datasheet for Arduino Uno here. The screenshot below is from the datasheet.

ArduinoUnoPinout

Programming the Arduino Uno board

Switching between boards

Here The Arduino IDE was used to program the Arduino Uno board the same way that the ATtiny412 was programmed. When switching between microcontrollers you have to change the settings in Arduino IDE by choosing Tools, Board and then click on the Arduino Uno.

Changing Board

The same code was used as was used to program the ATtiny412:

 //Defining which pin to use for LED and button
    #define LED 4
    #define BUTTON 0

    //Variable to keep track of how many button presses
    uint8_t buttonPresses = 0;

    //Defining what is input and what is output or input and pullup

    void setup() { 
        pinMode(LED, OUTPUT);
        pinMode(BUTTON, INPUT_PULLUP);
    }

    //Creating a loop that follows a pattern and then repeats itself
    void loop() { 
      //Defining what happens if button is pressed  
      if (digitalRead(BUTTON) == HIGH) {  
      // Increment buttonPresses
        buttonPresses++;

    //If buttonPresses is greater than 4, reset it to 0
    if (buttonPresses > 4) {
      buttonPresses = 0; 
    }

    // Blink LED based on buttonPresses count
    for (uint8_t i = 0; i < buttonPresses; i++) {
      digitalWrite(LED, HIGH);
      delay(200);
      digitalWrite(LED, LOW);
      delay(200);
  }  

    // Wait for button to be released
       while (digitalRead(BUTTON) == HIGH) {
       } 
     }  
  }

Arduino Uno/Arduino IDE - video

ATmega328P-Arduino Uno with Arduino IDE

Arduino Uno/VSCode/PlatformIO

We wanted to try more toolchains. Jeffery Naranjo used the PlatformIO extension in Visual Studio Code to program an Arduino Uno. This tutorial on the Digikey site explains the first steps in using the PlatformIO. This site is also a good guide. To be quite sure how everything worked, this video was also used as a step by step guidance. In the video all steps are explained, from installing Visual Studio Code, installing Python and installing the PlatformIO extension. Since both VS Code and Python were installed, I jumped over these steps.

Under extensions in Visual Studio Code the PlatformIO extension was chosen and installed. This took a few minutes.

Installing Platformio

Note

When you click on the device button you can see the devices and the port they are connected to.

Devices and ports

Note

When you create a new project or update an older project, you give it a name and choose the right board.

New project

Note

When you begin working on a sketch you click on Libraries, src (source directory) and then click on the file main.cpp. This is the file you edit to create a sketch. The PlatformIO uses the .cpp ending and it stands for C++.

Main

VSCode/PlatformIO - video

ATmega328P-Arduino Uno with Platformio in Visual Studio Code

Two toolchains for Arduino Uno

After using two different platforms to program the Arduino Uno it was possible to compare these two. I (Ólöf) found it difficult to understand exactly what to define as a part of a toolchain. Þórarinn Bjartur Breiðfjörð pointed out this video that expains Toolchains in Arduino. It helped me to understand and I decided to make this flowchart with explanations, based on this video.

Finding the toolchain in PlatformIO

It was not easy to find information about the toolchain in PlatformIO. I googled "how can you see which compiler is used in platformio" and found this answer. As you can see, the information should be defined like this:

How to find Toolchain

Note

I began searching by clicking every file that I could see, but did not find what I was looking for. It was frustrating so I took a break. Then I searched again and I noticed how the window did not always show the whole text. I used the bar under the window in a json file to scroll to the right and found it!

Toolchain found

Note

You can see that it uses the AVR-GCC compiler, just as the Arduino IDE does. After GCC in the line you can see AVR, so it uses the AVR Downloader/Uploader. Then it uses the bootloader that is already pre-installed as a program in the Arduino Uno. To my surprise, the toolchains were the same, except for the platform where you create your code. I used this this video that expains Toolchains in Arduino as a guidance when I created this flowchart. The flowchart was made in Canva.

Two Toolchains

Comparison of the microcontrollers used

We saw the group project site at FabLab Reykjavík here and got inspired to make a comparison table for the different microcontrollers.

ATtiny412 RP 2040 ATmega328P ESP32-S3
Price $ 0,58 $ 14 $ 2,89 $ 1,85
Architecture/Family Harvard, AVR® RISC Harvard ARM Harvard, AVR® RISC Harvard, ULP-RISC-V, ULP-FSM
Physical Size 5 mm x 6 mm 21 mm x 51 mm x 3,9 mm 7 mm x 7 mm 7 mm x 7 mm
Operating Voltage 1,8 V ~ 5,5 V 1,8 V - 5,5 V 2,7 V ~ 5,5 V 3,3 V
Word size 8 bit 32 bit 8 bit 32 bit
Clock speed 16 and 20 MHz 133 MHz 16 MHz 240 MHz
Number of Processor cores 1 2 1 2
Flash memory 4 kB 2 MB 32 kB external
RAM 256 B 264 kB 2048 B 512 kB
No of digital Pins 7 40 20 45 physical, uses multiplexer
No of analog Pins 6 3 6 20 ADC channels
Peripherals Brown-out Detect/Reset, POR, WDT USB, UART, I2C, SPI,PWM,Timer, Watchdog,RTC, ADMa and Temp Sensor, SSI Brown-out Detect/Reset, POR, PWM, WDT ADC, RTC, GPT, I2C, I2S, LCD, LEDC, MCPWM, PCNT, RMT, SD, SPI, Temp Sensor, Touch Sensor, TWAI, UART, USB
Connectivity I2C, IrDA, LINbus, SPI, UART/USART Wifi, Bluetooth, BLE, UART, USB
Programming languages C,C++, Assembly C/C++/Micropython, Assembly, Rust C,C++, Assembly C/C++, Micropython, Lua, ...