As you may seen throughout my previous posts, I have embarked on a journey to modernize embedded software development tools. I’m committed to breaking the status quo and proving that those working in the embedded field don’t have to resort to decades-old, outdated ecosystems and tools.
You might ask why change something that has worked for years and has become the “standard” across the industry. Well, true - but to be honest, they have never worked well at the first place. You could either opt for a (usually) free vendor tool which is (usually) a bloatware and it (usually) comes with outdated toolchains. On the top, integrating a non-vendor-issued debug probe that has proper debugging capabilities requires some considerate amount of hair-pulling (or it’s straight out impossible). On the other hand, you could shell out thousands of $$$ (per year) for an IAR or Keil license, which at least work nicely out of the box and they provide good debugging capabilities. On the flipside, you are stuck with an editor that was already considered outdated in the ’80s.
There are so many great and modern tools out there available. Many of them have become de facto standards in software engineering. Some of these tools are open-source and are being actively developed, plus they have great community support. However, they haven’t become popular in the embedded software world (yet). I’m fully committed to change that.
This repository contains a project template for STM32-based firmware projects. It features a modern, CMake-based build system, documentation generation with Doxygen, source code formatting with clang-format, linting, enforcing style and naming conventions with clang-tidy, devcontainer, proven and scalable folder organization and more.
The project template runs on a STM32L496 Discovery board out of the box. By default, the debug configuration is set up with a SEGGER J-Link debug probe. SEGGER offers a tool to convert the onboard ST-Link debugger on Discovery and Nucleo boards into a SEGGER J-Link debugger. The onboard ST-Link debugger on the STM32L496 Discovery board used in this project was converted to a J-Link debugger with this tool.
Read more, clone or fork the project at my GitHub repository:
akospasztor/stm32-project-template
Automatically generated Doxygen documentation:
https://akospasztor.github.io/stm32-project-template/
Pipeline status:
requirements.txt
file contains packages that are used for style checks.
It is highly recommended to install and run the python packages in a python
virtual environment (virtualenv).Note: In case the GCC for ARM or the clang-tools are not available in your PATH
(e.g. you have multiple, different versions installed), you can specify the
toolchain paths in the respective toolchain .cmake
file.
Command | Description |
---|---|
cmake --list-presets |
List all CMake presets |
cmake --preset Debug |
Configure the project for Debug build |
cmake --build --preset Debug |
Build the firmware with Debug build type |
cmake --build --preset Debug --target clean |
Clean the Debug target |
cmake --build --preset Debug --target check-format |
Check source code formatting with clang-format |
cmake --build --preset Debug --target run-format |
Run source code formatting with clang-format |
cmake --build --preset Debug --target tidy |
Perform analysis and style check with clang-tidy |
cmake --build --preset Debug --target doxygen |
Generate documentation with Doxygen |
Supported CMake configurations and build presets:
Preset | Description |
---|---|
Debug |
Debug preset for debugging, without any optimization enabled |
Release |
Release preset with O3 optimization |
MinSizeRel |
Release preset with Os optimization for size with link time optimization enabled |
RelWithDebInfo |
Release preset with O2 optimization with debug information |
The project has a CMake-based build system that allows seamless execution of all build-related tasks regardless of environment. The build system commands can be executed directly from the command line and can also be integrated into the IDEs and editors that support CMake (e.g. Visual Studio Code). It also works both locally and in a remote environment, such as in a container or a continuous integration (CI) pipeline.
See to the Usage section for the supported build types and built-in CMake build targets.
The source code is documented with Javadoc style comment blocks. The documentation output is generated with Doxygen. The output html files are automatically deployed to GitHub pages after a successful merge to the default branch.
Source code formatting can be checked with clang-format. The check verifies that
the source code conforms to the formatting guidelines contained in the
.clang-format
file. The source code can also be reformatted with the
appropriate command (see the Usage section) to conform to the
formatting guidelines.
Clang-tidy is used for basic linting of the source code. In addition, this tool also checks and enforces naming conventions and style violations.
The requirements.txt
file contains packages that are used for style checking.
Editorconfig-checker
is used to check that all files in the repository conform to the .editorconfig
file. Flake8 and
yamllint packages are used to
enforce style guides for python and yaml files respectively.
These style checking tasks are not part of the build system, however they are run as part of the CI pipeline.
The continuous integration (CI) pipeline is set up with GitHub Actions. It runs automatically on every git push and has the following stages:
The repository contains a devcontainer file that enables development inside a container. The development container uses the akospasztor/docker-gcc-arm Docker image.
The project includes C/C++ configuration presets, debug launch presets and CMake presets for Visual Studio Code. The following extensions are recommended for the best development experience:
stm32-project-template
├── .devcontainer
├── .github
│ └── workflows
├── .vscode
├── build
├── cmake
│ ├── microcontrollers
│ ├── toolchains
│ └── tools
├── docs
│ └── doxygen
├── include
├── lib
│ ├── CMSIS
│ └── STM32L4xx_HAL_Driver
├── mcal
│ └── st-stm32l4
│ ├── gcc-arm
│ ├── include
│ ├── source
│ └── svd
├── project
│ └── ozone
├── script
└── source
The .devcontainer
folder contains the devcontainer file which enables
development inside a container.
The .github
folder contains the GitHub Actions workflow file which describes
the CI pipeline that runs automatically on every git push operation.
Upon building the project, a build
folder is created. All build-related files
and output binaries are located in the build
folder, organized into
subfolders. Each build target and their respective output files have their own
subfolder. The generated Doxygen documentation output files are also located in
the build
folder.
The cmake
folder contains the files related to the CMake-based build system,
including the toolchain and microcontroller-specific files.
The docs
folder contains the doxygen configuration file (Doxyfile) and other
documentation-related static files.
The application-level source code and corresponding header files are located in
the source
and include
folders respectively.
The lib
folder contains all third-party code, including the CMSIS (Cortex
Microcontroller Software Interface Standard) as well as the HAL (Hardware
Abstraction Layer) drivers from ST.
The mcal
folder stands for Microcontroller Abstraction Library. This folder
contains the microcontroller-specific files and drivers. These drivers are
interfaced by the application source code and they function as tiny wrappers
around the low-level (HAL) drivers. This allows the application to interface
these thin wrappers instead of the manufacturer-specific low-level code, thus
providing easy portability across different chips and microcontrollers.
The project
folder contains SDK- and debugger-specific files organized into
subfolders.
The script
folder contains helper scripts related to the project and the build
system.