StmEpic  2.334
Device and algorithms library for microcontrollers for quick Robotics designs
Getting started

This page will guide you through the process of setting up the project for STM32 microcontrollers with:

  • C++,
  • FreeRTOS,
  • Cmake
  • StmEpic library
  • STM32CubeMX code generation tool
  • ccache

Requirements

Compiler:

Building the project requires GNU Arm Embedded Toolchain to be installed.

  1. Download it from this site GNU Arm Embedded Toolchain Downloads or directly from this link
  2. Extract the downloaded file,
tar -xf ~/Downloads/arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi.tar.xz
  1. Move the extracted folder to some directory for example "$HOME/.local/share",
mv arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi ~/.local/share/arm-gnu-toolchain-14
  1. Add this in your **_.profile_** file
# Add the arm-none-aebi to the path
if [ -d "$HOME/.local/share/arm-gnu-toolchain-14/bin" ]; then
PATH="$HOME/.local/share/arm-gnu-toolchain-14/bin:$PATH"
fi
  1. Restart the PC or run
source ~/.profile

Software:

  1. You will most likely need to install the following packages:
sudo apt-get install -y cmake ninja-build clang ccache dfu-util stlink-tools python3-pip python3-venv
  1. Install the StmCubeIDE you can install it from official site.
  2. Install the StmCubeMX you can install it from official site.
  3. Install the STM32CubeProgrammer you can install it from official site.

How to add the library to your project

  1. Clone the repository to your project directory as submodule:
git submodule add https://github.com/X-Lemon-X/StmEpic.git src/StmEpic
git submodule update --init --recursive
  1. Add the following line to your CMakeLists.txt file:
add_subdirectory(StmEpic)
target_link_libraries( <YOUR_PROEJCT_NAME> PUBLIC stmepic)
  1. Now you can simply include header files.
  2. Remember that StmEpic requires definitions provided by HAL library which are added by STM32CubeMX generator, so sometimes with minimal project you might have to enable manually some hardware interfaces in stm32yyxx_hal_config.h file.

Generating the project from scratch

We won't go into many details since there is many guides on how to use STM32CubeMX. In this example we assume that the you project name is the same as the folder where the project is located.

  1. Open the StmCubeMX click File->New Project.
  2. Select appropriate microcontroller, in this case [for this example] it is **_STM32F446RET_**.
  3. Configure the peripherals and their pinout in [Pinout & Configuration] tab.
  4. Enable FreeRTOS in [Pinout & Configuration]->[Middleware] tab with CMSIS V2, in Advanced settings set USE_NEWLIB_REENTRANT to ENABLED.
  5. Configure clock in [Clock Configuration] tab.
  6. In [Project Manager] tab set: Toolchain/IDE to **_CMake_** Project Name to **_project_name_**. Project location to **_<path where you repo is>/.. **. The CubeMX IDE doesn't allow relative paths, so if you set something incorrectly you might have to copy the project ***.ioc_** along with generated files to your repo folder. If that happened reopen the **_*.ioc_** in the folder with CubeMX and the current path will be set automatically.
  7. Save the project and generate the code using the GENERATE CODE button
  8. In you repo folder there should be bunch of new folders and files like:
- CMakeLists.txt
- cmake/
- Core/
- Drivers/
- Middlewares/
- project_name.ioc
- startup_stm32yyxx.s
- src
...
  1. The project is configured to be built with CMake, However the C++ language is not enabled yet so We still have to add our libraries and source files to the project. Check the next section for more details (Adding C++ support).

Adding C++ support

  1. In cmake/stm32cubemx/CMakeLists.txt find main.c and replace it with main.cpp
  2. Create some heder file that will have single function that will be called in the main.cpp file to enter our part of the program since We don't wont to touch files generated by CubeMX. For example:
//creat file src/main_prog.hpp with content:
#pragma once
void main_prog();
//creat file src/main_prog.cpp with content:
#include "main_prog.hpp"
void main_prog(){
// Your code here like your tasks, drivers, etc.
// Do not start FreeRTOS kernel here since it will
}
  1. in main.cpp add the following code:
// in include section
#include "main_prog.hpp"
// in main function bofore while(1)
osKernelInitialize() // This will be generated by CubeMX
//... some default task by cube mx
// call the function to enter your part of the program
main_prog(); // <---- your start function here
osKernelStart(); // This will also generated by CubeMX
  1. Now you can add your source files and libraries to the project. Since the generated fields and outer code is separated We don't have to worry with StmCubeMX messing with our files.
  2. Since the StmEpic library requires interface provided by the HAl library. If you generate minimalistic project you might not be able to build it, since not all HAL library components are enabled by default. To fix this you have to enable the HAL library in the **_Core/Inc/stm32f4xx_hal_conf.h_** file (or something similar). The file should look like this:
