Bare-metal C++20 SDK for STM32 microcontrollers with optional FreeRTOS support. CMSIS only, no HAL/LL. Drivers, sensors, and project templates are designed for deterministic startup, explicit configuration, and predictable footprint.
Builds are gated by -Werror with -Wall -Wextra -Wpedantic -Wshadow —
both for the SDK itself and for every project generated by stmtool. See
Build flags for the policy.
Preferred installation (uses pipx, pins to the latest released tag, configures shell completion automatically):
./install.shAlternatively, from a working checkout:
pip install ./tools/stmtoolCreate and flash your first project:
stmtool project create my-blink --chip STM32F407VG
cd my-blink
stmtool build
stmtool flashBuilds run inside the SDK Docker image; artifacts land in out/.
The full reference is published on GitHub Pages: https://khosta77.github.io/stm32-sdk/ — available in English (default) and Русский.
Source lives under docs/ and is built with MkDocs Material. To preview locally:
pip install -r tools/docs/requirements.txt
mkdocs serve- Docker — all builds run inside the SDK image, which ships the pinned ARM
toolchain (
arm-none-eabi-gcc15.2, GCC >= 14 is required for C++20 module dependency scanning) plus the hostg++used for the unit tests python>= 3.10 (forstmtool)st-flash(optional, for flashing via ST-Link)pipx(recommended, for isolatedstmtoolinstallation)
A local arm-none-eabi-gcc is no longer required; if present, it must be
GCC >= 14 (stmtool doctor verifies this).
| Command | Description |
|---|---|
stmtool project create <name> --chip <chip> |
Create new project from a template |
stmtool project create <name> --chip <chip> --template <tpl> |
Pick a specific template |
stmtool project create <name> ... --with-claude |
Also generate a CLAUDE.md tailored to the template |
stmtool project templates |
List available templates |
stmtool build |
Build project in Docker (artifacts in out/) |
stmtool build --clean |
Clean the out/ directory before building |
stmtool test |
Build and run the SDK host unit tests in Docker |
stmtool flash |
Flash firmware via st-link |
stmtool sdk update [--version <tag>] |
Update cached SDK to a release tag or develop |
stmtool sdk list-versions |
List available SDK versions (git tags) |
stmtool sdk path |
Print the resolved SDK root path |
stmtool doctor |
Check development environment |
stmtool completion <shell> |
Generate shell completion script |
stmtool version |
Show stmtool version |
| Variable | Description |
|---|---|
STMSDK_PATH |
Path to SDK repository (auto-detected or cached at ~/.stmtool/stm32-sdk/) |
STMTOOL_LANG |
UI language: en (default), ru |
Drivers (sdk/drivers/):
- GPIO, I2C, UART (interrupt and DMA TX), SPI, DMA stream wrapper, internal flash
- All MMIO access goes through
driver::reg::set/clear/write/read/get/modifyhelpers - Configs use designated initializers with compile-time validation (
gpio({...}))
Sensors (sdk/sensors/):
sensor.mpu6050— 6-axis IMU (I2C, accelerometer + gyroscope + temperature)sensor.ssd1306— 128×64 OLED display (I2C, framebuffer + 5×7 font)sensor.w25q32— 32 Mbit SPI flash (IExternalFlashinterface)
FreeRTOS helpers (sdk/rtos/):
rtos::Task,rtos::Mutex,rtos::SemaphoreRAII wrappersheap_4configuration, 16 KB heap by default
| Template | What it demonstrates |
|---|---|
bare-metal/blink |
LED on PD12 via SysTick; minimal startup + linker scripts |
bare-metal/i2c-scan |
I2C bus scanner with USART2 output (no FreeRTOS) |
bare-metal/unit-test-demo |
On-device ASSERT_/EXPECT_ unit tests with a UART-reporting runner |
freertos/blink |
FreeRTOS task controlling LED |
freertos/mpu6050-uart |
MPU6050 sampling at 10 Hz, USART2 TX via DMA |
freertos/oled-display-test |
SSD1306 with uptime counter and static text |
freertos/w25q32-flash-test |
W25Q32 round-trip: erase, page-program, read, verify |
freertos/imu-flash-oled-demo |
MPU + OLED + W25Q32 on one board, built on the system component framework |
freertos/signal-bus-demo |
Two components decoupled through a type-safe signal bus on one SingleThreadExecutor |
freertos/button-events-demo |
EXTI button → deferred debounce Timer → ring signal Channel → LED, with a component owning its task |
| Family | RAM | CCM | Flash | Example |
|---|---|---|---|---|
| STM32F401 | 64-96K | - | 128-512K | STM32F401CC, STM32F401RE |
| STM32F405 | 128K | 64K | 512-1024K | STM32F405RG |
| STM32F407 | 128K | 64K | 512-1024K | STM32F407VG |
| STM32F411 | 128K | - | 256-512K | STM32F411CE |
| STM32F412 | 256K | - | 512-1024K | STM32F412VG |
| STM32F429 | 192K | 64K | 512-2048K | STM32F429ZI |
| STM32F439 | 192K | 64K | 512-2048K | STM32F439ZI |
| STM32F446 | 128K | - | 256-512K | STM32F446RE |
Flash size is determined from chip name (letter at position 11: B=128K, C=256K, E=512K, G=1024K, I=2048K).
Starting with v0.1.4 only STM32F407VG is validated in CI (the maintainer's
physical hardware). F401/F411 etc. remain supported by the SDK code but
are not regression-tested.
Each project pins the SDK version in stmproject.toml:
[sdk]
version = "develop" # tracks origin/develop, or set a tag like "0.1.2"To update the SDK cache for the current project:
stmtool sdk update # use [sdk] version from stmproject.toml
stmtool sdk update --version 0.1.2 # explicit tag
stmtool sdk list-versions # show available tagsWhen upgrading across versions, check https://khosta77.github.io/stm32-sdk/migration/ for any source-side changes your project must make.
stm32-sdk/
sdk/
cmake/ CMake toolchain and family configs
core/ Cortex-M runtime, newlib, linker scripts
hal/stm32f4/ STM32F4 CMSIS headers, vectors, memory layout
drivers/ GPIO, I2C, UART, SPI, DMA, flash drivers
sensors/ MPU6050, SSD1306, W25Q32 implementations
rtos/ FreeRTOS wrappers
templates/ Project templates
tools/stmtool/ Python CLI tool
tools/docs/ MkDocs build dependencies
docs/ MkDocs source (en/ru via suffix mode)
docker/ Build environment Dockerfiles
Generated project layout:
my-project/
src/main.cpp Application code
CMakeLists.txt Build configuration
stmproject.toml Project config (chip, SDK pin, flash tool, etc.)
CLAUDE.md Optional, when --with-claude is passed
.gitignore
Tags follow SemVer (vX.Y.Z). The project is currently pre-1.0 — public APIs may
still be refined. The single source of versioning is git tags (resolved via
poetry-dynamic-versioning for stmtool, starting v0.1.4). Release notes live
in docs/release.md.
See CONTRIBUTING.md: install the pre-commit hooks
(pip install pre-commit && pre-commit install --hook-type pre-commit --hook-type commit-msg), keep to Google 2-space / 80-column C++ style
(clang-format pinned to 19.1.3), write English Conventional Commits, and open
pull requests against develop with a Russian description.
- Create
sdk/cmake/families/stm32XX.cmakewith astm32XX_get_chip_infofunction - Add CMSIS device headers to
sdk/hal/stm32XX/include/cmsis/ - Create vector tables in
sdk/hal/stm32XX/src/cmsis/ - Create
sdk/hal/stm32XX/ldscripts/mem.ld.in
MIT