Grace Schwan Silva
  • Home (current)
  • Student Agreement
  • About me
  • Final Project
  • Assignments
    Week1:Principles and Practices, Project Management Week2:Computer-Aided Design Week3:Computer Controlled cutting Week4:Embedded programming Week5:3D Scanning and Printing Week6:Electronics Design Week7:Computer Controlled Machining Week8:Electronics Production Week9:Input Devices Week10:Output Devices Week11:Networking and Communications Week12:Mechanical Design, Machine Design Week13:Molding and Casting Week14:Interfaces and Applications Programming Week15:Interface and Application Programming Week16:System Sntegration Week17:Wildcard Week Week18:Applications and Implications, Project Development Week19: invention, intellectual property, and income final project presentations
← Week 3 Week 5 →

WEEK 4

EMBEDDED PROGRAMMING

Assignment :

Group assignment:

- Demonstrate and compare the toolchains and development workflows for available embedded architectures.

Individual assignment:

- Browse through the data sheet for a microcontroller

- Write and test a program for an embedded system using a microcontroller to interact (with local input &/or output devices) and communicate (with remote wired or wireless connections)

* extra credit: try different languages &/or development environments

Group assignment:

During Week 4 (Embedded Programming), my teammate Carmen and the team organized ourselves to demonstrate and compare toolchains and development workflows across different microcontroller families. To divide the work, each member focused on one microcontroller. In my case, I documented the RP2040, and then shared my findings so we could compare them with the other architectures selected by the group.

Compare performance and development workflows for other architectures

1) Comparing other architectures

For this comparison we used four different families (XIAO form factor + one “minimal” ARM option):

  • RP2040 (ARM Cortex-M0+ dual-core, 32-bit)
  • ESP32-C3 (RISC-V, 32-bit, Wi-Fi/BLE)
  • ESP32-S3 (Xtensa LX7 dual-core, 32-bit, Wi-Fi/BLE)
  • ATSAMD11 (sometimes written “ATAMD11”) (ARM Cortex-M0+, 32-bit)

Quick comparison of performance and capabilities (hardware)

MCU/Board CPU / Architecture Max clock Memory (board/chip) Connectivity Typical use
RP2040 Dual-core ARM Cortex-M0+ 133 MHz 264 KB SRAM + 2 MB Flash No wireless Local control, PWM/ADC/PIO, fast prototyping
ESP32-C3 RISC-V 32-bit (single-core) 160 MHz 400 KB SRAM + 4 MB Flash Wi-Fi + BLE 5 Basic IoT, connectivity, low cost
ESP32-S3 Xtensa LX7 dual-core 32-bit 240 MHz 8 MB PSRAM + 8 MB Flash Wi-Fi + BLE 5 IoT + heavier apps / light edge-AI
ATSAMD11 ARM Cortex-M0+ 32-bit 48 MHz 16 KB Flash + 4 KB SRAM No wireless Minimalist, USB device, simple control, low power

Toolchains and workflow comparison

MCU/Board Common toolchains How it’s programmed (typical workflow) Evidence to show
RP2040 Arduino / MicroPython / CircuitPython USB upload (UF2/IDE) + Serial Monitor/REPL Upload screenshot + Serial logs + LED/button demo
ESP32-C3 Arduino / MicroPython / (optional ESP-IDF) Flash via USB-serial (ROM bootloader) + serial monitor Flash logs + Wi-Fi/BLE connection + remote demo
ESP32-S3 Arduino / MicroPython / (optional ESP-IDF) Flash via USB + monitor; ideal for Wi-Fi/BLE demos and larger apps Logs + Wi-Fi/BLE demo + power modes/consumption (if applicable)
ATSAMD11 gcc-arm / Microchip Studio + OpenOCD/EDBG/Atmel-ICE (SWD) Build (ARM GCC) → program/debug via SWD Terminal/IDE commands screenshot + programmer photo + USB/Serial output

2. Analyze specifications and features:

This week we compared four microcontrollers/boards: RP2040, ESP32-C3, ESP32-S3, and ATSAMD11. The main differences between them are processing power, memory, connectivity, and the programming workflow they typically use.

