Skip to content

4.Embedded Programming

Group Assignment: Embedded Programming

Simulation with TinkerCAD and Arduino UNO

Before touching any hardware, we started with a simulation. TinkerCAD lets you wire up virtual components and run code without risking anything, so it made sense to begin there.

We set up an Arduino UNO with a 4-pixel NeoPixel strip. The goal was simple: make each LED show a different color.

The code is based on the Adafruit NeoPixel library examples, adapted for our 4-pixel setup. In setup() we initialize the strip and turn everything off. In loop() we go through each pixel with a for loop and use a switch/case to assign a different color to each one — blue, green, red, yellow.

#include <Adafruit_NeoPixel.h>

#define PIN        4
#define NUMPIXELS  4

Adafruit_NeoPixel strip(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.begin();
  strip.show();
  strip.setBrightness(50);
}

void loop() {
  for(int i=0; i<NUMPIXELS; i++) {
    switch(i) {
      case 0: strip.setPixelColor(i, strip.Color(0, 0, 255)); break;
      case 1: strip.setPixelColor(i, strip.Color(0, 255, 0)); break;
      case 2: strip.setPixelColor(i, strip.Color(255, 0, 0)); break;
      case 3: strip.setPixelColor(i, strip.Color(255, 255, 0)); break;
    }
  }
  strip.show();
  delay(100);
}

This exercise helped us understand the two main building blocks of an Arduino program: setup() runs once at startup, loop() runs forever. Everything lives inside those two functions.


Programming the XIAO RP2040

Next we moved to real hardware — the Seeed Studio XIAO RP2040, a small but capable board with a built-in RGB LED.

First we installed Arduino IDE and added the RP2040 board library through the Board Manager.

The onboard LED is on pin 12, with a separate power enable pin on pin 11. You have to pull that pin HIGH or the LED doesn’t turn on at all — something worth knowing.

The program cycles through red, green, and blue with 500ms delays between each color. Nothing complicated, but it confirmed the board and toolchain were set up correctly.

#include <Adafruit_NeoPixel.h>

#define PIN_RGB    12
#define PIN_POWER  11
#define NUMPIXELS  1

Adafruit_NeoPixel pixels(NUMPIXELS, PIN_RGB, NEO_GRB + NEO_KHZ800);

void setup() {
  pinMode(PIN_POWER, OUTPUT);
  digitalWrite(PIN_POWER, HIGH);
  pixels.begin();
}

void loop() {
  pixels.clear();

  pixels.setPixelColor(0, pixels.Color(255, 0, 0));
  pixels.show();
  delay(500);

  pixels.setPixelColor(0, pixels.Color(0, 255, 0));
  pixels.show();
  delay(500);

  pixels.setPixelColor(0, pixels.Color(0, 0, 255));
  pixels.show();
  delay(500);
}

STM32F3DISCOVERY Board

The third platform was the STM32F3DISCOVERY. This one has a steeper setup curve than Arduino, but the workflow is more representative of professional embedded development.

Generating code with STM32CubeMX

STM32CubeMX is a graphical tool that generates initialization code and HAL (Hardware Abstraction Layer) files based on your board configuration. You pick your board, set your peripherals, choose a project type (we used CMake), and it generates the skeleton project.

Setting up VS Code

We used VS Code as the editor and compiler. On Linux, you need a few packages first:

sudo apt update
sudo apt install -y gcc-arm-none-eabi openocd make cmake ninja-build

Then we installed the STM32CubeIDE extension pack in VS Code. It picks up the generated project structure automatically. The Cortex-Debug extension adds real-time debugging.

Write your code in main.c, hit run — that’s it.


Summary

Three boards, three different toolchains. TinkerCAD and Arduino are the easiest starting point. The XIAO RP2040 works almost identically in Arduino IDE. STM32 takes more setup but gives you more control and a workflow that’s closer to what’s used in industry.

Group Assignment link

Tools

  • Arduino IDE
  • Seeed Studio XIAO RP2040
  • USB cable
  • Computer

Individual Assignment

During the group work, we explored different microcontrollers and their capabilities. I chose the Seeed Studio XIAO RP2040 because of its compact size and compatibility with Arduino IDE.

I selected the XIAO RP2040 because it is small, easy to use, and suitable for future project integration.

  • Downloaded and installed Arduino IDE.
  • Opened the Seeed Studio website.
  • Copied the board manager URL.

  • Added the URL into Arduino IDE preferences.

  • Installed the XIAO RP2040 board package.

  • Connected the XIAO RP2040 to the computer.
  • Selected the correct board from the menu.

  • Selected the COM port.

