CMake + CubeMX/CubeCLT Toolchain

Installing

  1. Install CubeMX. This is the .ioc file editor.
  2. Install CubeCLT. This is the command-line toolset that contains all the software necessary to build and deploy the codebase.
  3. Install CubeMCUFinder.
  4. Install the corresponding extension for your editor. In each case, the extension will need to be provided the location to CubeMX and CubeCLT.
    1. CLion
    2. VS Code

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/.

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/extern/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/extern/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_pwr_ex.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/extern/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/extern/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_rcc.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/extern/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_rcc_ex.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/extern/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_flash.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/extern/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_flash_ex.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/extern/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_flash_ramfunc.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/extern/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_gpio.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/extern/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_exti.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/extern/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_dma.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/extern/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_dma_ex.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/extern/STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_pwr.c
    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../lib/extern/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/extern/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

TODO

We should create a script to automate this process of creating and updating the cmake/stm32cubemx_extern/CMakeLists.txt file.

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
)

Building and Flashing

  1. ./scripts/build.sh --src <PROJECT> will build the project
  2. ./scripts/flash.sh --src <PROJECT> will flash the project to the MCU connected to the STLINK

For example, if the project is named myproject and is located in /home/user/mrover-esw/src/, the command to build would be:

./scripts/build.sh --src myproject

Note

In order to use the scripts to build and flash, ensure all */bin directories from CubeCLT are included in $PATH