How to Configure VS Code and CMake for STM32F4 Projects with PlatformIO
VS Code + CMake + PlatformIO for STM32F4 Development
STM32CubeIDE is fine, but if you already live in VS Code for everything else, context-switching to another IDE feels painful. PlatformIO v6 bridges that gap nicely -- it handles toolchain management, board definitions, and build systems so you can stay in VS Code and still target STM32F4 chips with a proper CMake-based workflow.
Here's how to get a clean STM32F4 project running with VS Code, PlatformIO, and CMake from scratch.
Prerequisites
- Working knowledge of C (you'll be writing bare-metal or HAL-based code)
- VS Code installed (1.85+ recommended)
- PlatformIO IDE extension installed in VS Code
- CMake 3.16+ installed on your system (
cmake --versionto check) - An STM32F4 dev board (Nucleo-F446RE, STM32F4 Discovery, etc.)
Parts and Tools
- Computer running Windows, macOS, or Linux
- STM32F4 development board
- USB cable (micro-USB or USB-C depending on your board's ST-Link connector)
- VS Code with the PlatformIO IDE extension
- CMake 3.16+
Steps
-
Install the Required Software
If you don't have VS Code yet, grab it from code.visualstudio.com. Then open it, hit
Ctrl+Shift+X(orCmd+Shift+Xon Mac) to open the Extensions panel, and search for "PlatformIO IDE". Install it and let it finish its initial setup -- PlatformIO v6 will pull down its own toolchains automatically, which takes a minute the first time.For CMake, grab the latest stable release from cmake.org or install via your package manager (
brew install cmake,apt install cmake, etc.). Version 3.16 or newer works well with PlatformIO's CMake integration. -
Create a New PlatformIO Project
Open the PlatformIO home tab in VS Code (click the alien icon in the sidebar). Hit "New Project", give it a name, and pick your STM32F4 board from the dropdown -- for example, "ST Nucleo F446RE" or "ST STM32F4 Discovery".
For the framework, select "cmsis" or "stm32cube" depending on whether you want bare CMSIS access or the full HAL/LL drivers. PlatformIO v6 handles both well. Click "Finish" and wait for it to scaffold the project.
Watch out: if you pick the wrong board variant, you'll get linker errors later because the memory layout won't match. Double-check which exact F4 chip is on your board (F401, F407, F411, F446, etc.).
-
Configure CMakeLists.txt
PlatformIO v6 generates a
CMakeLists.txtin the project root. Open it and make sure the basics are in place. Here's a minimal configuration:cmake_minimum_required(VERSION 3.16) project(MySTM32Project C ASM) set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR cortex-m4) # PlatformIO manages the toolchain, but if you need explicit paths: set(CMAKE_C_COMPILER arm-none-eabi-gcc) set(CMAKE_CXX_COMPILER arm-none-eabi-g++) set(CMAKE_ASM_COMPILER arm-none-eabi-gcc) # Linker script -- match this to your specific F4 chip set(CMAKE_EXE_LINKER_FLAGS "-TSTM32F446RETx_FLASH.ld")The linker script name matters. If you're on an F407, it'll be something like
STM32F407VGTx_FLASH.ld. PlatformIO usually provides the correct one in the build folder, but verify it matches your chip. -
Add Your Source Files
Your code goes in the
src/directory. Createmain.cthere with a basic skeleton:#include "stm32f4xx.h" int main(void) { HAL_Init(); SystemClock_Config(); // Your application code while (1) { // Main loop } }If you're using the HAL framework, you'll also want
stm32f4xx_hal_conf.hin yourinclude/directory to control which HAL modules get compiled in. Without it, you'll get a wall of "undefined reference" errors at link time. -
Build the Project
Open the VS Code terminal (
Ctrl+`) and run:pio runPlatformIO will resolve dependencies, compile everything, and produce a
.binor.elfin the.pio/build/directory. If you see errors about missing headers, check that yourplatformio.inihas the rightboardandframeworksettings. -
Upload the Firmware
Plug in your STM32F4 board via USB. Most Nucleo and Discovery boards have an onboard ST-Link, so PlatformIO should detect it automatically. Run:
pio run --target uploadIf the upload tool can't find your board, check that your OS recognizes the ST-Link USB device. On Linux, you may need to add udev rules. On Windows, the ST-Link drivers should install automatically, but sometimes you need to grab them manually from ST's website.
Pro tip:
pio device monitoropens a serial monitor right away if you've set up UART output -- handy for quick debugging.
Troubleshooting
- Build errors about missing files: Make sure your source files are in
src/and headers are ininclude/. PlatformIO follows a strict directory convention. Also double-checkCMakeLists.txtfor typos in paths or filenames. - Upload fails or times out: Verify the board shows up as a USB device on your OS. Try a different USB cable (some are charge-only). Check the upload port setting in
platformio.ini-- you can explicitly setupload_portif auto-detection isn't working. - Undefined reference to HAL functions: You're probably missing a HAL module in your config. Make sure the relevant
HAL_xxx_MODULE_ENABLEDdefines are active instm32f4xx_hal_conf.h. - Wrong linker script: If you get memory region errors, your linker script doesn't match your chip's flash/RAM layout. Verify the exact part number on your MCU and use the corresponding
.ldfile.
Where to Go from Here
Once the basic build-and-flash cycle works, you've got a solid foundation. From here, consider adding FreeRTOS v11 for multitasking, setting up GDB debugging through PlatformIO's debug integration (it works with ST-Link out of the box), or integrating STM32CubeMX-generated initialization code into your CMake project for faster peripheral setup. The VS Code + PlatformIO combo scales well as projects grow -- I've used it on production codebases without issues.