Skip to content

XIAO RP2040 MicroPython Setup & Troubleshooting Guide

Session Summary

This document summarizes a hands-on learning session for setting up and programming the XIAO RP2040 microcontroller with MicroPython, including common pitfalls and solutions.


1. Understanding BOOTSEL Mode

What is BOOTSEL Mode?

  • BOOTSEL = BOOTloader SELection mode
  • Special startup mode where the RP2040 acts as a USB flash drive
  • Appears as a mounted drive named "RPI-RP2"
  • Used to install firmware by drag-and-drop of .uf2 files

How to Enter BOOTSEL Mode

  1. Hold the BOOT button while plugging in USB cable, OR
  2. Double-press the RESET button quickly

BOOTSEL vs Normal Programming

  • BOOTSEL mode: Direct firmware flashing (MicroPython, CircuitPython, bootloaders)
  • Normal programming: Upload code via serial (Arduino IDE, Thonny, mpremote)
  • Both write to the same flash memory (non-volatile storage)

What You See in BOOTSEL Mode

After successfully installing MicroPython firmware: - The .uf2 file disappears (consumed during flashing) - Two files appear: INDEX.HTM and INFO_UF2.TXT - These are virtual files generated by the bootloader - Board automatically reboots into MicroPython


2. Memory Types on RP2040

SRAM (Volatile) - 264KB

  • Fast, temporary memory
  • Loses data when powered off
  • Used for variables, stack, heap during program execution

Flash (Non-volatile) - 2MB on XIAO RP2040

  • Permanent storage
  • Retains data when powered off
  • Stores program code, libraries, and data files

3. Reset Button vs Unplug/Replug

Reset Button (R)

  • Restarts the RP2040 chip
  • Power stays on
  • USB connection often remains active
  • Faster for development workflow
  • Good for: restarting programs, quick testing

Unplug/Replug

  • Complete power cycle
  • Full hardware reset
  • USB fully disconnects and reconnects
  • Good for: stuck USB states, exiting BOOTSEL mode, weird behavior

For most development: Reset button is sufficient
For troubleshooting: Unplug/replug provides a cleaner slate


4. VS Code Tasks Configuration

Understanding tasks.json

Created a VS Code task for automated MicroPython uploads:

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Upload to Pico",
      "type": "shell",
      "command": "mpremote connect auto fs cp main.py : + reset",
      "group": "build",
      "presentation": {
        "reveal": "always",
        "panel": "shared"
      }
    }
  ]
}

Key Components Explained

  • mpremote: MicroPython remote control tool
  • connect auto: Auto-detect the RP2040
  • fs cp main.py :: Copy file to board's root directory
  • + reset: Chain command to soft-reset the board
  • [] brackets: JSON array (required even for single task)
  • {} braces: JSON object (key-value pairs)

Prerequisites

Install mpremote:

pip install mpremote


5. JSON File Format

What is JSON?

  • JSON = JavaScript Object Notation
  • Plain text format for structured data
  • Human-readable and machine-parseable
  • Language-independent

JSON Syntax

  • {} = Object (key-value pairs, like a dictionary)
  • [] = Array (ordered list of items)
  • Keys must be in double quotes
  • No trailing commas allowed

Common Uses

  • Configuration files (VS Code, Arduino)
  • Data storage (sensor readings, settings)
  • API communication
  • MicroPython config files

6. First MicroPython Code - LED Blinking

Initial Code (Had Issues)

from machine import Pin
import time

print("Hello World")
led = Pin(6, Pin.OUT)

t = 10
off = 0.5
slow = 1.5
quick = 0.5

while t > 1:
    led.toggle()
    time.sleep(off)
    led.toggle()
    time.sleep(slow)
    led.toggle()
    time.sleep(off)
    led.toggle()
    time.sleep(quick)
    led.toggle()
    time.sleep(off)
    led.toggle()
    time.sleep(quick)
    t -= 1

Problem Encountered

  • Code logic was correct
  • Onboard LED worked fine
  • External LED did not light up

7. Troubleshooting External LED

Common Hardware Issues Identified

Issue 1: LED Polarity

LEDs only work in one direction: - Anode (+): Long leg, connects to resistor/pin - Cathode (-): Short leg, flat side, connects to GND - Solution: Flip LED 180° if backwards

Issue 2: Missing/Wrong Resistor

  • Need 220Ω - 1kΩ current-limiting resistor
  • Correct wiring: Pin → Resistor → LED+ → LED- → GND

Issue 3: Incomplete Circuit

  • LED cathode must connect to GND pin on XIAO
  • Circuit must be complete for current flow

Issue 4: Wrong Pin Number (THE ACTUAL PROBLEM!)

  • XIAO RP2040 silkscreen labels don't match GPIO numbers
  • Board label D6 = GPIO 0 in code
  • This was the root cause of the LED not working

8. XIAO RP2040 Pin Mapping (Critical!)

The Confusion

The XIAO RP2040 has misleading silkscreen labels. You must translate:

Board Label Use in Code Notes
D0 Pin(26) Also ADC0
D1 Pin(27) Also ADC1
D2 Pin(28) Also ADC2
D3 Pin(29) Also ADC3
D4 Pin(6)
D5 Pin(7)
D6 Pin(0) ← Common mistake!
D7 Pin(1)
D8 Pin(2)
D9 Pin(4)
D10 Pin(3)

