How-To-Tutorials · September 23, 2025

How to Configure VS Code and CMake for STM32F4 Projects with PlatformIO

how-to-configure-vs-code-and-cmake-for-stm32f4-projects-with-platformio.png

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 --version to 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

  1. 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 (or Cmd+Shift+X on 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.

  2. 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.).

  3. Configure CMakeLists.txt

    PlatformIO v6 generates a CMakeLists.txt in 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.

  4. Add Your Source Files

    Your code goes in the src/ directory. Create main.c there 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.h in your include/ directory to control which HAL modules get compiled in. Without it, you'll get a wall of "undefined reference" errors at link time.

  5. Build the Project

    Open the VS Code terminal (Ctrl+`) and run:

    pio run

    PlatformIO will resolve dependencies, compile everything, and produce a .bin or .elf in the .pio/build/ directory. If you see errors about missing headers, check that your platformio.ini has the right board and framework settings.

  6. 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 upload

    If 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 monitor opens 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 in include/. PlatformIO follows a strict directory convention. Also double-check CMakeLists.txt for 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 set upload_port if 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_ENABLED defines are active in stm32f4xx_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 .ld file.

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.