Skip to content

4. Embedded Programming

Overview

This week’s goal was to deepen my knowledge of multiple microcontrollers by working with the Seeed Studio XIAO ESP32-C3 and the Seeed Studio XIAO RP2040 I used both Arduino and MicroPython to program the first two controllers. I also learned how to download and use the relevant software for each platform.

Out of the two, the Seeed Studio XIAO ESP32-C3 (C3) quickly became my favorite. It’s a very reliable chip that can be programmed relatively easily, with little troubleshooting needed. It supports Wi-Fi, Bluetooth Low Energy, can be powered by a battery, and is relatively affordable.

Group work

Group assignment: Demonstrate and compare the toolchains and development workflows for available embedded architectures

Microcontrollers Used

Seeed Studio XIAO ESP32-C3

Datasheet Summary
Feature Specification
Chip ESP32-C3
Speed Up to 160 MHz
Flash / SRAM 4 MB Flash, 400 KB SRAM
GPIO Pins 11 GPIO pins
Analog Pins 3 Analog pins (A0, A1, A2)
Communication Protocols UART, SPI, I2C, BLE, Wi-Fi
ADC 12-bit ADC
Arduino Programming

For the ESP32-C3, I test how a pull-down resistor works using a button and an LED. The button is set up such that when the button is not pressed, the input pin reads LOW, and when pressed, the input pin reads HIGH because the voltage flows through the button with the pull-down resistor pulling the input to ground when not pressed.

I first tested the circuit and code in Wokwi, an website where you can test circuits, to make sure the code worked without worrying about hardware issues. After that, I redid the setup physically on a breadboard using the ESP32-C3.

Here is the code I used in Arduino IDE:

#define LED_PIN D2
#define BUTTON_PIN D4

void setup() {
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
  pinMode(BUTTON_PIN, INPUT_PULLDOWN);
}

void loop() {
  int buttonState = digitalRead(BUTTON_PIN);
  if (buttonState == HIGH) {
    digitalWrite(LED_PIN, HIGH);
  } else {
    digitalWrite(LED_PIN, LOW);
  }
  delay(100); // Small delay for debounce and readability
}

How it works

  • Pin Definitions: Assign easy-to-read names to pins for clarity.
  • Setup: Define LED_PIN as an OUTPUT and BUTTON_PIN as an INPUT with a built-in pull-down resistor. The LED starts off.
  • Loop: Read the button state; if pressed, turn LED on, otherwise off.

Troubleshooting:

During upload, I had an exit status 1 error, which seemed came from hardware or connection problems rather than the code. After changing USB cables and using different computers, I eventually got it to work on one computer with good USB ports. Trouble shooting is not fun.

MicroPython Programming

Setting up MicroPython on the ESP32-C3 was more complicated. I had to:

  1. Download the generic ESP32-C3 firmware from the MicroPython website.
  2. Install esptool through Python to flash firmware using terminal commands.
  3. Identify the correct USB port (ls /dev/cu.* command on Mac).
  4. Erase flash memory (if there was already code) by putting the ESP in bootloader mode.
  5. Flash the MicroPython firmware.

At first, Thonny did not recognize the device until I configured the interpreter to the correct port. I also faced “error 6” read failures but resolved them after taking a break and trying again.

Here’s the MicroPython code for the button and LED:

from machine import Pin
import time

LED_PIN = 2  # GPIO pin for LED on ESP32-C3
BUTTON_PIN = 3  # GPIO pin for button

led = Pin(LED_PIN, Pin.OUT)
button = Pin(BUTTON_PIN, Pin.IN, Pin.PULL_DOWN)

while True:
    button_state = button.value()
    if button_state == 1:
        led.value(1)  # Turn LED on
    else:
        led.value(0)  # Turn LED off
    time.sleep(0.1)  # Delay for debounce and readability

Seeed Studio XIAO RP2040

Datasheet Summary
Feature Specification
Chip RP2040
Speed 133 MHz
Flash / SRAM 2 MB Flash, 264 KB SRAM
GPIO Pins 11 GPIO pins
Analog Pins 4 Analog pins (A0–A3)
Communication Protocols UART, I2C, SPI, I2S, PWM
ADC 12-bit ADC

Arduino Programming

The RP2040 workflow was similar to the ESP32-C3’s. The main difference was changing the pin numbers based on the RP2040’s pinout and avoiding computers that had USB port issues from earlier.

Here is the Arduino code I used, similar to the ESP32-C3 but with adjusted pins:

#define LED_PIN A2
#define BUTTON_PIN A1

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
  pinMode(BUTTON_PIN, INPUT_PULLDOWN);
}

void loop() {
  int buttonState = digitalRead(BUTTON_PIN);
  if (buttonState == HIGH) {
    digitalWrite(LED_PIN, HIGH);
  } else {
    digitalWrite(LED_PIN, LOW);
  }
  delay(100); // Small delay for debounce and readability
}

MicroPython Programming

Setting up MicroPython on the RP2040 was much simpler compared to the ESP32-C3. I only had to:

  1. Download the firmware from the MicroPython website.
  2. Put the RP2040 into bootloader mode (by holding the BOOT button while plugging it in).
  3. Copy the firmware file directly onto the RP2040 drive that appears on my desktop.

No terminal commands, and the device was immediately recognized by Thonny.

MicroPython code for the RP2040 was basucally the same as the ESP32-C3 code, just with different pins:

from machine import Pin
import time

LED_PIN = 26  # Corresponding to A2 on RP2040
BUTTON_PIN = 27  # Corresponding to A1 on RP2040

led = Pin(LED_PIN, Pin.OUT)
button = Pin(BUTTON_PIN, Pin.IN, Pin.PULL_DOWN)

while True:
    button_state = button.value()
    if button_state == 1:
        led.value(1)
    else:
        led.value(0)
    time.sleep(0.1)

Workflow Summary

Arduino

  1. Write your code in Arduino IDE using C++.
  2. Install necessary libraries via Board Manager (search for ESP boards).
  3. Select the correct board and port under the Tools menu.
  4. Verify and upload your code.

MicroPython

  1. Download the latest MicroPython firmware for your board.
  2. For ESP32-C3, install esptool and use terminal commands to erase flash and flash firmware.
  3. For RP2040, simply copy the firmware file onto the device in bootloader mode.
  4. Configure Thonny interpreter to connect to your device’s port.
  5. Upload MicroPython code and run.

Last update: June 3, 2025