/* #define HAL_CRYP_MODULE_ENABLED */
/* #define HAL_ADC_MODULE_ENABLED */
#define HAL_CAN_MODULE_ENABLED
/* #define HAL_CRC_MODULE_ENABLED */
/* #define HAL_CAN_LEGACY_MODULE_ENABLED */
/* #define HAL_HASH_MODULE_ENABLED */
#define HAL_I2C_MODULE_ENABLED // This might need to be enabled manually
/* #define HAL_I2S_MODULE_ENABLED */
/* #define HAL_IWDG_MODULE_ENABLED */
/* #define HAL_LTDC_MODULE_ENABLED */
/* #define HAL_RNG_MODULE_ENABLED */
/* #define HAL_RTC_MODULE_ENABLED */
/* #define HAL_SAI_MODULE_ENABLED */
/* #define HAL_SD_MODULE_ENABLED */
/* #define HAL_MMC_MODULE_ENABLED */
#define HAL_SPI_MODULE_ENABLED // This might need to be enabled manually
#define HAL_TIM_MODULE_ENABLED // This might need to be enabled manually
#define HAL_UART_MODULE_ENABLED // This might need to be enabled manually
//...
  1. Now you should be able to build the project with CMake
cmake -B build -G Ninja
cmake --build build

Adding source files and libraries in CMakeLists.txt

There are highlighted section in the CMakeLists.txt file where you can add your source files and libraries.

cmake_minimum_required(VERSION 3.22)
#
# This file is generated only once,
# and is not re-generated if converter is called multiple times.
#
# User is free to modify the file as much as necessary
#
# Setup compiler settings
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)
############################################################################################################
# C++ Configuration [1/4]
set(CMAKE_CXX_STANDARD 20)
# Define the build type
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()
# Set the project name
set(CMAKE_PROJECT_NAME YOUR_PROJECT_NAME_HERE)
set(PROJECT_MAJOR_VERSION 0)
# Include toolchain file
include("cmake/gcc-arm-none-eabi.cmake")
# Enable compile command to ease indexing with e.g. clangd
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
# Enable CMake support for ASM and C languages
enable_language(CXX C ASM)
# Core project settings
project(${CMAKE_PROJECT_NAME})
message("Build type: " ${CMAKE_BUILD_TYPE})
# Create an executable object type
add_executable(${CMAKE_PROJECT_NAME})
set(STMEPIC_MIN_VERSION_REQUIRED_ENABLED ON)
set(STMEPIC_MIN_VERSION_REQUIRED 2.330)
add_subdirectory(src/StmEpic)
message(INFO "Linker flags: " ${CMAKE_C_LINK_FLAGS})
# Add STM32CubeMX generated sources
add_subdirectory(cmake/stm32cubemx)
# Link directories setup
target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE
# Add user defined library search paths
)
# Add sources to executable
target_sources(${CMAKE_PROJECT_NAME} PRIVATE
# Add user sources here
src/main_prog.cpp
src/main_callbacks.cpp
)
# Add include paths
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
# Add user defined include paths
Core/Inc
src
)
# Add project symbols (macros)
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE
# Add user defined symbols
)
# Add linked libraries
target_link_libraries(${CMAKE_PROJECT_NAME}
stm32cubemx
stmepic
)
############################################################################################################
# Configure nice task to make life easy [4/4]
find_program(CCACHE_PROGRAM ccache)
if(NOT CCACHE_PROGRAM)
message(STATUS "ccache not found")
else()
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_PROGRAM}")
endif()
add_custom_command(
TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O binary ${CMAKE_PROJECT_NAME}.elf firmware.bin
COMMAND ${CMAKE_OBJCOPY} -O ihex ${CMAKE_PROJECT_NAME}.elf firmware.hex
COMMAND ${CMAKE_SIZE} ${CMAKE_PROJECT_NAME}.elf
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_PROJECT_NAME}.elf firmware.elf
COMMAND ${CMAKE_SOURCE_DIR}/scripts/update-software-version.sh ${CMAKE_SOURCE_DIR} ${PROJECT_MAJOR_VERSION}
# Show ccache statistics
)
if(CCACHE_PROGRAM)
add_custom_command(
TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND ${CCACHE_PROGRAM} -s
)
endif()

Example project using the StmEpic library