Here is a stepwise guide to getting started with STM32 embeddedC programming using GCC, CMAKE, and Visual Studio Code IDE:

  1. Install the necessary tools:
  2. Create a new project:
    • Create a new directory for your project.
    • In the project directory, create a file named CMakeLists.txt. This file will contain the CMake build instructions for your project.
    • In the project directory, create a file named main.c. This file will contain your main program code.
  3. Configure CMake:
    • Open Visual Studio Code and open the project directory.
    • Install the CMake Tools extension by clicking on the Extensions icon on the left sidebar and searching for “CMake Tools”.
    • In the project directory, create a file named CMakeSettings.json. This file will contain the CMake configuration for your project.
    • In CMakeSettings.json, specify the toolchain file for the GCC Arm Embedded toolchain, the build type (Debug or Release), and the target architecture (e.g., Cortex-M4).
    • In CMakeLists.txt, specify the minimum required version of CMake, the project name, the C language standard, the source files (main.c), and the target architecture.
  4. Build and Flash the Project:
    • Build the project by opening the Command Palette (Ctrl+Shift+P) and selecting “CMake: Build”. This will generate the binary file for your project.
    • Flash the binary file to your STM32 microcontroller using a programming tool such as ST-Link or J-Link.
  5. Debug the Project:
    • Install the Cortex-Debug extension by clicking on the Extensions icon on the left sidebar and searching for “Cortex-Debug”.
    • Connect your STM32 microcontroller to your computer and open a debug session by clicking on the Debug icon on the left sidebar and selecting “Create a launch.json file”.
    • In launch.json, specify the GDB server executable and port, the binary file path, and the target architecture.
    • Start the debug session by clicking on the “Start Debugging” button.

That’s it! You should now have a working STM32 embeddedC project using GCC, CMake, and Visual Studio Code IDE.

Example CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)
project(stm32_example C ASM)

set(CMAKE_C_STANDARD 11)

set(TOOLCHAIN_PREFIX "arm-none-eabi-")
set(CMAKE_C_COMPILER "${TOOLCHAIN_PREFIX}gcc")
set(CMAKE_ASM_COMPILER "${TOOLCHAIN_PREFIX}gcc")
set(CMAKE_OBJCOPY "${TOOLCHAIN_PREFIX}objcopy")

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -T${CMAKE_SOURCE_DIR}/STM32F446RETx_FLASH.ld")

file(GLOB_RECURSE SOURCES "Src/*.c" "Drivers/STM32F4xx_HAL_Driver/Src/*.c")

add_executable(${PROJECT_NAME}.elf ${SOURCES})
set_target_properties(${PROJECT_NAME}.elf PROPERTIES OUTPUT_NAME ${PROJECT_NAME})

add_custom_target(${PROJECT_NAME}.hex
    COMMAND ${CMAKE_OBJCOPY} -O ihex ${PROJECT_NAME}.elf ${PROJECT_NAME}.hex
    DEPENDS ${PROJECT_NAME}.elf
)

add_custom_target(${PROJECT_NAME}.bin
    COMMAND ${CMAKE_OBJCOPY} -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.bin
    DEPENDS ${PROJECT_NAME}.elf
)

In this example, we are toggling the LED connected to PA5 of the STM32F446RETx microcontroller every second.

#include "stm32f4xx_hal.h"

int main(void) {
    HAL_Init();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    while (1) {
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
        HAL_Delay(1000);
    }
}