Special Pins

  • Onboard LED: Pin(25) or Pin(16), Pin(17) for RGB components
  • NeoPixel Power: Pin(11)
  • NeoPixel Data: Pin(12)

Best Practice

Always comment your code with both labels:

# D6 = GPIO 0
led = Pin(0, Pin.OUT)


9. Running Multiple LEDs

Method 1: Two Separate Pins (Simplest)

from machine import Pin
import time

led1 = Pin(26, Pin.OUT)  # D0
led2 = Pin(27, Pin.OUT)  # D1

# Both on
led1.on()
led2.on()
time.sleep(1)

# Both off
led1.off()
led2.off()

Method 2: Alternating Pattern

while True:
    led1.on()
    led2.off()
    time.sleep(0.5)

    led1.off()
    led2.on()
    time.sleep(0.5)

Method 3: Using Lists (Scalable)

leds = [
    Pin(26, Pin.OUT),
    Pin(27, Pin.OUT),
    Pin(28, Pin.OUT),
]

# Toggle all
for led in leds:
    led.toggle()

Hardware Requirements

Each LED needs: - Its own GPIO pin - Its own current-limiting resistor (220Ω - 1kΩ) - Connection to GND (can share common GND)


10. Key Lessons Learned

Technical Insights

  1. BOOTSEL mode is for firmware installation, not which memory type
  2. Pin mapping is critical - silkscreen ≠ GPIO number
  3. JSON arrays [] are required even for single items in task configurations
  4. Reset button vs unplug/replug serve different purposes
  5. Hardware debugging requires systematic checking: polarity, resistors, connections, pin numbers

Best Practices

  1. Always verify pin numbers against GPIO mapping
  2. Test with onboard LED first to validate code logic
  3. Use descriptive variable names and comments
  4. Create pin mapping dictionaries for complex projects
  5. Install mpremote for efficient development workflow

Common Mistakes to Avoid

  • ❌ Using silkscreen label (D6) directly as pin number
  • ❌ Forgetting current-limiting resistors
  • ❌ Reversing LED polarity
  • ❌ Not connecting to GND
  • ❌ Confusing BOOTSEL mode with memory types

11. Development Workflow Summary

1. Initial Setup

  1. Enter BOOTSEL mode (hold BOOT + plug USB)
  2. Drag MicroPython .uf2 file to RPI-RP2 drive
  3. Board auto-reboots into MicroPython

2. Code Development

  1. Write code in VS Code or Thonny
  2. Save as main.py (auto-runs on boot)
  3. Upload via mpremote or Thonny

3. Testing

  1. Use REPL for interactive testing
  2. Test onboard LED first
  3. Verify external hardware connections
  4. Check serial output for debugging

4. Debugging Hardware

  1. Verify LED polarity (long leg = +)
  2. Confirm resistor is present
  3. Check GND connection
  4. Verify GPIO pin number (most common issue!)
  5. Test with simple on/off code

12. Resources Created

Documentation Files

  1. MicroPython Commands Reference
  2. REPL commands
  3. File operations
  4. GPIO, PWM, ADC
  5. Timers, UART, I2C, SPI
  6. Common patterns and examples
  7. mpremote commands

  8. XIAO RP2040 Pinout Reference XIAO RP2440 Pinout

  9. Complete pin mapping table
  10. I2C/SPI/UART configurations
  11. ADC pin reference
  12. NeoPixel LED control
  13. Common mistakes and solutions

13. Next Steps

  1. Master basic GPIO: Multiple LEDs, buttons with debouncing
  2. Explore PWM: LED fading, servo control
  3. Try ADC: Read sensors (temperature, light, potentiometer)
  4. Communication protocols: I2C sensors, SPI displays
  5. Advanced topics: Interrupts, timers, multithreading

Project Ideas

  • Traffic light simulator (3 LEDs)
  • Button-controlled LED patterns
  • Temperature monitor with LED indicators
  • Sensor data logger to JSON files
  • Simple game with buttons and LEDs

Quick Troubleshooting Checklist

When code doesn't work: - [ ] Is print() output appearing? (Code is running) - [ ] Does onboard LED work with same code? (Logic is correct) - [ ] Is GPIO number correct for silkscreen label? (Check pin mapping!) - [ ] Is LED polarity correct? (Long leg to pin/resistor) - [ ] Is resistor present? (220Ω - 1kΩ) - [ ] Is GND connected? (Complete circuit) - [ ] Try different pin to isolate hardware vs software issue


Conclusion

This session covered the complete journey from understanding BOOTSEL mode to successfully controlling multiple external LEDs with MicroPython on the XIAO RP2040. The main breakthrough was discovering the pin mapping discrepancy between silkscreen labels and GPIO numbers - a common pitfall for beginners.

Key Takeaway: Always verify pin mappings when working with new hardware. The silkscreen label is not always the GPIO number you use in code!


Session Date: February 16, 2026
Board: Seeed Studio XIAO RP2040
Firmware: MicroPython (latest)
Development Environment: VS Code with mpremote