Performance and development workflows (MCU comparison)

Feature RP2040 ESP32-C3 ESP32-S3 ATSAMD11 Quick takeaways
Architecture / CPU ARM Cortex-M0+ (dual-core) RISC-V 32-bit (single-core) Xtensa LX7 (dual-core) ARM Cortex-M0+ (single-core) Raw compute: ESP32-S3 > RP2040 > ESP32-C3 > SAMD11
Word size 32-bit 32-bit 32-bit 32-bit All are 32-bit (more capable than typical 8-bit MCUs)
Max clock Up to 133 MHz Up to 160 MHz Up to 240 MHz Up to 48 MHz S3 is fastest; SAMD11 is the most basic
Flash memory 2 MB (on board) 4 MB (on board) 8 MB (on board) 16 KB (on chip, typical) S3/C3 fit larger apps; SAMD11 requires tiny firmware
SRAM 264 KB (on chip) ~400 KB (on chip) SRAM + (external PSRAM) 4 KB (on chip, typical) S3 stands out for total memory; SAMD11 is very limited
Extra memory — — 8 MB PSRAM (on board) — S3 PSRAM helps with buffers, large libraries, and data
Connectivity No Wi-Fi/BLE (needs external module) Wi-Fi 2.4 GHz + BLE 5 Wi-Fi 2.4 GHz + BLE 5 No Wi-Fi/BLE For wireless communication: ESP32 (C3/S3)
Programming / Debug USB (UF2 bootloader), SWD pads USB/Serial (boot), JTAG/debug depends on board USB/Serial (boot), JTAG/debug depends on board SWD (Atmel-ICE/EDBG), bootloader depends on design SAMD11 is ideal to show SWD; RP2040 is very straightforward via USB
Common toolchains Arduino, MicroPython, CircuitPython Arduino, MicroPython, ESP-IDF Arduino, MicroPython, ESP-IDF Microchip Studio, ARM GCC, OpenOCD ESP-IDF shows a more “professional” flow (build/flash/monitor)
Typical workflow (summary) Plug in → upload sketch/UF2 → Serial/REPL Select port → flash → monitor → (Wi-Fi/BLE) Select port → flash → monitor → (Wi-Fi/BLE + more libs) Build → flash via SWD → debug Show at least 2 workflows (e.g., RP2040 USB vs SAMD11 SWD or ESP-IDF)
Best for… Local control, fast prototyping, PWM/ADC Simple IoT with Wi-Fi/BLE Advanced IoT, more memory, heavier apps Minimal projects, USB device, bare-metal Pick based on your demo goals (local vs wireless vs low-level)

Simple explanation of each board

  • RP2040 is well balanced: it has dual-core, good speed (up to 133 MHz), and enough memory (264 KB SRAM + 2 MB Flash) for medium projects. It’s ideal for local control (LEDs, buttons, sensors, PWM, ADC) and quick development with Arduino or MicroPython.
  • ESP32-C3 is a good option when you need wireless connectivity, since it includes Wi-Fi and Bluetooth (BLE). It is strong enough for basic IoT, and its main advantage is connecting to a network or a phone. The workflow usually includes network setup (Wi-Fi credentials or BLE services).
  • ESP32-S3 is the most powerful: higher speed and much more memory available on the board (large Flash + PSRAM). This helps when you need heavier tasks, larger libraries, or advanced features, while still keeping Wi-Fi/BLE.
  • ATSAMD11 is the most basic and limited in resources (lower speed and memory). However, it is very useful for learning because it pushes you to write efficient firmware and it is often programmed with a more “technical” workflow using ARM tools and SWD debugging. It’s a good option to demonstrate a workflow different from “just upload via USB”.

Group assignment conclusion

In this group assignment we compared, through real practice, how these microcontrollers are programmed and how capable they are: XIAO RP2040, XIAO ESP32-C3, XIAO ESP32-S3, and ATSAMD11. We learned that it’s not only about how powerful a chip is, but also how easy it is to program, what tools it uses, and how fast you can test changes.

