Pico: program the Pico with the Arduino core (when C++ is the right tool)
Install the arduino-pico core, upload a blink sketch, and learn when the Pico deserves C++ instead of MicroPython: interrupts, timing precision, and memory headroom.
Most Pico tutorials (including the ones on this site) are MicroPython, and for good reason. But the Pico also runs the Arduino core, which means the Arduino IDE, C++, and the entire Arduino library ecosystem run on a $4 board. Some projects want that, and it is worth knowing which ones before you are halfway into one.
This tutorial installs Earle Philhower’s arduino-pico core (the
community core, not the older Mbed one), uploads a first sketch, and
lays out the honest decision rule for MicroPython versus C++ on this
chip.
The trap is treating this as an either/or decision made once. Both toolchains live on the same machine, flash the same board over the same USB cable, and you can switch between them any afternoon. The real trap inside the trap: uploading a MicroPython UF2 wipes the flash, and then the Arduino sketch appears to have “broken the Pico” when it was just replaced (e.g. people re-flash MicroPython, see the old script gone, and conclude the Arduino IDE deleted their work). One filesystem, one program at a time. Back up your scripts like you back up anything else.
What you need
Needed
- Raspberry Pi Pico or Pico W (about $4-6).
- A micro-USB cable that carries data (the charging-only cables in the junk drawer have wasted more hours than any software bug).
- A computer running Windows, macOS, or Linux.
For the LED demo: nothing else. The Pico has a built-in LED you can blink.
Nice to have
- Breadboard, jumpers, an LED, and a 220 ohm resistor, if you want to blink an external LED on GP15 instead of the onboard one.
- USB hub with individual power switches, so you can cut power for BOOTSEL without unplugging.
- Soldering iron + solder, if you bought a bare Pico with unsoldered headers.
- Soldering iron stand, for parking the iron.
- Helping hands, to hold the header strip square while the joints cool.
- Anti-static wristband, for handling the bare board.
- Magnifying goggles, for inspecting cold solder joints on GP0-GP15.
- Soldering mat, to catch solder balls.
- Wire stripper, if you are making a custom sensor lead.
Wiring
No wiring needed for the first sketch. The onboard LED is on GP25 (Pico) or the “LED” pin (Pico W). For the external-LED variant:
| Component | Connect to |
|---|---|
| LED anode (long leg) | 220 ohm resistor -> Pico GP15 (physical pin 20) |
| LED cathode (short leg) | Pico GND |
Install
The core installs from inside the Arduino IDE, no downloads hunted on GitHub:
- Open the Arduino IDE.
- File >> Preferences >> Additional Board Manager URLs, paste:
https://github.com/earlephilhower/arduino-pico/releases/package_rp2040_index.json - OK, then Tools >> Board >> Boards Manager, search “pico”, install “Raspberry Pi Pico/RP2040” (Earle Philhower’s core).
- Tools >> Board >> Raspberry Pi RP2040 Boards >> select your exact board (e.g. “Raspberry Pi Pico” or “Pico W”).
- Tools >> Port >> pick the Pico’s serial port.
The first upload is the only awkward one. The IDE puts the board in bootloader mode automatically and asks where to save the sketch; after that, uploads happen over the serial port directly.
If the upload fails with “permission denied” or a silent port vanish, another program is holding the serial port. Close any MicroPython REPL (Thonny, mpremote) before uploading. One program at a time owns the port.
The code
Blink, the smoke test
// Works on Pico and Pico W: LED_BUILTIN maps to the right pin
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
Upload (Sketch >> Upload, or the right-arrow button). The LED starts blinking. That is the whole hello-world, and it proves the toolchain, the core, and the USB link all work.
Something MicroPython cannot do well: precise pulses
The real reason to reach for C++ on the Pico is timing. This sketch produces a 1 microsecond pulse train with stable width, the kind of thing you would drive a camera flash trigger or an LED driver with:
const int OUT_PIN = 15;
void setup() {
pinMode(OUT_PIN, OUTPUT);
Serial.begin(115200);
}
void loop() {
digitalWrite(OUT_PIN, HIGH);
delayMicroseconds(1); // one microsecond, reliably
digitalWrite(OUT_PIN, LOW);
delay(99); // 100 Hz total rate
Serial.print("heap: ");
Serial.println(RP2040.firmwareVersion()); // just proving the core API exists
}
MicroPython sleeps in milliseconds; sub-microsecond jitter is outside its deal. If a project needs that kind of timing, C++ is the right tool, and on the extreme end PIO (the Pico’s programmable I/O blocks) handles it without the CPU at all.
The library ecosystem argument
The second reason: Arduino libraries. Every sensor with a
begin()/read() API has one (e.g. Adafruit’s BME280, the TFT
display stacks, CAN bus, all of it). The MicroPython versions are
often single-file ports of varying quality. When a project leans on
several mature libraries, the C++ side saves real time.
When MicroPython is still the right answer
The honest decision table, from a few years of building both ways:
| Situation | Pick |
|---|---|
| Scripting, tweaking, REPL-driven experiments | MicroPython |
| Sub-microsecond timing, heavy interrupts | Arduino (C++) |
| Lean on mature Arduino libraries | Arduino (C++) |
| Rapid iteration on a hobby project | MicroPython |
| Very small flash/RAM budget, tight control | Arduino (C++) |
| Web servers and MQTT on a Pico W | Either works; MicroPython code is shorter |
The two share more than people expect: the GPIO, PWM, UART, and I2C concepts are identical, so moving between them costs an evening, not a semester.
Flash layout and the back-and-forth
One more mental model and you are done: the Pico’s flash holds one program. Flashing a UF2 (MicroPython, CircuitPython, or a UF2 built from the Arduino IDE) replaces whatever was there. That is why the first Arduino upload after MicroPython feels like an event; it is the same mechanism both toolchains use.
If you settle on C++ but keep a rescue REPL, flash MicroPython back by holding BOOTSEL and dropping the UF2 again. Nothing about the board ages or wears out in this cycle; it is all just files in flash.
What you learned
- The
arduino-picocore installs from the Arduino IDE Board Manager with one URL in Preferences. - The same board, cable, and BOOTSEL mechanism serve both toolchains; flash replacement is the expected behavior, not data loss.
- C++ earns its keep on precise timing (delayMicroseconds-class work) and mature Arduino libraries.
- MicroPython earns its keep on iteration speed and readable scripts.
- Knowing both means picking per project, not per career.
When something breaks
- The board does not appear as a port. The USB cable is charge-only, or the driver is missing on Windows. Try a known-good data cable first; it is the most common failure by a wide margin.
- Upload fails with “boot mode” errors. The IDE could not flip the board into bootloader mode. Hold BOOTSEL while plugging in USB, then upload; the manual path always works.
- Sketch uploads but nothing runs. You selected the wrong board variant (e.g. “Pico W” code on a plain Pico). The onboard LED pin differs between variants; check Tools >> Board matches the board on the desk.
- The IDE cannot find the core after install. The Board Manager URL in Preferences is mistyped or your network blocks GitHub. The URL must be exactly the one in the install steps above.
- Port busy on every upload. A REPL session is holding the serial
device. Close Thonny or kill mpremote, then upload (e.g. on Linux,
check
lsof /dev/ttyACM0to find the holder). - My scripts vanished after an Arduino upload. Expected: the
flash now holds the compiled sketch. Re-flash MicroPython and copy
your
.pyfiles back from your backup.
What to build next
- The Pico MicroPython setup tutorial is the other half of this decision, with the REPL workflow this one replaces for C++ projects.
- The Pico W web server tutorial exists in both toolchains; compare the same project in Python and C++ in one sitting.
- The servo tutorial in MicroPython ports to C++ with the
Servo.hlibrary in about ten lines (e.g.attach(pin)andwrite(degrees)replace the whole duty-cycle dance). - The microSD datalogger tutorial is the classic C++ win: the SD library and sensor libraries are more mature on the Arduino side.