Before making connections, I reviewed the RP2040 pinout diagram to better understand the pin functions and avoid incorrect wiring.


RP2040 Datasheet

Datasheet Before writing any code, I opened the official RP2040 datasheet to understand what the chip actually contains.

The RP2040 is a dual-core ARM Cortex-M0+ microcontroller made by Raspberry Pi. The name itself is informative: RP stands for Raspberry Pi, 2 means two processor cores, 0 refers to the Cortex-M0+ processor type, and 40 is the number of logical pins.

Key specs from the datasheet:

Feature Value
Processor Dual-core ARM Cortex-M0+
Clock speed Up to 133 MHz
SRAM 264 kB (split into 6 banks)
Flash External only, via QSPI interface
GPIO 30 pins (multifunction)
ADC 12-bit, 4 external inputs + 1 internal temperature sensor
Communication 2× UART, 2× SPI, 2× I2C, USB 1.1
PWM 16 channels
Special 2× PIO blocks, 8 state machines total

A few things stood out when reading it.

The RP2040 has no internal flash memory. The program lives on an external chip and is loaded over a QSPI interface. On the XIAO RP2040 board, that flash is already soldered on, so you don’t notice it during use — but the datasheet makes it clear this is separate hardware from the chip itself.

The GPIO pins on the XIAO RP2040 require a power enable pin to activate certain hardware, including the onboard RGB LED. In the datasheet, this is described as a controlled power rail to the LED circuit. In practice, pin 11 (PIN_POWER) must be pulled HIGH before the LED responds at all. I ran into this directly — the LED simply didn’t light up until I added digitalWrite(PIN_POWER, HIGH) to setup(). Without the datasheet, that would have been very hard to debug.

pinMode(PIN_POWER, OUTPUT);
digitalWrite(PIN_POWER, HIGH);  // required — without this, the RGB LED won't turn on

The ADC is 12-bit, meaning it divides the 0–3.3V input range into 4096 discrete steps. This is directly relevant to my final project, where I need to read analog output from a CO₂ sensor. Understanding the ADC resolution from the datasheet helps me know how precisely I can measure the sensor voltage.

The PIO (Programmable I/O) system was something I hadn’t seen before. It’s a mini-processor inside the chip that handles timing-critical communication independently from the main cores. The Adafruit NeoPixel library uses PIO under the hood to generate the precise signal timing that WS2812 LEDs require — which is why the library works so reliably on this board.

The chip also supports Serial Wire Debug (SWD), which allows stepping through code and inspecting memory directly on the hardware. Useful to know for future debugging beyond what the Serial Monitor can show.


Programming

After studying the RP2040 pinout and datasheet, I created a simple program to test input reading from pin D0.

The code initializes serial communication and sets pin D0 as an input.
The program continuously reads the digital state of the pin and prints “CLOSED” or “OPEN” in the Serial Monitor depending on the input signal.

  • Serial.begin(9600) initializes serial communication
  • pinMode(D0, INPUT) sets pin D0 as input
  • digitalRead(D0) reads the pin state
  • Serial.println outputs the result

Code

void setup() {
  pinMode(D0, INPUT);
  Serial.begin(9600);
}

void loop() {
  if (digitalRead(D0) == HIGH) {
    Serial.println("CLOSED");
  } else {
    Serial.println("OPEN");
  }
}

Code Screenshot

Arduino Code


Serial Output

OPEN
CLOSED
OPEN

This test helped me understand how to read digital input signals and verify hardware connections. The Serial Monitor acts as a wired communication channel between the board and the computer — the microcontroller sends data over USB Serial using the UART protocol, and Arduino IDE receives it in real time. This is the same UART interface listed in the RP2040 datasheet under communication peripherals.


Hero Shot

The XIAO RP2040 running the input reading program, with the Serial Monitor showing live output.

Hero Shot


Functions and Variables (Additional Learning)

During this week, I also explored basic programming concepts such as functions and variables in Arduino.

Example Code

#define pin1 17

int distSens = 17;
float var2 = 17.444;
String var3 = "hello Gyumri";
bool var4 = true;

const int var5 = 68;

void myFunc() {
  digitalWrite(pin1, HIGH);
  delay(500);
  digitalWrite(pin1, LOW);
  delay(500);
}

void setup() {
  pinMode(pin1, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  myFunc();
}

Key Concepts

  • Function → reusable block of code
  • Variables → store data
  • setup() → runs once
  • loop() → runs continuously

Common Mistakes

#defint pin1 14      // incorrect
char var3 = "text";  // incorrect
bool var4 = tru;     // incorrect

Correct version:

#define pin1 14
String var3 = "text";
bool var4 = true;