In general, we found that:

  • RP2040 is very comfortable for fast testing and local control (button/LED/sensors).
  • ESP32 (C3/S3) is better when you need Wi-Fi or Bluetooth for IoT projects.
  • SAMD11 helps you understand a more “technical” low-level workflow and debugging, although it has less memory and power.

In summary, teamwork helped us compare tools and workflows and choose the right microcontroller depending on the project requirements.

Group Work (Grace & Carmencita)

Carmencita and I worked together on the group assignment, testing and comparing two embedded development workflows using real hardware (XIAO RP2040 and XIAO ESP32-C3). We documented our process, troubleshooting, and results as a team.

For more details, please visit our group documentation:

🔗 View Group Documentation

Carmencita’s Week 4 documentation: View Carmencita’s page

Individual assignment

Explore the datasheet for the RP2040 microcontroller

RP2040 microcontroller

I chose to study the microcontroller RP2040 because it combines an ultra-compact form factor with good performance for prototyping and embedded systems. It is ideal for portable projects and for testing different programming environments (Arduino/MicroPython/CircuitPython).

🔹 RP2040 Microcontroller Features

General Information

  • Manufacturer: Raspberry Pi
  • Model: RP2040
  • Architecture: Dual-core ARM Cortex-M0+ (32-bit)
  • Maximum clock frequency: Up to 133 MHz

Memory

  • Internal SRAM: 264 KB
  • Internal Flash: ❌ None
  • External memory support: QSPI interface for external Flash (required to store the program)

GPIO (Input/Output)

  • Up to 30 multifunction GPIO pins
  • Logic level: 3.3 V
  • Configurable as digital input or output
  • Interrupt support

Analog-to-Digital Conversion

  • 12-bit ADC
  • 5 ADC channels:
    • 4 external analog inputs
    • 1 internal temperature sensor

Communication

  • 2 × UART
  • 2 × I2C
  • 2 × SPI
  • USB 1.1 controller (Device or Host with external PHY)

PWM

  • 8 PWM slices
  • 16 PWM channels total

DMA

  • 12 DMA channels for direct memory transfers

Timers

  • Hardware timers
  • Watchdog timer

Special Feature — PIO (Programmable I/O)

  • 2 PIO blocks
  • 4 state machines per block (8 total)
  • Enables custom hardware protocols (e.g., WS2812, proprietary protocols, special signals)

Electrical Characteristics

  • Core voltage: 1.1 V (internally regulated)
  • I/O voltage: 3.3 V
  • Not 5 V tolerant on GPIO pins
  • Low power consumption

Package

  • QFN-56 (56-pin package)

Hardware precautions (important)

  • 3.3 V GPIO: do not apply signals above 3.3 V to the I/O pins to avoid damage.
  • Power supply: it can be powered with 5 V through power pins (regulated internally to 3.3 V).
  • Battery + USB-C: avoid connecting USB-C while a battery is connected (safety risk).

Pin map (useful functional summary)

  • Analog (ADC): D0=P26, D1=P27, D2=P28, D3=P29.
  • I2C: D4=SDA (P6), D5=SCL (P7).
  • UART: D6=TX (P0), D7=RX (P1).
  • SPI: D8=SCK (P2), D9=MISO (P4), D10=MOSI (P3).
  • Control: BOOT (bootloader mode) and RESET (restart).

Bootloader and port recovery (when it “disappears”)

  1. Hold the BOOT (B) button.
  2. Connect the RP2040 to the computer.
  3. The device appears as a drive (bootloader mode) and the programming port becomes available again.

Note about the onboard LED

  • The onboard RGB LED behavior can be inverted compared to Arduino (in some cases it turns on with LOW).

