Skip to content
Shop

STM32 MCU: PlatformIO Setup

Set up with your favorite AI

Gemini & other AI

Copy the setup prompt into your AI. Work through each step together, from checking your kit to getting it running.

Open Gemini

Copy the prompt, then paste it into Gemini’s message box.

View prompt

This guide follows the Japanese STM32 PlatformIO guide and uses VS Code with PlatformIO to build a program that prints Hello World once per second. STM32CubeProgrammer uploads it through a USB leaf. You do not need Arduino IDE or its board package for this workflow.

Install the latest stable software from the official distribution sites. The STM32CubeProgrammer version pins in older instructions are no longer required for this workflow.

  • STM32 MCU leaf (AP03 / STM32L452REI6) and a USB leaf
  • A data-capable USB cable
  • A Windows, macOS or Linux computer with an internet connection

For Basic Kit 2, replace the assembled AVR MCU with the STM32 MCU leaf before programming.

  1. Install Visual Studio Code for your OS and CPU.
  2. Open Extensions in VS Code, find PlatformIO IDE published by PlatformIO, and install it. Wait for its initial setup to finish and restart VS Code if requested.
  3. Install STM32CubeProgrammer from ST. Locate its command-line executable; you will use its actual path in upload_command.

PlatformIO Core and its serial monitor are included in the IDE extension. If prompted for Python, follow PlatformIO’s Python installation instructions; Linux also requires python3-venv. See the PlatformIO IDE documentation for setup details.

Python is prepared automatically on supported operating systems. Add Japanese Language Pack for Visual Studio Code if you want a Japanese interface, or Teleplot for graphs.

OSSTM32CubeProgrammer command-line tool
Windowsbin/STM32_Programmer_CLI.exe under the installation folder
macOSContents/Resources/bin/STM32_Programmer_CLI inside STM32CubeProgrammer.app
Linuxbin/STM32_Programmer.sh under the installation folder

Use a local project path with simple ASCII characters, such as C:/PlatformIO/Projects on Windows. Open the command terminal through PlatformIO → Quick Access → Miscellaneous → PlatformIO Core CLI. To change the default folder for new projects, run the following with your actual path and restart VS Code:

Terminal window
pio settings set projects_dir "C:/PlatformIO/Projects"

This does not move existing projects. See the projects_dir documentation.

Simple paths help avoid path-handling problems. User folders and OneDrive locations differ between computers, so check the actual destination before copying an example. On macOS and Linux, replace the quoted path with the absolute path to your chosen folder.

1. Create the project and install its board definition

Section titled “1. Create the project and install its board definition”

Use the Leafony AP03 board definition, which contains Leafony’s pin assignments and serial configuration. It differs from the Leafony Systems AP03 definition registered with PlatformIO.

  1. Create an empty folder named STM32_Hello_World_Pjt and open it with File → Open Folder in VS Code.
  2. Download the board definition repository using Code → Download ZIP and extract it.
  3. Create boards, variants/STM32L4xx and src under the project folder.
  4. Copy LEAFONY_AP03.json into boards. Copy the entire LEAFONY_AP03 directory into variants/STM32L4xx. Match filename capitalization exactly.
  5. Create platformio.ini in the project root and main.cpp inside src.
STM32_Hello_World_Pjt/
├── platformio.ini
├── boards/
│ └── LEAFONY_AP03.json
├── variants/
│ └── STM32L4xx/
│ └── LEAFONY_AP03/
│ ├── PeripheralPins.c
│ ├── PinNamesVar.h
│ ├── generic_clock.c
│ ├── ldscript.ld
│ ├── variant_generic.cpp
│ ├── variant_generic.h
│ ├── variant_LEAFONY_AP03.cpp
│ └── variant_LEAFONY_AP03.h
└── src/
└── main.cpp

PlatformIO reads the definition from the project’s boards directory. You do not need to overwrite files in .platformio/packages or .platformio/platforms. For another project, copy boards and variants and use the configuration below.

With USB disconnected, assemble the STM32 MCU and USB leaves as shown in the connection example. Connect the USB leaf to your computer, then run:

Terminal window
pio device list

The connected port disappears and reappears when you unplug and reconnect the cable.

OSExample port
WindowsCOM3
macOS/dev/cu.usbserial-XXXXXXXX
Linux/dev/ttyUSB0

