Getting started

A new (or not so new) plugin for Visual Studio Code (VSCODE) is available that makes debugging the Cortex line of MCUs a breeze. It is called Cortex-Debug by Marcel Ball (Marus). The best thing about Cortex-Debug is it is OSS as well (Github Repo).

For those who don’t know VSCODE is a free and opensource IDE. Paired with the Cortex-Debug plugin, the CPP Tools plugin, the GNU ARM toolchain, and OpenOCD you have a powerful (and importantly free) tool set for the STM32 range of MCUs.

Let’s begin

Start by downloading and installing the necessary parts.

For more specific instructions on setting up the GNU ARM toolchain, please see the Cleanflight documentation.

To make things simple, setup a few environment variables on your system (it will allow easy re-use of config files between projects). OPENOCD which will point to the base directory of your OpenOCD installation, GNUARM which will point to the directory of your ARM toolchain, and you can’t forget your CYGWIN directory. As an example:

OPENOCD=c:/dev/openocd
GNUARM=c:/dev/gcc-arm-6.2
CYGWIN=c:/cygwin

To use these environmwnt variables in the VSCODE config files you use the prepopulated variables ${env:NAME} where “NAME” is the name of the environment variable, e.g. ${env:OPENOCD}.

Install VSCODE

First install the VSCODE, and then add the following extensions:

  • cpptools extension (run the command: ext install cpptools in VSCODE). See here for the tools instructions: ms-vscode.cpptools.
  • Cortex-Debug extension (run the command: ext install cortex-debug in VSCODE). See here for the tools instructions: marus25.cortex-debug.

Making sure you can build

As per the previous VSCODE article before we can get the build working within VSCODE you need to make sure that you can build the repository from the windows command line. See the instructions above (from the cleanflight repo) for the GNU Arm tool chain under cygwin. Before running make you will need to set the Path environment variable to your toolchain, and cygwin e.g. by running: set Path=c:\cygwin\bin;d:\dev\gcc-arm-6.2\bin;%Path%. In Windows I had to get the case-sensitivity exactly right on the Path name of the environment variable for it to work correctly.

You should then be able to build within that command prompt. Note that if you set the path order incorrectly when you are making a target you will likely get a file not found *.c error in the output. This is due to the find command in windows being used instead of the cygwin one.

Installing OpenOCD

The second thing to get working is OpenOCD. First make sure that your ST link device is operation, test using the ST Link Utility, you should be able to read the MCU details etc.

Once you know your ST Link is working, then download and install OpenOCD.

If you get the error libusb_open() failed with LIBUSB_ERROR_NOT_SUPPORTED then you should download the Zadig USB tool, and install the libusbk device driver for the “STM32 Link” device.

Setting up VSCODE to perform the build

VSCODE uses the .vscode directory and json files to configure it. This can be created automatically using the menu options in VSCODE.

The first json file needing to be edited will be the tasks.json, select Tasks|Configure Tasks from the VSCODE menu. Here is the configuration I am using for building the betaflight-ESC code using an STM32F051 discovery board:

{
    "version": "2.0.0",
    "type": "process",
    "presentation": {
        "echo": true,
        "reveal": "always",
        "focus": false,
        "panel": "dedicated"
    },
    "windows": {
        "options": {
            "env": { "Path":"${env:CYGWIN}/bin;${env:GNUARM}/bin;%Path%" }
        }
    },
    "tasks": [
        {
            "label": "build-FISHDRONE",
            "windows": {
                "command": "make.exe",
                "args": [
                    "TARGET=FISHDRONE",
                    "DEBUG=GDB"
                ]
            },
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "problemMatcher": {
                "owner": "cpp",
                "fileLocation": [ "relative", "${workspaceRoot}" ],
                "pattern": {
                    "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
                    "file": 1,
                    "line": 2,
                    "column": 3,
                    "severity": 4,
                    "message": 5
                }
            }
        },
        {
            "label": "clean-FISHDRONE",
            "windows": {
                "command": "make.exe",
                "args": [
                    "TARGET=FISHDRONE",
                    "clean"
                ]
            },
            "problemMatcher": []
        }
    ]
}

This will allow you to CTRL-SHIFT-B and you should see build information displayed in the terminal output window.

Setting up VSCODE to debug

Select Debug|Open Configurations in VSCODE. You will be presented with the launch.json file. Here is the configuration I am using:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "openocd-gdb",
            "request": "launch",
            "name": "Debug Microcontroller",
            "executable": "${workspaceRoot}/obj/main/BFESC_FISHDRONE.elf",
            "configFiles": [
                "${env:OPENOCD}/share/openocd/scripts/board/stm32f0discovery.cfg"
            ],
            "cwd": "${workspaceRoot}",
            "openOCDPath": "${env:OPENOCD}/bin/openocd.exe",
            "preLaunchTask": "build-FISHDRONE"
        }
    ]
}

Note that the prelaunch task name means that it will execute the build task that shares the same label prior to starting the debugger. This will ensure the latest build is always made prior to starting the debugging session. You can now start debugging simply by hitting F5 (or Debug|Start Debugging). Debugging output from OpenOCD will be displayed in the debug console window.

If you experience any errors with launch OpenOCD, you can see the Adapter output in the Output window, under Adapter Output.

Adapter Output

Intellisense updates

The latest versions of VSCODE have an improved intellisense in the cpp-tools extension. This requires some edits of a new c_cpp_properties.json file in the .vscode directory.

This is my configuration for the intellisense for the betaflight esc:

{
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*",
                "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/atlmfc/include/*",
                "C:/Program Files (x86)/Windows Kits/8.1/Include/um",
                "C:/Program Files (x86)/Windows Kits/8.1/Include/shared",
                "C:/Program Files (x86)/Windows Kits/8.1/Include/winrt",
                "${env:GNUARM}/arm-none-eabi/include",
                "${env:GNUARM}/lib/gcc/arm-none-eabi/6.3.1/include",
                "${workspaceRoot}/src/main/target/FISHDRONE_ESC",
                "${workspaceRoot}/src/main/target",
                "${workspaceRoot}/lib/main/STM32F0/Drivers/CMSIS/Device/ST/STM32F0xx/Include",
                "${workspaceRoot}/lib/main/STM32F0/Drivers/CMSIS/Include",
                "${workspaceRoot}/lib/main/STM32F0/Drivers/STM32F0xx_HAL_Driver/Inc",
                "${workspaceRoot}/src/main",
                "${workspaceRoot}"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "USE_HAL_DRIVER",
                "USE_FULL_LL_DRIVER",
                "STM32F051x8",
                "STM32F0"
            ],
            "intelliSenseMode": "msvc-x64",
            "browse": {
                "path": [
                    "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*",
                    "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/atlmfc/include/*",
                    "C:/Program Files (x86)/Windows Kits/8.1/Include/um",
                    "C:/Program Files (x86)/Windows Kits/8.1/Include/shared",
                    "C:/Program Files (x86)/Windows Kits/8.1/Include/winrt",
                    "${workspaceRoot}"
                ],
                "limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            }
        }
    ],
    "version": 3
}

Importantly you can see how to add more directories into the include search locations, and also to set the basic defines that are added in the make file – that VSCODE doesn’t have visibility of (as they are buried in the make file). You can add separate configurations for Mac and Linux also, not just Win32.