Using VS Code for STM32 development (related to MTE 241 @ UW)

At the University of Waterloo, we have an interesting course, MTE 241, where students are expected to develop their real-time-ish embedded operating system on a NUCLEO-F401RE board.

The only problem is that this course used to require students to use an IDE bloated from Eclipse, which feels anything but natural for a modern developer. ST now provides a VS Code extension for STM32 development, but for this course, we still need to “hack” it a little. The drivers and HAL setup needed for the course are not directly provided by the extension.

This note records the setup that worked for me.

Note: scroll to the bottom for update regarding the starter project for the 2026 offerings

Basic setup

Install the extension STM32CubeIDE for Visual Studio Code in VS Code.

Unfortunately, it does not appear to be available in Code OSS, so you may need the official Microsoft build of VS Code.

After installing the extension:

  • Create a project.
  • Select the correct board, NUCLEO-F401RE.
  • Create a launch option in the debug menu.
  • Select the ST-LINK server option.

On Linux, you also need to make the ST-LINK device accessible to the user. Create the following udev rule:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# /etc/udev/rules.d/80-stm32.rules

SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", MODE="0666"
SUBSYSTEM=="usb_device", ATTRS{idVendor}=="0483", MODE="0666"

# See:
# https://stackoverflow.com/questions/22713834/libusb-cannot-open-usb-device-permission-isse-netbeans-ubuntu
````

Then reload the rules:

```bash
sudo udevadm control --reload-rules
sudo udevadm trigger

You may need to unplug and reconnect the board.

The debugger works relatively well — if you have a huge screen.

The default project is not enough

The default CMake project provided by the extension is not sufficient for our purpose. Specifically, it does not provide the already set-up HAL expected by the course. You still need STM32CubeMX / STM32CubeF4 files.

First, get the template from ST’s STM32CubeF4 repository:

https://github.com/STMicroelectronics/STM32CubeF4/tree/master/Projects/STM32F401RE-Nucleo/Templates

The easiest way is to clone the whole repository:

1
git clone --recurse-submodules https://github.com/STMicroelectronics/STM32CubeF4.git

Then open the template project in VS Code.

When opening the project, there should be a small pop-up asking whether you want to regard this CMake project as an STM32 project. You must select Yes. Otherwise, the tool will not be able to find the required files.

Bringing in the generated board files

Next, use the board selector to download or generate the correct starter project for your board.

Then copy the source and header files from the generated code and replace the ones in the template project.

This part is not exactly elegant, but it gets the project into a shape that matches what the course needs while still letting VS Code understand it as an STM32 project.

If you get an error saying the compiler cannot be found, create a plain project for your board first, then copy everything under its .vscode directory into the template project.

Serial output

To check the board’s output to the serial port, use:

1
minicom -D /dev/ttyACM0

If /dev/ttyACM0 is not the right device, check with:

1
ls /dev/ttyACM*

Always compile in Debug mode

Always compile in Debug mode.

The reason is that compiler optimization will be on in Release mode. The first thing we do in this project is to get MSP_INIT_VAL by dereferencing:

1
*(uint32_t **) 0x0

This is a null pointer according to the C language standard. After optimization, the compiler is free to assume this does not happen, and the generated code may simply break the program.

So unless you have checked the generated assembly and know exactly what is happening, use Debug mode.

Flash without debugging

Sometimes you may want to run the code without starting the debugger.

In .vscode/tasks.json, add:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
{
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "CubeProg: Flash project (SWD)",
"command": "cube",
"args": [
"programmer",
"--connect",
"port=swd",
"--download",
"${command:cmake.launchTargetPath}",
"-hardRst",
"-rst",
"--start"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": [],
"presentation": {
"showReuseMessage": false
}
},
{
"label": "Build + Flash",
"dependsOrder": "sequence",
"dependsOn": [
"CMake: clean rebuild",
"CubeProg: Flash project (SWD)"
],
"problemMatcher": [
"$gcc"
],
"presentation": {
"showReuseMessage": false
}
},
{
"type": "cmake",
"label": "CMake: clean rebuild",
"command": "cleanRebuild",
"targets": [
"all"
],
"preset": "${command:cmake.activeBuildPresetName}",
"group": "build",
"problemMatcher": [],
"detail": "CMake template clean rebuild task",
"presentation": {
"clear": true,
"showReuseMessage": false
}
}
]
}

Then run the Build + Flash task.

Source: https://community.st.com/t5/stm32cubeide-for-visual-studio/run-without-debugging-on-vscode/td-p/796064/page/2

Using Mike’s starter code

Just use STM32cube’s “convert Eclipse project” function. You will still need the setting file and tasks file for easier provessing.

Final note

The setup is a bit awkward because the extension-generated project, the STM32CubeF4 template, and the course’s expected HAL setup do not line up perfectly.

But after the pieces are copied into the right places, VS Code can be used for MTE 241 development without relying on the Eclipse-based IDE.