Skip to content

Repository files navigation

HelloSTM32

Learning STM32 MCUs through a C23 project wired for test-driven development using Unity and CMock. All dependencies are fetched automatically via CMake FetchContent — no manual installation required beyond the tools listed below.

Development

CMake

The CMake build automatically downloads the ARM GNU toolchain into .tools/ on first configure if it is not already present. No manual toolchain setup needed.

Configure:

cmake -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE=cmake/arm-none-eabi-toolchain.cmake

Build:

ninja -C build

To target a different MCU (default is STM32U545xx):

cmake -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE=cmake/arm-none-eabi-toolchain.cmake \
      -DTARGET_MCU=STM32H503xx

Supported MCUs are defined in cmake/MCU.cmake. Add an elseif block there to support a new device.

Optional: Symlink compile_commands.json to the root directory for clangd/ccls.

Linux

ln -sfn ./build/compile_commands.json .

Windows (requires admin)

New-Item -ItemType SymbolicLink -Path "compile_commands.json" -Target "./build/compile_commands.json"

Docker Container

Linux:

docker build --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g) -t hellostm32 .

Windows:

docker build -t hellostm32 .

Run container:

docker run -it --rm -v "$(pwd):/app" hellostm32

Testing

Logic modules are unit-tested on the host with Unity + CMock, without any ARM toolchain. HAL-dependent code is isolated in src/hal/ and src/sys/; all logic modules are platform-free.

Run the test suite:

cmake -B build/test && cmake --build build/test --target check

Generate a coverage report (requires Clang):

cmake -B build/cov -DENABLE_COVERAGE=ON && cmake --build build/cov --target coverage

On Windows, add -G Ninja to the coverage configure step so CMake selects Clang instead of MSVC (MSVC does not support --coverage).

Flashing

You can flash your firmware onto the target MCU using various tools. Choose the one that matches your hardware/debug adapter.

stlink

Download stlink.

st-flash write build/firmware.bin 0x8000000

Windows

If you're downloading through the github release page make sure to copy the stlink directory under Program Files (x86) in the zip file to the real Program Files (x86).

And you'll also need to download libusb and put the dll either in the same path as stlink binaries or expose it in the system path environment.

OpenOCD

openocd -f interface/stlink.cfg -f target/stm32u5x.cfg \
        -c "program build/firmware.elf verify reset exit"

Debugging

OpenOCD

CMake targets are provided for all common workflows:

cmake --build build --target flash   # build and flash firmware
cmake --build build --target debug   # start OpenOCD GDB server on :3333
cmake --build build --target gdb     # connect arm-none-eabi-gdb to :3333

debug and gdb are meant to run in separate terminals — start debug first, then gdb.

Equivalent manual commands:

openocd -f interface/stlink.cfg -f target/stm32u5x.cfg
arm-none-eabi-gdb \
  -ex "target remote :3333" \
  -ex "load" \
  -ex "monitor reset init" \
  build/firmware.elf

Zed

Zed's built-in debugger connects to OpenOCD via GDB. Requires a GDB build with DAP support (GDB 14+) and multi-architecture support. Install gdb-multiarch for your platform:

WindowsMSYS2 UCRT64:

pacman -S mingw-w64-ucrt-x86_64-gdb-multiarch

Linux:

sudo apt install gdb-multiarch

macOS:

brew install gdb

Create .zed/settings.json with the path to the installed binary:

Platform Path
Windows C:/msys64/ucrt64/bin/gdb-multiarch.exe
Linux /usr/bin/gdb-multiarch
macOS /opt/homebrew/bin/gdb
{
  "dap": {
    "GDB": {
      "binary": "<path from table above>",
    },
  },
}

Create .zed/debug.json:

[
  {
    "label": "Debug firmware (OpenOCD)",
    "adapter": "GDB",
    "request": "launch",
    "program": "$ZED_WORKTREE_ROOT/build/firmware.elf",
    "gdb_args": [
      "-ex",
      "target remote :3333",
      "-ex",
      "load",
      "-ex",
      "monitor reset init",
    ],
  },
]

Start OpenOCD first, then launch the debugger in Zed:

# Terminal — keep this running
cmake --build build --target debug

Then use Run > Start Debugging or the debug panel and select Debug firmware (OpenOCD).

Segger J-Link

JLinkGDBServer -device STM32U545RET6 -if SWD -speed 4000
arm-none-eabi-gdb -ex "target remote localhost:3333" -ex "load" -ex "monitor reset init" -ex "b main" -ex "c" build/firmware.elf

Follow the same step as the openocd.

Resources

You'll need an account if you want to download anything from ST.

Tutorials

Hardware

AArch32 bare-metal target (arm-none-eabi)

About

Learning STM32 MCUs

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Contributors

Languages