Learnings - Exploring the XIAO RP2040 datasheet

  • I learned how to quickly extract “what matters” from a datasheet: CPU architecture, clock, memory, voltage levels, and available peripherals (ADC, PWM, UART, I2C, SPI). This helped me decide what the board can realistically do for my demo.
  • I understood why the 3.3 V logic level is critical. Even if the board can be powered with 5 V (because it regulates internally), the GPIO pins still operate at 3.3 V, so applying higher voltage to inputs can damage the microcontroller.
  • I learned to read a pin mapping not only by board labels (D0, D1, etc.) but also by the MCU pin names (P26, P27…). This is important when using different libraries or when debugging wiring mistakes.
  • I clarified the difference between power pins vs. signal pins: power can enter through specific pins (with internal regulation), but signals must respect the logic voltage. This avoids common beginner errors when connecting sensors or modules.
  • I discovered how the BOOT/RESET workflow works on RP2040 boards. If the programming port “disappears” after a failed upload, holding BOOT while connecting forces bootloader mode, and the board shows up again as a storage device (UF2), making recovery easy.
  • I learned that the onboard RGB LED behavior can be inverted compared to Arduino expectations (sometimes LOW turns it on). This is important when testing “blink” or status indicators, so I don’t misinterpret results.
  • I realized the RP2040 is a very good choice for fast prototyping because it supports multiple environments (Arduino/MicroPython/CircuitPython). This lets me test the same hardware with different toolchains and compare workflows.

Individual assignment — Programming RP2040

Programming process (simple)

  • Software: I used Arduino IDE on Windows with the RP2040 board support.
  • Connection: I plugged my board into the computer using a USB-C data cable.
  • Upload steps: I entered BOOT mode (RPI-RP2) → clicked Upload in Arduino → the board restarted and ran the program.
  • Local input: a pushbutton starts the LED sequence.
  • Local output: three LEDs blink following a pattern.
  • Communication: I used the Serial Monitor to see messages and confirm the button press and cycles.

What I changed (modified code)

  • Replaced delay() with a non-blocking timing approach using millis().
  • Used INPUT_PULLUP + debounce for a more stable button reading.
  • Triggered the sequence only once per press (press-event), instead of repeating continuously.
  • Organized the LEDs using an array to keep the code cleaner and easier to scale.

Wiring (pins used)

  • LEDs: D0, D6, D7 (each LED with a resistor to GND).
  • Button: D1 connected to GND (using INPUT_PULLUP).

Source code (Arduino — modified version)

Show/hide source code — Button debounce + LED sequence (millis)

// Week 4 - XIAO RP2040
// Modified version: stable button (INPUT_PULLUP), press-event trigger, no delay (millis), LED array

const uint8_t LEDS[] = {D0, D6, D7};
const uint8_t NLEDS = sizeof(LEDS) / sizeof(LEDS[0]);

const uint8_t BUTTON_PIN = D1;          // button to GND
const unsigned long STEP_MS = 250;      // speed of the animation
const int CYCLES_TO_RUN = 7;            // how many times the pattern repeats

// Debounce
int lastReading = HIGH;
int stableState = HIGH;
unsigned long lastDebounceTime = 0;
const unsigned long DEBOUNCE_MS = 30;

// Sequence state machine
bool running = false;
int cycleCount = 0;
int stepIndex = 0;                      // 0..(2*NLEDS - 1)
unsigned long lastStepTime = 0;

void allOff() {
  for (uint8_t i = 0; i < NLEDS; i++) digitalWrite(LEDS[i], LOW);
}

void setup() {
  Serial.begin(9600);

  for (uint8_t i = 0; i < NLEDS; i++) pinMode(LEDS[i], OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP);   // more stable

  allOff();
  Serial.println("RP2040 ready. Press the button to run the LED sequence.");
}

void startSequence() {
  running = true;
  cycleCount = 0;
  stepIndex = 0;
  lastStepTime = millis();
  allOff();
  Serial.println("Button pressed -> starting sequence");
}

