Skip to content
| Marketplace
Sign in
Visual Studio Code>Debuggers>STM32 Cross Development ContainersNew to Visual Studio Code? Get it now.
STM32 Cross Development Containers

STM32 Cross Development Containers

Meddoks Developments

|
66 installs
| (1) | Free
Containerised build, flash and debug for CubeMX STM32 projects
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

STM32 Cross Development Containers

Build, flash and debug CubeMX STM32 projects inside containers, from VS Code.

Your machine needs Docker and, on Windows, usbipd-win. The compiler, OpenOCD and GDB live in the image — nothing is installed on the host, and a project builds the same way on every machine that opens it.

The problem it removes

A CubeMX project carries a Makefile with an absolute path to whoever generated it, a linker script, and an assumption that the right arm-none-eabi-gcc is somewhere on PATH. Getting a colleague to a working breakpoint usually costs an afternoon, and the result differs from yours in ways nobody notices until the firmware does.

Declare the project once in stm32cdc.json, and the tasks, launch configuration, IntelliSense settings and dev container are generated from it. Your own files are never edited — CubeMX rewrites its Makefile, linker script and sources whenever it regenerates, so everything the tool needs arrives from outside. Regenerating from the .ioc stays a no-op.

Requirements

Docker Desktop on Windows, or the engine on Linux build and debug
usbipd-win Windows only debug only
STM32CubeMX on whoever creates or regenerates the project not needed to build
VS Code 1.85+ with the Dev Containers extension build and debug

Docker and VS Code are needed by everyone. The other two are not: usbipd-win matters only once you want to flash or debug, and CubeMX only on the machine the project is generated on. A colleague who clones the repository and builds it needs neither.

Docker must use the WSL 2 backend on Windows. Not a preference: usbipd attaches the probe into the WSL 2 virtual machine, and the WSL 2 backend runs the Docker engine in that same machine, which is the only reason /dev/bus/usb inside a container has anything in it. With the Hyper-V backend the engine sits in a separate VM, and the probe never reaches it — the build still works, the debugger never finds an adapter. Nothing else about Docker is special: no registry is required, since the image recipe ships inside the extension.

usbipd-win is what forwards the probe, and it is worth knowing how it behaves before it surprises you.

winget install --exact dorssel.usbipd-win

Binding is per USB port, not per device, and the first use of each port raises a UAC prompt — the extension asks for the elevation itself. Attachment is lost on every replug, and whenever a Windows-side tool such as STM32CubeProgrammer claims the device. It must be in place before the container starts: the container takes a snapshot of the USB tree, so a probe attached afterwards is invisible to it until it is rebuilt. Attach debug probe and Diagnose environment report all of this rather than leaving you to infer it. On Linux none of it applies — the probe is already on /dev/bus/usb, and the container mounts it directly.

STM32CubeMX is what makes a project in the first place, and this extension deliberately generates nothing that CubeMX owns. Either toolchain in Project Manager → Toolchain / IDE works, Makefile or CMake, detected rather than configured. What it must leave behind is an .ioc (the device is read from it), the build file for the mode you chose, a linker script and a startup file; Diagnose environment names any of these that is missing and says which generation mode produces it. Only the person regenerating from the .ioc needs CubeMX installed — everyone else builds from what is already in the repository.

Dev Containers is declared as a dependency of this extension, so installing this one installs it too. It is what turns the generated devcontainer.json into a running container; without it that file is read by nothing.

macOS is not supported: Docker Desktop there has no USB passthrough into containers, so debugging cannot work.

Getting started

  1. Get the images — run STM32CDC: Build images from source. The recipe ships inside this extension, so no registry is involved. It downloads a Debian base, its packages and the Arm toolchain; a few minutes, once.
  2. Open a CubeMX project and run STM32CDC: Initialize project. It reads the device from the .ioc and the target from the build files, asks only for the probe and the image tags, and offers to fetch a matching SVD.
  3. Plug in the probe and run STM32CDC: Attach debug probe. On Windows the first use of each USB port raises a UAC prompt — binding needs it.
  4. Open the project in its dev container, then Ctrl+Shift+B to build and F5 to debug.

When something misbehaves, run STM32CDC: Diagnose environment before anything else. It checks the two dozen things that actually go wrong with this stack and names the command that fixes each one.

Prefer pulling to building? Set stm32cdc.imageRegistry to where the images are published and run STM32CDC: Pull images. Pulling is faster and gives everyone a byte-identical image; building is the path that works with no registry at all.

What it supports

  • Both CubeMX project shapes — Makefile and CMake, detected rather than configured.
  • Arm GNU Toolchain 14.3, pinned by version and SHA256.
  • ST-Link, CMSIS-DAP and J-Link, with the probe chosen explicitly when several are connected, remembered per workspace, and by device rather than by USB port — so the choice survives a replug.
  • Peripheral registers, with the SVD matched to your device and fetched on request; CubeMX does not ship one.

Commands

Command
Initialize project Writes stm32cdc.json for a CubeMX project
Project settings A form over that manifest
Init / fix project configuration Regenerates the VS Code and container files
Build project · Clean build output Through the generated tasks
Attach · Detach · Select debug probe usbipd, including the elevation prompt
Add peripheral register view (SVD) Fetches and installs the right SVD
Open project in its dev container Creates the container, checking the probe first
Pull images · Build images from source Either way of getting them
Clean up containers and volumes left behind Stopped dev containers accumulate one per project, and each retired image leaves its extension volume behind
Diagnose environment Start here when something is wrong

All of them are also in the activity bar, grouped by what you are doing, with the state on screen rather than behind a command: which project is active, which build driver it uses, whether an SVD is configured, whether the probe is forwarded right now.

Settings

Setting
stm32cdc.imageRegistry Where released images live, e.g. ghcr.io/acme; enables pulling instead of building
stm32cdc.toolchainTag Toolchain part of the image tag; the version part comes from the extension
stm32cdc.probes vid:pid values treated as debug probes — CMSIS-DAP ids differ per vendor, so add yours
stm32cdc.svdRepository · stm32cdc.svdRef Where SVDs come from, pinned to a commit
stm32cdc.wslDistro Distribution used for the usbipd attach
stm32cdc.showStatusBar · stm32cdc.refreshIntervalSeconds Status bar and how often probe state is polled

stm32cdc.json has a JSON schema registered for that filename, so completion, hover documentation and error checking work without a network round trip. Unknown fields are rejected — the point is to catch a misspelled key, which otherwise fails silently by being ignored.

Known limitations

  • One window reload the first time a dev container is created. VS Code installs the debug extensions after the extension host has started, and devcontainer.json has no way to ask for anything else.
  • An extension can be installed in the container and still disabled, because enablement lives in your client profile, keyed by extension id, and no API can change it. Use Enable (Workspace), which scopes the change to that folder.
  • amd64 only — the Dockerfile uses the x86_64 toolchain tarball.
  • Locally built images are not byte-identical across machines: only the toolchain is pinned by checksum, the Debian packages float. Pull published images when that matters.

How it works, briefly

The extension runs on the host, always — usbipd is a Windows program and the Docker CLI talks to the local daemon, and neither is reachable from inside a dev container. It builds nothing itself: builds go through the generated VS Code task, debugging through Cortex-Debug, and configuration through a generator that lives in the builder image.

That last point is what keeps one build path rather than two. A task runs wherever the window is — on the host for a local folder, inside the container for a remote one — so the same command works in both without knowing which it is in.

Licence

MIT.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft