CubeMX STM32 Adapter
Turn a CubeMX-generated STM32 project into one you can build, flash and debug
from VS Code — without giving up the ability to regenerate it in CubeMX.
The extension never edits the part of the Makefile that CubeMX owns. Every
change it makes lives in a separate cubemx-adapter.mk, pulled in by a single
-include line appended to the end of the file. Regenerate in CubeMX as often
as you like; if a regeneration drops that line, the extension notices and puts
it back, settings intact.
What it does
Parameterises the build. The toolchain directory, the OpenOCD binary, the
debug probe, the OpenOCD scripts and the flash address all become variables
you can override per invocation:
make TOOLCHAIN_PATH=/opt/gcc-arm/bin/ flashload
Adds flashing and debugging targets driven by OpenOCD: flashload,
flashbin, erase, reset and openocd-server.
Manages what gets compiled. Add or remove .c, .cpp and header files
from the Files tab. CubeMX-owned sources are excluded rather than deleted from
the CubeMX list, so regeneration keeps working. Headers contribute their
directory to the include path.
Compiles C++. Adding a .cpp file switches on the C++ rules, a
configurable -std=, and the C++ runtime in LDFLAGS.
Sets the build options from the Build & Debug tab: optimization level,
debug information, C and C++ standard, -Wextra / -Werror, link-time
optimization, floating point in printf, and free-text compiler and linker
flags. Nothing rewrites a CubeMX line — the flags are appended, and GCC lets
the last -O, -g and -std= win. Each one is an overridable variable, so a
single build can still deviate:
make ADAPTER_OPT=-O0 ADAPTER_LTO=0
Sets up the debug session on the same tab: stop at main or at the reset
vector, and an SWO console on ITM port 0 so printf can go out through the
probe instead of a UART.
Quietens the build log. A CubeMX build echoes several hundred characters
of compiler command line per file, with the warnings that matter buried
between them. Compact build log replaces each with one short line, so a
build reads as its own progress:
CC Core/Src/main.c
CC Core/Src/stm32f4xx_it.c
LD build/sample-project.elf
text data bss dec hex filename
3420 4 1564 4988 137c build/sample-project.elf
Warnings and errors still come through untouched, and make V=1 brings the
full commands back for a single build. Running the build as a VS Code task
additionally shows a progress notification counting the objects as they land.
Shows the peripheral registers while you debug. The STM32 Peripherals
view in the Run and Debug sidebar lists every peripheral from the SVD, each
register decoded into its named bit fields. Values are re-read every time the
core halts. Any writable register or field is edited in the row itself —
click the value, type, press Enter; fields the SVD gives names to become a
drop-down of those names. Escape or clicking away cancels without writing.
Shows where the firmware's bytes went. The Firmware tab reads the linked
.elf and reports how full each memory region from your linker script is,
what the space is spent on, a per-section table and the largest functions and
variables. Initialized data is charged to both flash and RAM, because its
starting values are stored in the image and copied into RAM before main()
runs — the one thing a single "size" number cannot tell you.
Manages preprocessor defines from the Defines tab.
Follows CubeMX on its own. Turn on Keep the project in sync with CubeMX
on the Overview tab and the .ioc and Makefile are watched from then on.
Every regeneration puts the -include hook back and rebuilds the .vscode
files from the new include paths, defines and device — no refresh, no
re-adapt. A regeneration that happened while VS Code was closed is picked up
when the window opens. It re-applies the configuration already recorded in
cubemx-adapter.mk; adapting a project the first time stays a deliberate step.
Writes the .vscode configuration — c_cpp_properties.json,
launch.json (Cortex Debug), tasks.json, settings.json and
extensions.json — from what it found in your project. Configurations you
wrote by hand, and the comments around them, are preserved.
Every operation backs up the files it touches and rolls all of them back if any
step fails. Before the hook is added for the first time, your original
Makefile is copied to Makefile.cubemx-adapter.bak.
Requirements
You need these on your machine; the extension does not install them.
| Tool |
Why |
arm-none-eabi-gcc toolchain |
Compiling and linking |
| GNU Make |
Running the build |
| OpenOCD |
Flashing and the GDB server |
| Cortex Debug |
Debugging with the generated launch.json |
They can be on PATH or pointed at through the settings below.
Getting started
- Open the folder containing your CubeMX project — the one with the
Makefile
and the .ioc beside it.
- Run CubeMX Adapter: Open Home from the Command Palette.
- On the Overview tab, set the toolchain and OpenOCD paths, pick your probe,
and press Adapt.
- Build with
make, flash with make flashload, debug with F5.
make adapter-info prints the configuration the generated makefile resolved to,
which is the fastest way to check a path or a probe setting.
Settings
| Setting |
Default |
Description |
cubemx-adapter.toolchainPath |
"" |
Directory holding the arm-none-eabi-* binaries, e.g. C:/gcc-arm/bin/. Empty resolves through PATH. |
cubemx-adapter.openOcdPath |
openocd |
Path to the OpenOCD executable. |
cubemx-adapter.programmer |
st-link |
Debug probe: st-link, stlink-dap, cmsis-dap or jlink. |
cubemx-adapter.autoSync |
false |
Re-apply the adaptation automatically whenever CubeMX regenerates the project. |
cubemx-adapter.debug.runToMain |
true |
Break at main; off stops at the reset vector. |
cubemx-adapter.debug.swo.enabled |
false |
Route ITM port 0 to a console over SWO. |
cubemx-adapter.debug.swo.cpuFrequency |
0 |
Core clock in Hz; required for SWO. |
cubemx-adapter.debug.swo.frequency |
2000000 |
SWO baud rate in Hz. |
The build options are not settings — they live in cubemx-adapter.mk with the
rest of the project's configuration, so they travel with the repository.
Commands
| Command |
Description |
CubeMX Adapter: Open Home |
Opens the home panel. |
CubeMX Adapter: Refresh Project State |
Re-analyses the workspace. |
CubeMX Adapter: Toggle Automatic CubeMX Synchronization |
Same switch as the one on the Overview tab. |
CubeMX Adapter: Re-read Peripheral Registers |
Re-reads the register view from the halted target. |
What ends up in your project
your-project/
├── Makefile # CubeMX's, plus a 3-line -include at the end
├── Makefile.cubemx-adapter.bak # your original, kept from the first adapt
├── cubemx-adapter.mk # everything the extension manages
└── .vscode/ # IntelliSense, debugging and build tasks
cubemx-adapter.mk is regenerated on every change, so edit it through the
extension rather than by hand. It is readable on purpose — each section explains
what it does and why — so you can check exactly what was added to your build.
Notes and limits
- The file list shows files that exist on disk. Delete one outside the extension
and the next refresh drops it from the build automatically; an entry that
CubeMX still lists keeps its exclusion, because removing it would put a
missing file straight back into the link.
- A project whose
Makefile carries no CubeMX markers is still adapted, but the
extension says so — verify the build before flashing.
-Werror together with -Wextra fails the build on ST's own HAL and LL
drivers, which do not compile warning-free. Those sources cannot be excluded,
so either narrow the warnings with a -Wno-… in the extra compiler flags, or
keep -Werror off.
- The SWO console needs the core clock to match what the target actually runs
at; the probe derives the trace bit rate from it, so a stale value decodes to
nothing.
- Writing a field in the register view writes the whole register back, because
that is what the bus does. A write-1-to-clear flag that happened to be set when
the register was read is cleared as a side effect.
- The register view reads a peripheral only when you expand it. A peripheral
whose clock is off raises a bus fault instead of returning data; the affected
rows say so rather than the view failing.
- Registers declared with
<dim> or inside a <cluster> are left out of the
view. Nothing in the bundled ST catalog uses either, but an SVD from elsewhere
might, and placing such a register at a single address would make the view
write to the wrong one.
- The Firmware tab needs a build to look at, and reports the last one — it does
not build for you. Percentages need a
MEMORY block in the linker script; a
project without one gets absolute sizes instead of percentages.
- The symbol list shows names as the compiler wrote them, so C++ names appear
mangled. A function that was inlined at every call site has no symbol and no
entry, which is why the symbol sizes do not add up to the section total.
License
MIT — see the LICENSE file shipped with the extension.
| |