void updateSequence() {
  if (!running) return;

  unsigned long now = millis();
  if (now - lastStepTime < STEP_MS) return;
  lastStepTime = now;

  // Pattern: turn ON LEDs forward, then turn OFF LEDs backward
  if (stepIndex < NLEDS) {
    digitalWrite(LEDS[stepIndex], HIGH);
  } else {
    int offIdx = (2 * NLEDS - 1) - stepIndex;
    digitalWrite(LEDS[offIdx], LOW);
  }

  stepIndex++;

  // End of one full cycle
  if (stepIndex >= 2 * NLEDS) {
    stepIndex = 0;
    cycleCount++;
    Serial.print("Cycle: ");
    Serial.println(cycleCount);

    if (cycleCount >= CYCLES_TO_RUN) {
      running = false;
      allOff();
      Serial.println("Sequence finished.");
    }
  }
}

void loop() {
  // ----- Debounced button reading -----
  int reading = digitalRead(BUTTON_PIN);

  if (reading != lastReading) {
    lastDebounceTime = millis();
    lastReading = reading;
  }

  if (millis() - lastDebounceTime > DEBOUNCE_MS) {
    if (reading != stableState) {
      stableState = reading;

      // Press event (INPUT_PULLUP => pressed = LOW)
      if (stableState == LOW) {
        if (!running) startSequence();
        else Serial.println("Sequence already running...");
      }
    }
  }

  // ----- Run the LED animation without blocking -----
  updateSequence();
}

  

1) Code 1 — Debounced button + LED sequence (millis)

This program for the XIAO RP2040 uses three LEDs (D0, D6, D7) and a pushbutton (D1 to GND). The button is configured with INPUT_PULLUP and debounced to avoid false triggers. When a valid press event is detected, it starts a non-blocking LED animation using millis() (no delay()): LEDs turn ON forward and then turn OFF backward, repeating for a set number of cycles. Serial messages are printed to confirm button press, cycle count, and when the sequence finishes.

⬇️ Download Code 1 (.ino)

Credits / Acknowledgements

  • PCB / Programmer board: I used a board created by Adrian Torres called QUENTORRES. I downloaded the PCB PNG files from the official repository. Full documentation is available here: QUENTORRES documentation (Fabcloud GitLab) .
  • Code reference: I used as a starting example a sketch shared by Ronal Vilca on his Fab Academy page: Ronal Vilca — Week 6 . I then made my own variation (timing logic, button handling, and LED sequence changes) so the final code is unique and fully understood by me.

Difficulties / Challenges

  • At the beginning I got confused because the RPI-RP2 drive disappears after uploading. Later I understood this is normal: the board resets and runs the program, so it leaves BOOT mode.
  • Sometimes the board did not show a COM port in Arduino IDE. I solved it by using a real USB-C data cable (not charge-only) and reconnecting the board.
  • I had issues with the pushbutton reading: it was unstable at first. I fixed it by using INPUT_PULLUP and understanding that pressed = LOW.
  • The LED sequence was repeating too much when I kept the button pressed. I solved it by triggering the sequence only once per press (press-event logic).
  • Using delay() made the program feel “stuck” and less responsive. I changed it to millis() to make the code non-blocking.
  • I also had to double-check my wiring (pins, GND, resistors) because small mistakes easily stop the LEDs from working.

How I tested it

  1. Connected the board to my Windows PC using a USB-C data cable.
  2. In Arduino IDE, selected Seeed XIAO RP2040 and the correct COM port.
  3. Uploaded the sketch. (If needed: entered BOOT mode to restore the device and re-upload.)
  4. Opened Serial Monitor at 9600 baud to verify button press logs and cycle count.
  5. Pressed the button and confirmed the LED pattern ran once per press.

Evidence to include:

  • Hero shot: board + wiring + LEDs + button.
  • Screenshot of Arduino IDE showing successful upload.
  • Short video: press button → LEDs run sequence → serial messages.
  • Source code embedded as text (this page) or downloadable file.

Media (photos + video)

Hero shot - XIAO RP2040 setup
Hero shot — XIAO RP2040 with button and 3 LEDs.

Serial Monitor error UF2_Board

Problem:Arduino IDE upload screenshot (“Done uploading”).

Your browser does not support the video tag.

