Software development for embedded microcontrollers requires – as a minimum – 1) a text editor to enter and tweak source code, 2) a “toolchain” to compile and link the code into a firware image suitable for the selected µC, and 3) an upload mechanism. The best-known example of this is no doubt the “Arduino IDE”, an Integrated Development Environment which, ehm … integrates all of the above into a single (open-source and free) product.

But nowadays I prefer PlatformIO, a.k.a. pio - because it’s less opinionated. Which is just another way of saying that it can be used in more ways, combined with more tools (some of which I already know well), and supports far more embedded platforms.

If you follow pio’s lead, you’ll end up with “VScode”, a modern programmer’s editor, with pio itself added as highly-integrated extension package. It’s probably a great way to get up and running with embedded programming from scratch. It also looks considerably more advanced than the Arduino IDE - not surprising, given that this is Microsoft’s next-generation IDE, evolved from its decades of experience with “MS Visual Studio”.

But I’m not starting from scratch, and am not willing to spend my days switching between a keyboard and a mouse. My wrists have felt the excruciating pain of RSI a few decades ago, and I’ve been very lucky to switch away fast and to come away unharmed.

For intense computer work, I’m now a keyboard person - 95% of the time anyway.

And that’s where the second pio mode comes in: PlatformIO Core. This is the same as used by VScode, but aimed at the command line, i.e. a shell-based window where typing is everything, no mouse or trackpad in sight. For text editing, I use vim (and MacVim), because it’s available everywhere and I know it well, but if you’re looking for a GUI-based editor with excellent keyboard mappings, there’s also Sublime Text, Atom, or CLion.

The point is that with pio’s command-line setup, it doesn’t matter: pick the editor you like and get to know it really well. This is where you’ll spend the rest of your life … just kidding!

Getting started

There is a single hurdle you will need to take upfront. Fortunately, it’s a very small hurdle. In my case, since I use a Mac laptop, and since I have the homebrew package manager installed (the gateway to heaven, IMO), all it takes to install pio on a new Mac for me, is:

brew install platformio

Installation on Windows or Linux will be equally straightforward, but different, obviously.

That’s it. The toolchain is ready. Typing pio should show its help screen.

Embedded hardware

As example, I’m going to use one of the many “Nucleo” boards by ST Microelectronics - not only are they very low-cost and well-designed, they also solve the “first-experience” problem, because the hardware to power, upload, debug, and talk to the µC is on-board, in the form of an ST-Link v2 circuit. All it needs to get started, is a USB cable:

To stay close to home, I’ve decided to use the Nucleo-L053, with the STM32L053 µC on it. There are dozens of alternatives, but this is similar to the JeeNode Zero, and a good starting point for a future project I have in mind. There are well over a hundred STM32 boards to choose from, see the pio/boards page (or type pio boards stm32).

We need to set up a project with a few settings and some source code:

$ mkdir blink
$ cd blink
$ cat >platformio.ini
build_flags = -DSTM32L0
platform = ststm32
framework = stm32cube
board = nucleo_l053r8
lib_deps = jeeh
upload_protocol = mbed
^D  <-- typed as CTRL-D
$ mkdir src
$ cat >src/main.cpp
#include <jee.h>
PinA<5> led;
int main() {
    while (true) {
        led = 1;
        led = 0;
^D  <-- typed as CTRL-D

In prose:

  1. make a new directory blink and switch to it
  2. create a project file called platformio.ini with some settings
  3. make a new directory blink/src for the project’s source code
  4. create a src/main.cpp source file with a few lines of C++ code

For your convenience, the project and code can also be obtained from

The result will look like this:

$ tree blink
├── platformio.ini
└── src
    └── main.cpp

Note: intermediate build results will be placed in hidden directories named .pio*

Now for the magic, assuming the commands above were entered with no mistakes:

pio run -t upload

The first time you run this, pio will fetch and install all the necessary tools for this project. It will also fetch the JeeH library, mentioned as dependency in the project settings. And then it compiles and uploads the project code to the board. The result will be a blinking LED.


Here’s the output I see when building and uploading this project to my Nucleo board:

$ pio run -t upload
Processing nucleo (platform: ststm32; board: nucleo_l053r8; framework: stm32cube)
Verbose mode can be enabled via `-v, --verbose` option
PLATFORM: ST STM32 > ST Nucleo L053R8
HARDWARE: STM32L053R8T6 32MHz 8KB RAM (64KB Flash)
DEBUG: CURRENT(stlink) ON-BOARD(stlink) EXTERNAL(blackmagic, jlink)
Library Dependency Finder ->
Collected 8 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <JeeH> 1.7
Checking size .pioenvs/nucleo/firmware.elf
Memory Usage ->
DATA:    [=         ]   8.6% (used 708 bytes from 8192 bytes)
PROGRAM: [          ]   1.0% (used 624 bytes from 65536 bytes)
Configuring upload protocol...
AVAILABLE: blackmagic, jlink, mbed, stlink
CURRENT: upload_protocol = mbed
Looking for upload disk...
Auto-detected: /Volumes/NODE_L053R8
Uploading .pioenvs/nucleo/firmware.bin
Firmware has been successfully uploaded.
(Some boards may require manual hard reset)
========================= [SUCCESS] Took 0.90 seconds =========================

In case you haven’t noticed: the whole process takes less than a second.

Smooth sailing

Note that I’ve snuck in a library of my own in here, i.e. JeeH. Since it has been registered on the PlatformIO site, there’s no need to specify anything more than “libdeps = jeeh” in the project settings - pio will take care of downloading and compiling it for this project.

And that’s really the whole idea of PlatformIO: to deal with the chore of getting all the tools and libraries, and to build/upload projects. Here are a few other things pio can do for you:

There’s infinitely more to say about PlatformIO, but the documentation site does an exceptionally good job, so there’s really no need for me to add anything here.

As for asking questions and getting tips: check out the active online community.

I’ve been using PlatformIO for well over a year now, and everything I’ve thrown at it works (or gets answered / resolved promptly). They’re doing everything right - very impressive!