CMake + CubeMX/CubeCLT Toolchain

In Getting Started/STM32Cube, we went over how to set up the STM32Cube toolchain utilizing our own scripts and CMakeLists.txt templates to setup and build the projects.

In this document, we will go over the manual approach of using CubeMX and CubeCLT directly.

Prerequisites

Please install STM32CubeMX and STM32CubeCLT by following the instructions in the Getting Started/STM32Cube document.

1. Creating a New CubeMX Project

  1. Open CubeMX and navigate to FileNew Project.
  2. A window should pop up. In this window, select your desired MCU or development board. To search, use the "Commercial Part Number" search bar.
  3. When you have selected your MCU/board, click Start Project in the top right.
  4. Navigate to the Project Manager tab.
  5. Give your project a name and set the Project Location to the desired directory.
  6. Set the Toolchain / IDE dropdown to CMake.
  7. Now, still in the Project Manager tab, navigate to the Code Generator settings on the left menu.
  8. Select Copy only the necessary library files. This will reduce bloat on your computer by only bringing in the necessary HAL files for your specific project instead of all 900+.
  9. Save the project by navigating to FileSave Project or by pressing Ctrl + S.
  10. Click Generate Code in the top right. CubeMX will generate the project files in the specified directory. For example, if the project name is myproject and the location is /home/user/mrover-esw/src/, the generated files will be in /home/user/mrover-esw/src/myproject/.

2. Adding CMake Dependencies to Projects

Removing Dependency on Generated HAL Drivers

By default, CubeMX generates HAL drivers and includes them in the project. The top level CMakeLists.txt then includes these generated HAL drivers in the build with the following line:

add_subdirectory(cmake/stm32cubemx)

If you take a look inside the CMakeLists.txt inside the cmake/stm32cubemx/ directory, you will see that it includes all of the generated HAL drivers for the selected MCU. This CMakeLists.txt is automatically generated by CubeMX to include the necessary HAL drivers your project requires. For example:

set(STM32_Drivers_Src
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Core/Src/system_stm32g4xx.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_pwr_ex.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_rcc.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_rcc_ex.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_flash.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_flash_ex.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_flash_ramfunc.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_gpio.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_exti.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_dma.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_dma_ex.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_pwr.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_cortex.c
)

These generated HAL drivers total over 900 files, which is unnecessary and would bloat the repository if committed. In order to prevent this, we remove the dependency on the generated HAL drivers for each project and instead use a shared HAL driver library which is hosted as a git submodule in lib/stm32g4/STM32CubeG4.

To do this, we create our own CMakeLists.txt file in a new directory cmake/stm32cubemx_extern/. This CMakeLists.txt file will replace the generated one and instead link to the shared HAL driver library. For example, the above generated CMakeLists.txt would be replaced with the following:

set(STM32_Drivers_Src
    ${CMAKE_CURRENT_SOURCE_DIR}/../../Core/Src/system_stm32g4xx.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_pwr_ex.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_rcc.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_rcc_ex.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_flash.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_flash_ex.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_flash_ramfunc.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_gpio.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_exti.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_dma.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_dma_ex.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_pwr.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_cortex.c
)

You can see that instead of navigating to the Drivers/STM32G4xx_HAL_Driver/ directory that is autogenerated for every project, we instead navigate to the shared HAL driver library in lib/stm32g4/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/.

To use this new CMakeLists.txt file instead of the autogenerated one, simply replace the following line in the top-level CMakeLists.txt:

add_subdirectory(cmake/stm32cubemx)

with

add_subdirectory(cmake/stm32cubemx_extern)

Keep in mind that whenever you generate code from CubeMX which requires a new HAL driver file, you will need to manually add that file to the cmake/stm32cubemx_extern/CMakeLists.txt file. For example, if you enable the I2C peripheral in CubeMX and regenerate code, CubeMX will generate the file stm32g4xx_hal_i2c.c. You will then need to add the following line to the cmake/stm32cubemx_extern/CMakeLists.txt file where the other HAL driver files are listed:

${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/extern/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_i2c.c

Adding lib/ Dependencies

To add lib/ dependencies to a CubeMX project, add the following to CMakeLists.txt.

# Add fwlib dependency
add_subdirectory(../../lib fwlib)

# Add linked libraries
target_link_libraries(${CMAKE_PROJECT_NAME}
    stm32cubemx

    # Add user defined libraries
    stm32
    units
    util
)

3. Building and Flashing

You can now build the CMake project as you would normally or by using our build script as described in Getting Started/STM32Cube.