Learnings - Programming the RP2040

  • Now I understand how uploading works on the RP2040 in Windows: I enter BOOT mode (it shows up as RPI-RP2), upload from Arduino IDE, and then the drive disappears because the board resets to run the code — so that’s totally normal.
  • I got the full workflow clear: select the right board, pick the correct COM port, upload the sketch, and check everything using the Serial Monitor.
  • I learned the difference between interaction and communication: the button is my input, the LEDs are my output, and Serial is how I “see” what’s happening (wired communication to the PC).
  • I learned why INPUT_PULLUP is better: the button reading becomes stable (no random values). The only thing is the logic changes: pressed = LOW.
  • I added debounce, which basically prevents multiple triggers from a single press.
  • I replaced delay() with millis(), so my code is not “blocked” anymore. It feels more professional and easier to expand.
  • Using an array for LED pins made the code cleaner and easier to scale.
  • And most importantly: I used a reference code, but I modified it (timing, button handling, LED sequence), I gave credit, and now the final code is unique and fully understood by me.

Communication demo — Serial ( RP2040 ↔ PC)

Source Code (XIAO RP2040)

Show/hide code — Button + LED sequence + Serial commands
// XIAO RP2040 - Week 4 (Fab Academy)
// Interaction: Button starts LED sequence (input)
// Output: 3 LEDs blink in a pattern (output)
// Communication: USB Serial PC <-> XIAO (commands + logs)
//
// Pins used (change if needed):
// LEDs: D0, D6, D7
// Button: D1 to GND (INPUT_PULLUP)

const uint8_t LEDS[] = {D0, D6, D7};
const uint8_t NLEDS = sizeof(LEDS) / sizeof(LEDS[0]);
const uint8_t BUTTON_PIN = D1;          // button to GND

// Sequence parameters
bool running = false;
int cyclesToRun = 7;
int cycleCount = 0;
int stepIndex = 0;                       // 0..(2*NLEDS-1)
unsigned long lastStep = 0;
unsigned long stepMs = 250;              // animation speed

// Button debounce / press-event
int lastReading = HIGH;
int stableState = HIGH;
unsigned long lastDebounceTime = 0;
const unsigned long DEBOUNCE_MS = 30;

// ---------- helpers ----------
void allOff() {
  for (uint8_t i = 0; i < NLEDS; i++) digitalWrite(LEDS[i], LOW);
}

void allOn() {
  for (uint8_t i = 0; i < NLEDS; i++) digitalWrite(LEDS[i], HIGH);
}

// ---------- sequence ----------
void startSequence() {
  running = true;
  cycleCount = 0;
  stepIndex = 0;
  lastStep = millis();
  allOff();
  Serial.println("Button pressed -> sequence start");
}

void updateSequence() {
  if (!running) return;

  unsigned long now = millis();
  if (now - lastStep < stepMs) return;
  lastStep = now;

  // Pattern: turn ON LEDs forward, then turn OFF LEDs backward
  if (stepIndex < NLEDS) {
    digitalWrite(LEDS[stepIndex], HIGH);
  } else {
    int offIdx = (2 * NLEDS - 1) - stepIndex;
    digitalWrite(LEDS[offIdx], LOW);
  }

  stepIndex++;

  // End of one full cycle
  if (stepIndex >= 2 * NLEDS) {
    stepIndex = 0;
    cycleCount++;
    Serial.print("Cycle: ");
    Serial.println(cycleCount);

    if (cycleCount >= cyclesToRun) {
      running = false;
      allOff();
      Serial.println("Sequence finished.");
    }
  }
}

// ---------- serial commands ----------
void handleCommand(String s) {
  Serial.print("RX: ");
  Serial.println(s);

  s.trim();
  s.toLowerCase();

  if (s == "on") {
    running = false;
    allOn();
    Serial.println("OK: LEDs ON");
    return;
  }

  if (s == "off") {
    running = false;
    allOff();
    Serial.println("OK: LEDs OFF");
    return;
  }

  if (s == "start") {
    if (!running) startSequence();
    Serial.println("OK: start");
    return;
  }

  if (s == "status") {
    Serial.print("running=");
    Serial.print(running ? "true" : "false");
    Serial.print(" stepMs=");
    Serial.print(stepMs);
    Serial.print(" cyclesToRun=");
    Serial.println(cyclesToRun);
    return;
  }

  if (s.startsWith("blink ")) {
    int v = s.substring(6).toInt();
    if (v < 50) v = 50;
    stepMs = (unsigned long)v;
    Serial.print("OK: stepMs=");
    Serial.println(stepMs);
    return;
  }

  Serial.println("ERR: try: on | off | start | status | blink 300");
}