If no port appears, check the cable, leaf connections and USB driver. Refer to the FAQ. On Linux, also follow PlatformIO’s serial port permissions instructions.

The following example is for Windows on COM3. Replace the port and executable path with those on your computer.

[env:leafony_ap03]
platform = ststm32
board = LEAFONY_AP03
framework = arduino
board_build.variants_dir = variants
upload_protocol = custom
upload_port = COM3
upload_command = "C:/Program Files/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin/STM32_Programmer_CLI.exe" -c port=$UPLOAD_PORT br=115200 -w "$SOURCE" 0x08000000 -v
monitor_port = ${this.upload_port}
monitor_speed = 115200

On macOS, replace upload_port and upload_command with the following, using the actual port name:

upload_port = /dev/cu.usbserial-XXXXXXXX
upload_command = "/Applications/STMicroelectronics/STM32Cube/STM32CubeProgrammer/STM32CubeProgrammer.app/Contents/Resources/bin/STM32_Programmer_CLI" -c port=$UPLOAD_PORT br=115200 -w "$SOURCE" 0x08000000 -v

On Linux, use the absolute installation path and actual serial port. This example uses the account name user:

upload_port = /dev/ttyUSB0
upload_command = "/home/user/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin/STM32_Programmer.sh" -c port=$UPLOAD_PORT br=115200 -w "$SOURCE" 0x08000000 -v
SettingPurpose
[env:leafony_ap03]Names the build environment and output folder
board = LEAFONY_AP03Selects boards/LEAFONY_AP03.json
board_build.variants_dirSelects the folder containing the pin definitions
upload_protocol = customRuns upload_command for uploads
$UPLOAD_PORT, $SOURCESubstituted by PlatformIO with the port and firmware path
0x08000000Flash start address
-vVerifies the uploaded data
monitor_portSerial monitor port; the upload port in this example
monitor_speedSerial baud rate; must match Serial.begin()

Leave $UPLOAD_PORT and $SOURCE unchanged. See the PlatformIO upload command reference and STM32CubeProgrammer CLI manual.

Save the following as src/main.cpp:

#include <Arduino.h>
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println("Hello World");
delay(1000);
}

Run PlatformIO → PROJECT TASKS → leafony_ap03 → General → Build, or run this command in the project folder:

Terminal window
pio run -e leafony_ap03

The first build downloads the compiler and framework and can take several minutes. Check for SUCCESS at the end of the log and the generated file .pio/build/leafony_ap03/firmware.bin. If the project is not recognized, reopen the folder containing platformio.ini.

If several projects or build environments are open, check that the selected target is leafony_ap03 in STM32_Hello_World_Pjt.

  1. Close any application using the serial port, including the serial monitor and Teleplot. Press Ctrl+C in PlatformIO’s monitor terminal to stop it.
  2. Set the STM32 MCU switch to Program and check that its LED is on.
  3. Press Reset to enter programming mode.
  4. Run PROJECT TASKS → leafony_ap03 → General → Upload, or:
Terminal window
pio run -e leafony_ap03 -t upload

STM32 MCU program switch, reset switch and LED

Check the STM32CubeProgrammer log for successful connection, programming and verification. A verification success message may read Download verified successfully; wording depends on the tool version. If there is a timeout or verification error, close other port users, reset in Program mode and upload again, even if the overall log says SUCCESS.

  1. Set the switch back to Run and check that the LED turns off.
  2. Press Reset to start the program.
  3. Run PROJECT TASKS → leafony_ap03 → General → Monitor, or:
Terminal window
pio device monitor -e leafony_ap03

The following output should appear once per second:

Hello World
Hello World
Hello World

Download a project from the Leafony STM32 PlatformIO samples. Open the individual folder containing its platformio.ini, rather than the entire repository.

Apply the same boards, variants and upload settings used above. Preserve sample-specific lib_deps and build_flags. Replace old upload commands referencing Arduino15/.../STM32Tools/1.4.0/... with the path to your installed STM32CubeProgrammer.

For example, when using STM32_Hello_World_Pjt, place boards and variants inside the project and apply this page’s platformio.ini settings. Review the existing sample settings before carrying them over.

Review library compatibility before updating packages. pio pkg update updates dependencies within the version constraints in platformio.ini; see the command reference.

Adjust the version constraints as needed, then run the update command in the project folder.

