Minimal Zephyr boilerplate for STM32 (nucleo_f103rb) with a single blinky app.
- One build system:
west+ CMake/Ninja (Zephyr standard) - One app source file:
app/src/main.c - One board target:
nucleo_f103rb - One manifest with only required STM32 modules (
cmsis_6,hal_stm32)
Install these once per laptop/workstation:
- Python 3.10+
- uv
- Git
- CMake
- Ninja
- DTC (Device Tree Compiler)
- Zephyr SDK (with ARM toolchain)
- stlink tools (
st-flash) for flashing (default in this repo) - OpenOCD (optional fallback flasher)
Example package install commands:
# macOS (Homebrew)
brew install git uv cmake ninja dtc stlink openocd# Ubuntu/Debian
sudo apt update
sudo apt install -y git cmake ninja-build device-tree-compiler stlink-tools openocd python3 python3-venvFrom the repository root:
uv venv .venvActivate virtual environment:
# macOS/Linux
source .venv/bin/activate# Windows PowerShell
.venv\Scripts\Activate.ps1Install project Python tools and fetch Zephyr workspace:
uv pip install west
python -m west init -l app
python -m west update
uv pip install -r zephyr/scripts/requirements.txtNotes:
- The workspace is pinned in
app/west.yml(Zephyrv4.3.0). - Manifest allowlist is intentionally small:
cmsis_6,hal_stm32.
From repo root, with venv active:
python -m west build -p always -b nucleo_f103rb appBuild artifact used for flashing:
build/zephyr/zephyr.bin
macOS/Linux:
./flash.shAny platform with st-flash installed:
st-flash --connect-under-reset write build/zephyr/zephyr.bin 0x08000000python -m west flash --runner openocdIf python -m west flash tries stm32cubeprogrammer by default and fails, use --runner openocd explicitly as above.
eps/
├── app/
│ ├── CMakeLists.txt
│ ├── prj.conf
│ ├── src/main.c
│ └── west.yml
├── flash.sh
└── README.md
Use three terminal sessions from repo root:
# Board 1 (sender: node 0x01)
./.venv/bin/python -m west build -p always -b nucleo_f103rb app -- -DCONF_FILE="prj.conf;node_a.conf"
st-flash --connect-under-reset write build/zephyr/zephyr.bin 0x08000000# Board 2 (receiver: node 0x02)
./.venv/bin/python -m west build -p always -b nucleo_f103rb app -- -DCONF_FILE="prj.conf;node_b.conf"
st-flash --connect-under-reset write build/zephyr/zephyr.bin 0x08000000# Board 3 (receiver: node 0x03)
./.venv/bin/python -m west build -p always -b nucleo_f103rb app -- -DCONF_FILE="prj.conf;node_c.conf"
st-flash --connect-under-reset write build/zephyr/zephyr.bin 0x08000000Expected logs:
- Sender prints
TX broadcast seq=.... - All boards print
RX src=1 broadcast=1 ...for each broadcast frame. - Unicast demo messages continue to print with
broadcast=0.
Use the helper script to monitor all connected boards with [1]/[2]/[3] labels:
./.venv/bin/python monitor.pyOptional explicit ports:
./.venv/bin/python monitor.py --ports /dev/cu.usbmodem11203 /dev/cu.usbmodem11303 /dev/cu.usbmodem11403