on 2025-01-31 8:00 AM
The STM32 VS Code extension doesn’t natively support OpenOCD, but with some simple configuration, you can integrate it into your debugging workflow. This article covers how to set up OpenOCD (either Streamline or ST’s fork) with the extension by modifying the launch.json
file, allowing you to maintain a consistent GDB server setup across tools and frameworks like Zephyr.
Using VS Code for STM32 development offers a powerful and flexible environment for embedded projects, with the added advantage of being cross-platform, running seamlessly on Windows, macOS, and Linux. However, while the STM32CubeCLT is designed to integrate closely with the STM32 VS Code extension, it doesn’t include STMicroelectronics' fork of OpenOCD by default. This omission can pose challenges for developers who prefer OpenOCD, as it’s widely used in other tools and frameworks.
Despite this, VS Code’s robust flexibility and extensive customization options make it a great choice for automating workflows, including building, flashing, and debugging STM32 projects. The combination of VS Code and STM32CubeCLT is especially powerful for integrating CI/CD workflows, enabling developers to standardize their toolchains across operating systems while maintaining consistency and efficiency. In this article, I’ll guide you through the steps to configure the STM32 VS Code extension to work with OpenOCD. This helps you to take full advantage of an efficient and versatile development environment.
In this article, I use a Nucleo-U083RC with the STM32 VS Code extension found in the VS Marketplace. I’m working in a Linux environment, but all content covered here is the same across different operating systems.
When customizing the STM32 VS Code extension, you have two main options for OpenOCD: the community-maintained Streamline version or STMicroelectronics' fork. Both are capable of supporting debugging with STM32 devices, but there are key differences to consider:
Both options are valid, but developers targeting newer STM32 chips or features might prefer ST’s fork to ensure seamless support. Those working across diverse platforms may choose Streamline for its broader integration.
For this article I use ST's fork of OpenOCD which is included with STM32CubeIDE, albeit heavily buried in the file system.
This article assumes preexisting knowledge on how to use the STM32 VS Code extension to build and debug projects.
For a quick refresh you can watch and read these short tutorials:
First, we can start off by making a simple project. For this article a Nucleo-U083RC is used, and the project made is based off of the board selector.
We initialize all the BSP peripherals code to their defaults.
The important bit here is that we set Toolchain/IDE to CMake so that we can import this project into the STM32 VS Code extension
Generate the project and import it using the STM32 VS Code extension per the video tutorial seen here.
Add simple blink LED code into the main function so we can have a visual representation that the code is running on our hardware
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
BSP_LED_Toggle(LED_GREEN);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
You can now launch a debug session per the tutorial video above and verify everything works as expected.
The launch.json
file in VS Code is used to configure debugging sessions, specifying how the debugger connects to your target device. For STM32 development, this file defines parameters such as the GDB server, target interface, and any specific initialization commands. By customizing launch.json
, you can adapt your debugging setup to work with different tools, like OpenOCD, and tailor the experience to your specific requirements.
In the image below, you'll notice that the available debug sessions, [Build & Debug Microcontroller - ST-Link] and [Attach to Microcontroller - ST-Link] correspond directly to the two configurations defined in the launch.json
file. The name
element in each configuration determines what appears in the dropdown menu for selecting a debug session.
Before we can modify the json file we need to get our hands on a configuration file that is generated by STM32CubeIDE, since it does support OpenOCD by default.
In the code below, I’ve added the entire launch.json as not to cause confusion about json syntax. The only new item is the last section is the OpenOCD debug session. I’ll go over each element below.
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Build & Debug Microcontroller - ST-Link",
"cwd": "${workspaceFolder}",
"type": "cortex-debug",
"executable": "${command:cmake.launchTargetPath}",
// Let CMake extension decide executable: "${command:cmake.launchTargetPath}"
// Or fixed file path: "${workspaceFolder}/path/to/filename.elf"
"request": "launch",
"servertype": "stlink",
"device": "STM32U083RCTx", //MCU used
"interface": "swd",
"serialNumber": "", //Set ST-Link ID if you use multiple at the same time
"runToEntryPoint": "main",
"svdFile": "${config:STM32VSCodeExtension.cubeCLT.path}/STMicroelectronics_CMSIS_SVD/STM32U083.svd",
"v1": false, //Change it depending on ST Link version
"serverpath": "${config:STM32VSCodeExtension.cubeCLT.path}/STLink-gdb-server/bin/ST-LINK_gdbserver",
"stm32cubeprogrammer":"${config:STM32VSCodeExtension.cubeCLT.path}/STM32CubeProgrammer/bin",
"stlinkPath": "${config:STM32VSCodeExtension.cubeCLT.path}/STLink-gdb-server/bin/ST-LINK_gdbserver",
"armToolchainPath": "${config:STM32VSCodeExtension.cubeCLT.path}/GNU-tools-for-STM32/bin",
"gdbPath":"${config:STM32VSCodeExtension.cubeCLT.path}/GNU-tools-for-STM32/bin/arm-none-eabi-gdb",
"serverArgs": [
"-m","0",
],
//"preLaunchTask": "Build + Flash"
/* If you use external loader, add additional arguments */
//"serverArgs": ["--extload", "path/to/ext/loader.stldr"],
},
{
"name": "Attach to Microcontroller - ST-Link",
"cwd": "${workspaceFolder}",
"type": "cortex-debug",
"executable": "${command:cmake.launchTargetPath}",
// Let CMake extension decide executable: "${command:cmake.launchTargetPath}"
// Or fixed file path: "${workspaceFolder}/path/to/filename.elf"
"request": "attach",
"servertype": "stlink",
"device": "STM32U083RCTx", //MCU used
"interface": "swd",
"serialNumber": "", //Set ST-Link ID if you use multiple at the same time
"runToEntryPoint": "main",
"svdFile": "${config:STM32VSCodeExtension.cubeCLT.path}/STMicroelectronics_CMSIS_SVD/STM32U083.svd",
"v1": false, //Change it depending on ST Link version
"serverpath": "${config:STM32VSCodeExtension.cubeCLT.path}/STLink-gdb-server/bin/ST-LINK_gdbserver",
"stm32cubeprogrammer":"${config:STM32VSCodeExtension.cubeCLT.path}/STM32CubeProgrammer/bin",
"stlinkPath": "${config:STM32VSCodeExtension.cubeCLT.path}/STLink-gdb-server/bin/ST-LINK_gdbserver",
"armToolchainPath": "${config:STM32VSCodeExtension.cubeCLT.path}/GNU-tools-for-STM32/bin",
"gdbPath":"${config:STM32VSCodeExtension.cubeCLT.path}/GNU-tools-for-STM32/bin/arm-none-eabi-gdb",
"serverArgs": [
"-m","0",
],
/* If you use external loader, add additional arguments */
//"serverArgs": ["--extload", "path/to/ext/loader.stldr"],
},
{
"name": "OpenOCD",
"cwd": "${workspaceFolder}",
"type": "cortex-debug",
"executable": "${command:cmake.launchTargetPath}",
"request": "launch",
"servertype": "openocd",
"serverpath": "/home/eddie/st/stm32cubeide_1.16.0/plugins/com.st.stm32cube.ide.mcu.externaltools.openocd.linux64_2.3.200.202404091248/tools/bin/openocd",
"configFiles": [
"debugConfig.cfg"
],
"serverArgs": [
"-s","${env:SCRIPTS_PATH}",
"-d3"
],
"device": "STM32U083RCTx",
"runToEntryPoint": "main",
"svdFile": "${config:STM32VSCodeExtension.cubeCLT.path}/STMicroelectronics_CMSIS_SVD/STM32U083.svd",
"showDevDebugOutput": "raw"
}
]
}
Here’s a breakdown of each element in the OpenOCD
configuration section in launch.json
a lot of the settings are copied over from the default configurations, like device name and SVD path etc.
name
: Specifies the name of the debug configuration, which appears in the VS Code dropdown menu when selecting a debug session.cwd
: Defines the working directory for the debugging session. ${workspaceFolder}
sets it to the root of your project.type
: Indicates the debugger type, with cortex-debug
used for STM32 development.executable
: Specifies the path to the compiled binary to be debugged, resolved dynamically with ${command:cmake.launchTargetPath}
.request
: Determines the type of debugging session, where "launch"
starts the program and "attach"
connects to a running process.servertype
: Specifies the type of GDB server to use, set to "openocd"
for OpenOCD debugging.serverpath
: Defines the path to the OpenOCD executable. Using ${env:SERVER_PATH}
allows you to set this path via an environment variable. Here you set the path to your streamline OpenOCD or the ST fork.configFiles
: Lists OpenOCD configuration files, which define target-specific settings like the MCU type and debugging interface.serverArgs
: Additional arguments for OpenOCD, such as -s
to specify the search path for OpenOCD scripts (for example, ${env:SCRIPTS_PATH}
for flexibility) and -d3
to set the debug verbosity level. Here, the path varies if you are using the streamline OpenOCD or the ST fork.device
: Specifies the target STM32 microcontroller to ensure proper initialization for debugging.runToEntryPoint
: Defines the entry point function where debugging pauses automatically, typically set to "main"
.svdFile
: Path to the system view description (SVD) file for the MCU, which provides peripheral register definitions for enhanced debugging.showDevDebugOutput
: Controls the verbosity of debug output in the VS Code debug console, with "raw"
showing unprocessed output from the debugger.At this point, you should be able to debug you application per usual.
While the STM32 VS Code extension doesn’t officially support OpenOCD by default, the flexibility of VS Code allows developers to integrate tools like OpenOCD with a bit of configuration. This adaptability ensures you can create a tailored debugging setup that works seamlessly across different frameworks and tools. By taking advantage of this flexibility, you can streamline your workflow and maintain consistency, whether you’re working on STM32 projects or across multiple embedded platforms. With your environment now configured, you’re ready to debug efficiently and focus on building great solutions. Happy debugging!