Add libraries to lib_deps inside the [env:...] section you use. The Hello World example needs no additional libraries.

If lib_deps already exists, append to its list. Add only the libraries needed for the leaves and functions you use.

lib_deps =
adafruit/Adafruit Unified Sensor
adafruit/Adafruit BusIO
https://github.com/Leafony/TBGLib

Git URLs require Git. Restart VS Code after installing it and check that git --version works in the terminal.

Leaf or functionLibraries
BLETBGLib
4-SensorsAdafruit Unified Sensor, Adafruit BusIO, HTS221, ClosedCube OPT3001, Adafruit LIS3DH
LCDST7032
RTC on RTC & microSDRTClib
STM32 internal RTC / low powerSTM32duino RTC, STM32duino Low Power
LTE-MLteLeafV4
Wi-FiWiFi101Leafony
LoRa / signed communicationarduino-LoRa, arduino-tca9536, SparkFun ATECCX08a

ST STM32 20.0.0 moved to STM32 Arduino Core 3.0.0. Follow the STM32RTC requirements and STM32LowPower requirements: use the 2.x library lines with Core 3.x, and 1.x with Core 2.x.

; For STM32 Arduino Core 3.x
lib_deps =
stm32duino/STM32duino RTC@^2.0.0
stm32duino/STM32duino Low Power@^2.0.0

Check the framework-arduinoststm32 entry under PACKAGES in the build log to identify your Core. Do not use the AVR MsTimer2 library on STM32; use HardwareTimer instead.

Even if an older sample specifies a version such as @1.2.0, check each library’s README against the Arduino Core used by your project.

The Leafony board definition normally runs the CPU at 80 MHz.

  1. Download Leafony’s leafony_tools .cpp and save it as src/leafony_tools.cpp. Remove the space before .cpp from the downloaded filename.
  2. Add the following flag to the active environment. If build_flags already exists, append the flag to it.
build_flags =
-D CPUCLOCK_LOW
  1. Replace main.cpp with the following, rebuild and upload. Return the switch to Run and reset. The monitor should print 16000000.
#include <Arduino.h>
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println(HAL_RCC_GetHCLKFreq());
delay(1000);
}

Remove -D CPUCLOCK_LOW, rebuild and upload to return to 80 MHz. Changing board_build.f_cpu alone does not switch the actual hardware clock.

Install Teleplot for VSCode. Upload this example, return the switch to Run and reset:

#include <Arduino.h>
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.print(">seconds:");
Serial.println(millis() / 1000.0f);
delay(100);
}

Close PlatformIO’s serial monitor. From the VS Code command palette run teleplot: Start teleplot session, choose the serial port and baud rate 115200, then click Open. Check that seconds appears in the graph.

Teleplot uses newline-terminated >name:value messages. Serial.println() supplies the newline. Close Teleplot’s port before uploading another program. See also the STM32 Teleplot example.

src/main.cpp follows normal C++ rules. Add #include <Arduino.h>, declare functions before use, and add required libraries to lib_deps.

#include <Arduino.h>
void printMessage();
void setup() {
Serial.begin(115200);
printMessage();
}
void loop() {
}
void printMessage() {
Serial.println("Hello World");
}
  1. Build and locate .pio/build/leafony_ap03/firmware.bin. If you renamed the environment, use its folder name instead.
  2. Close other serial port users, switch to Program and press Reset.
  3. Open STM32CubeProgrammer and connect using the following settings.
SettingValue
ConnectionUART
PortThe STM32 MCU serial port
Baud rate115200
ParityEven
Data bits8
Stop bits1
Flow controlOFF
  1. Open Erasing & Programming. Select firmware.bin and start address 0x08000000.
  2. Enable Verify programming, click Start Programming, and check that verification succeeds.
  3. Click Disconnect, return the switch to Run, press Reset, and check output in PlatformIO’s serial monitor.
SymptomCheck
UnknownBoard or missing variant filesFile paths, capitalization and board_build.variants_dir
pio command not foundReopen the PlatformIO Core CLI terminal
Upload tool not foundActual installation path and quotes around paths containing spaces
Cannot open the portPort name, other applications holding the port, and Linux permissions
Connection times outProgram switch, Reset before upload, USB cable and port name
No output after uploadSwitch back to Run, Reset, and monitor_port
Garbled serial outputMatch monitor_speed to Serial.begin(); this example uses 115200