// ---------- setup / loop ----------
void setup() {
  Serial.begin(115200);
  delay(1200);

  for (uint8_t i = 0; i < NLEDS; i++) pinMode(LEDS[i], OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP);

  allOff();

  Serial.println("XIAO RP2040 ready.");
  Serial.println("Commands: on | off | start | status | blink ");
  Serial.println("Press the button to start the LED sequence.");
}

void loop() {
  int reading = digitalRead(BUTTON_PIN);

  if (reading != lastReading) {
    lastDebounceTime = millis();
    lastReading = reading;
  }

  if (millis() - lastDebounceTime > DEBOUNCE_MS) {
    if (reading != stableState) {
      stableState = reading;

      if (stableState == LOW) {
        if (!running) startSequence();
        else Serial.println("Sequence already running...");
      }
    }
  }

  if (Serial.available()) {
    String line = Serial.readStringUntil('\n');
    line.trim();
    if (line.length() > 0) handleCommand(line);
  }

  updateSequence();
}

  

2) Code 2 — Button + LED sequence + Serial Monitor commands

This program is an extended version of Code 1. It keeps the same local interaction: a debounced button (D1 to GND) triggers a non-blocking LED sequence on three LEDs (D0, D6, D7) using millis(). Additionally, it implements USB Serial communication: you can send text commands from the Serial Monitor to control the LEDs and read status. Commands include on, off, start, status, and blink <ms> to change the animation speed in real time. This demonstrates both local interaction and communication (PC ↔ board) in the same embedded system.

⬇️ Download Code 2 (.ino)

What “serial communication” means in my project

  • Wired communication via USB: the XIAO RP2040 creates a virtual COM port on Windows.
  • XIAO → PC: logs using Serial.println() (status, cycles, OK messages).
  • PC → XIAO: I send commands from Arduino Serial Monitor (example: on, off, blink 150, status).

Tools and what I needed

  • Software: Arduino IDE (Windows) + Seeed XIAO RP2040 board support
  • Hardware: my custom PCB with XIAO RP2040 + USB-C data cable

Step-by-step workflow (how I tested serial)

  1. Connected the board to my PC using a USB-C data cable.
  2. In Arduino IDE, selected Board: Seeed XIAO RP2040.
  3. Selected the correct COM port (example: COM4).
  4. Uploaded the sketch.
  5. Opened Serial Monitor and set 115200 baud (must match Serial.begin(115200)).
  6. Set line ending to New Line and typed commands to verify two-way communication.

Commands I used (PC → XIAO)

  • on → turn all LEDs ON
  • off → turn all LEDs OFF
  • blink 150 → change animation speed
  • status → print current settings

Evidence (XIAO → PC)

The board replies back in Serial Monitor with messages like: RX: on, OK: LEDs ON, and cycle counters.

Serial Monitor error UF2_Board

Problem: Serial Monitor failed because I was on UF2_Board (bootloader), not a COM port.

Serial Monitor working on COM port

Fixed: After selecting the real COM port, Serial Monitor showed RX/OK responses.

Difficulties (real mistakes + how I fixed them)

  • UF2_Board error: I tried to open Serial Monitor while the board was in UF2/boot mode.
    Fix: I selected the real COM port instead of UF2_Board.
  • No text in Serial Monitor: my baud rate didn’t match the code.
    Fix: I set 115200 in Serial Monitor to match Serial.begin(115200).
  • RPI-RP2 disk disappeared: I thought the board was broken.
    Fix: I learned it’s normal — after upload the board exits BOOT mode and runs the sketch.
  • Commands didn’t respond at first: line ending was wrong.
    Fix: I used New Line and pressed Enter to send the command properly.

Your browser does not support the video tag.

Learnings — Serial communication (RP2040 ↔ PC)

  • I learned that the RP2040 has two modes on Windows: BOOT mode (RPI-RP2 / UF2) for uploading, and normal mode (COM port) for Serial Monitor.
  • I learned that UF2_Board is not a Serial port. Serial Monitor works only with the real COM port (e.g., COM4).
  • I learned that the baud rate must match the code. If the sketch uses Serial.begin(115200), Serial Monitor must be set to 115200.
  • I learned how to prove real communication with two-way serial: PC sends commands (on, off, blink 150) and the board replies (OK: LEDs ON).
  • I learned that the line ending matters. Using New Line (or Both NL & CR) helps the board read commands correctly.
  • I learned that if Serial Monitor looks empty, pressing RESET can print the startup messages again.
  • I learned a simple troubleshooting checklist: data cable, correct port, correct baud, and correct line ending.

Conclusions

Group Conclusions (RP2040 vs ESP32-C3)

  • Programming two different microcontroller families allowed us to understand that the development workflow depends not only on the code, but also on correct environment configuration (board selection, drivers, and COM port management).
  • The ESP32-C3 required more attention to setup details, especially using GPIO numbers instead of Arduino-style D pins and correctly selecting the COM port. This showed that many initial errors were related to the toolchain rather than the program logic.
  • The RP2040 provided a more straightforward workflow for local hardware prototyping (button and LEDs), making debugging simpler and faster.
  • As a team, we reinforced a structured debugging methodology: verify wiring → select correct board and port → compile → upload → validate using LED behavior and Serial Monitor.

Individual Conclusions (XIAO RP2040)

  • A stable hardware-software interaction was implemented using a pushbutton with INPUT_PULLUP and software debounce, preventing false triggering caused by mechanical bounce.
  • The LED sequence was controlled using a non-blocking timing approach with millis(), demonstrating better embedded programming practice compared to using delay().
  • The original code provided by Ronal Vilca was improved and reorganized to enhance stability and structure.
  • ChatGPT was used as a support tool to help analyze, refactor, and optimize the code (debounce logic, non-blocking timing, and serial structure). The final implementation was tested, modified, and validated on the physical hardware.
  • Real troubleshooting (pin configuration, wiring adjustments, and debugging through Serial Monitor) strengthened practical understanding of embedded system development.

AI assistance (code adaptation)

I started from Ronal Vilca’s original sketch and used ChatGPT as a support tool to adapt and improve it for my own wiring and testing on the XIAO RP2040.

Show/hide — Prompt used to adapt Ronal Vilca’s code

Help me modify Ronal Vilca’s Arduino code for the XIAO RP2040 so it works with my wiring.
I need a stable button input using INPUT_PULLUP + debounce, trigger the LED sequence only once per press,
replace delay() with millis(), and keep Serial messages for debugging and validation.
  

Show/hide — What I changed (my modifications)

  • Updated pin mapping to match my setup (LEDs on D0, D6, D7; button on D1 to GND).
  • Configured the button with INPUT_PULLUP and added software debounce to avoid false triggers.
  • Implemented a press-event trigger so the sequence runs once per button press.
  • Replaced delay() with a non-blocking timing approach using millis().
  • Added Serial prints to confirm events, cycles, and system state during testing.

Assessment checklist

  • ✅ Linked to the group assignment page (verify the button link is not “GROUP_PAGE_LINK_HERE”)
  • ✅ Browsed and documented some information from a microcontroller’s datasheet (RP2040)
  • ✅ Programmed a board to interact and communicate (button + LEDs + Serial)
  • ✅ Described the programming process(es) used (toolchain, BOOT, upload, Serial monitor)
  • ✅ Included source code (embedded + downloadable .ino)
  • ✅ Included hero shot(s) (board + wiring visible)

← Week 3 Week 5 →

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License .

  • © 2026 Grace Schwan — Licensed under CC BY-NC-SA 4.0 (Some rights reserved).