This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Visual Studio Code development with gcc and openocd

Hello,

I'm migrating all my projects from Eclipse to VSCode. On Eclipse I used to debug using JLink tools, however I would like to have a more generic tool (not all the devkits I use are equipped with a jlink debugger). I found openocd together with arm-none-eabi-gdb to be a good choice since it supports a number of MCUs and devkits that I use often.

Now, I already made it work for a third party manufacturer's MCU (therefore the installed tools look ok) and I'm trying to do the same for the Nordic's ones but I'm facing problems.

First of all, if I launch openocd from a terminal with the proper parameters (the same used by VScode) everything looks ok. Here the console:

giova@ubuntu-giova:~$ openocd -f board/nordic_nrf52_dk.cfg -c init -c "reset init"
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
openocd.org/.../bugs.html
adapter speed: 10000 kHz
cortex_m reset_config sysresetreq
Info : No device selected, using first device.
Info : J-Link OB-SAM3U128-V2-NordicSemi compiled Jul 24 2017 17:30:12
Info : Hardware version: 1.00
Info : VTarget = 3.300 V
Info : Reduced speed from 10000 kHz to 1000 kHz (maximum).
Info : Reduced speed from 10000 kHz to 1000 kHz (maximum).
Info : clock speed 10000 kHz
Info : SWD DPIDR 0x2ba01477
Info : nrf52.cpu: hardware has 6 breakpoints, 4 watchpoints
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x000008e8 msp: 0x20000400

and if I run arm-none-eabi-gdb and then target remote localhost:3333 it connects to openocd without apparent errors.

However, when I launch the debug configuration from VScode, openocd starts properly (I see the same output of above) but then something goes wrong since gdb doesn't connect and the console tells is:

<-logout
Send Event AD7MessageEvent

Any idea on how to fix it? Unfortunately the console output is not really meaningful and I cannot say what component is complaining.

Davide

PS: my launch.json file is as follow:

{
    "version": "0.2.0",
    "configurations": [  
        {
            "name": "Debug Nordic",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceRoot}/pca10040/s132/armgcc/_build/nrf52832_xxaa.out",
            "args": [],
            "stopAtEntry": true,
            "cwd": "${workspaceRoot}/pca10040/s132/armgcc/",
            "environment": [],
            "externalConsole": false,
            "debugServerArgs":"-f board/nordic_nrf52_dk.cfg -c init -c \"reset init\"",
            "serverLaunchTimeout": 20000,
            "filterStderr": false,
            "filterStdout": false,
            "serverStarted": "target halted due to debug-request, current mode: Thread",
            "preLaunchTask": "build",
            "setupCommands": [
                { "text": "-target-select remote localhost:3333", "description": "connect to target", "ignoreFailures": false },
                { "text": "-file-exec-and-symbols ${workspaceRoot}/pca10040/s132/armgcc/_build/nrf52832_xxaa.out", "description": "load file", "ignoreFailures": false},
                { "text": "-interpreter-exec console \"monitor endian little\"", "ignoreFailures": false },
                { "text": "-interpreter-exec console \"monitor reset\"", "ignoreFailures": false },
                { "text": "-interpreter-exec console \"monitor halt\"", "ignoreFailures": false },
                { "text": "-interpreter-exec console \"monitor arm semihosting enable\"", "ignoreFailures": false },
                { "text": "-target-download", "description": "flash target", "ignoreFailures": false }
            ],
            "logging": {
                "moduleLoad": true,
                "trace": true,
                "engineLogging": true,
                "programOutput": true,
                "exceptions": true
            },
            "linux": {
                "MIMode": "gdb",
                "MIDebuggerPath": "/usr/bin/arm-none-eabi-gdb",
                "debugServerPath": "/usr/local/bin/openocd"
                //"debugServerPath":"/opt/SEGGER/JLink/JLinkGDBServer"
            },
            "osx": {
                "MIMode": "gdb",
                "MIDebuggerPath": "/usr/local/bin/arm-none-eabi-gdb",
                "debugServerPath": "/usr/local/Cellar/open-ocd/0.10.0/bin/openocd"
            },
            "windows": {
                "preLaunchTask": "mbed",
                "MIMode": "gdb",
                "MIDebuggerPath": "C:\\Program Files (x86)\\GNU Tools ARM Embedded\\4.9 2015q3\\bin\\arm-none-eabi-gdb.exe",
                "debugServerPath": "openocd.exe",
                "setupCommands": [
                    { "text": "-environment-cd ${workspaceRoot}\\DISCO_F413ZH\\GCC_ARM\\BUILD" }, //what's this?
                    { "text": "-target-select remote localhost:3333", "description": "connect to target", "ignoreFailures": false },
                    { "text": "-file-exec-and-symbols ${workspaceRootFolderName}.elf", "description": "load file", "ignoreFailures": false},
                    { "text": "-interpreter-exec console \"monitor endian little\"", "ignoreFailures": false },
                    { "text": "-interpreter-exec console \"monitor reset\"", "ignoreFailures": false },
                    { "text": "-interpreter-exec console \"monitor halt\"", "ignoreFailures": false },
                    { "text": "-interpreter-exec console \"monitor arm semihosting enable\"", "ignoreFailures": false },
                    { "text": "-target-download", "description": "flash target", "ignoreFailures": false }
                ]
            }
        },
  
    ]
  }

Parents
  • So, now it works.

    I don't know where the problem was because that launch.json was derived from a working one (it was working with third party ARM device). However, I fixed it by using the Cortex-Debug extension of vscode.

    That extension was actually already installed, however it was not properly used. In fact, in order to use it, the configuration inside the launch.json is required to be "type":"cortex-debug".

    Now the working launch.json is like this:

    {
        "version": "0.2.0",
        "configurations": [
            {
                "name": "Debug Nordic",
                "type": "cortex-debug",
                "request": "launch",
                "servertype": "openocd",
                "executable": "${workspaceRoot}/pca10040/s132/armgcc/_build/nrf52832_xxaa.out",
                "cwd": "${workspaceRoot}",
                "preLaunchTask": "build",
                "runToMain": true, //does not look to work for now
                "debuggerArgs": [
                    "--directory=/home/giova/workspaces/GIT/time_of_flight_ble/nRF5_SDK_14.0.0_3bcc1f7" //not sure it is required
                ],
                "searchDir": ["/usr/local/share/openocd/scripts"],
                "device":"nRF52832_xxAA", //required if "servertype":"jlink",
                //   "svdFile": //used for peripheral view
                //   "swoConfig":{ //see https://marcelball.ca/projects/cortex-debug/cortex-debug-swo-decoding-and-graphing/
                //       "enabled": false,
                //       "swoFrequency": 0,
                //       "cpuFrequency": 0,
                //       "ports":{ //to populate see https://marcelball.ca/projects/cortex-debug/cortex-debug-swo-decoding-and-graphing/
                //       }
                //   },
    
                "graphConfig": [],
                "showDevDebugOutput": true,
                "configFiles": [
                    "board/nordic_nrf52_dk.cfg"
                ],
                "linux": {},
            },
        ]
      }

    This file also requires task.json which defines how to build the project:

    {
        // See https://go.microsoft.com/fwlink/?LinkId=733558
        // for the documentation about the tasks.json format
        "version": "2.0.0",
        "tasks": [
            {
                "label": "build",
                "type": "shell",
    
                "args": [],
                "linux": {
                    "command": "${workspaceRoot}/pca10040/s132/armgcc/build_script.sh" //substitute with "make" for regular builds
                },
            },
    
        ]
    }

    These configuration is just the first one working. Probably there are better ways to configure it (for instance by using only relative paths), nevertheless they can be used as reference.

Reply
  • So, now it works.

    I don't know where the problem was because that launch.json was derived from a working one (it was working with third party ARM device). However, I fixed it by using the Cortex-Debug extension of vscode.

    That extension was actually already installed, however it was not properly used. In fact, in order to use it, the configuration inside the launch.json is required to be "type":"cortex-debug".

    Now the working launch.json is like this:

    {
        "version": "0.2.0",
        "configurations": [
            {
                "name": "Debug Nordic",
                "type": "cortex-debug",
                "request": "launch",
                "servertype": "openocd",
                "executable": "${workspaceRoot}/pca10040/s132/armgcc/_build/nrf52832_xxaa.out",
                "cwd": "${workspaceRoot}",
                "preLaunchTask": "build",
                "runToMain": true, //does not look to work for now
                "debuggerArgs": [
                    "--directory=/home/giova/workspaces/GIT/time_of_flight_ble/nRF5_SDK_14.0.0_3bcc1f7" //not sure it is required
                ],
                "searchDir": ["/usr/local/share/openocd/scripts"],
                "device":"nRF52832_xxAA", //required if "servertype":"jlink",
                //   "svdFile": //used for peripheral view
                //   "swoConfig":{ //see https://marcelball.ca/projects/cortex-debug/cortex-debug-swo-decoding-and-graphing/
                //       "enabled": false,
                //       "swoFrequency": 0,
                //       "cpuFrequency": 0,
                //       "ports":{ //to populate see https://marcelball.ca/projects/cortex-debug/cortex-debug-swo-decoding-and-graphing/
                //       }
                //   },
    
                "graphConfig": [],
                "showDevDebugOutput": true,
                "configFiles": [
                    "board/nordic_nrf52_dk.cfg"
                ],
                "linux": {},
            },
        ]
      }

    This file also requires task.json which defines how to build the project:

    {
        // See https://go.microsoft.com/fwlink/?LinkId=733558
        // for the documentation about the tasks.json format
        "version": "2.0.0",
        "tasks": [
            {
                "label": "build",
                "type": "shell",
    
                "args": [],
                "linux": {
                    "command": "${workspaceRoot}/pca10040/s132/armgcc/build_script.sh" //substitute with "make" for regular builds
                },
            },
    
        ]
    }

    These configuration is just the first one working. Probably there are better ways to configure it (for instance by using only relative paths), nevertheless they can be used as reference.

Children
  • Hello,

    I'm a beginner in embedded programming and I wanted to use the same setup as yours.
    Sadly several months ago I didn't find enough resources and I was stuck trying to integrate GDB and OpenOCD altogether in my VS Code project.
    I temporary gave up and switched to another non-embedded project.

    Would you mind to share a sample project on Github to simply demonstrate how these tools integrate together?
    That would be an interesting resource for the community in my opinion.

    Thanks a lot

  • Dear Koenigs,

    I don't have time to write a complete tutorial but I'll try to write here a brief description on how I managed to do it (I found 99% of the resources by searching with google, the remaining 1% is probably experience). This refers to a linux machine (I tested the same on macOs and it works, but I never tested this on windows).

    First of all you need all the gcc toolchain set up. In other words you need arm-none-eabi-gcc working on your machine, make and all the components to build the .elf file (can be .out in some cases).

    If you have arm-none-eabi-gcc probably you also have arm-none-eabi-gdb, but in order to debug you need also a version of openOCD that works for your target MCU (Nordic DKs are well supported in all the recent versions).

    Then you need vscode and its cortex-debug extension.

    With this in your hand, from vscode open the folder that contains the makefile or the folder you prefer as the "root" of the project and now you can create a debug configuration from vscode, it will create a launch.json. You must modify that file to make it similar to the one I posted above (of course you must fix the "executable" path, and maybe also the configFiles). Moreover, in order to compile the code automatically when you press the debug button you also need the task.json posted above ("command" is simply "make" on regular projects). If you also provide the SVD file for your MCU (I think it is somewhere in the sdk) vscode also have an handy view of the peripheral registers during debug.

    Now, by pressing the debug button it should compile and then bring you to the debug interface where you can do step by step debugging.

    Notes:

    Keep in mind that making this work requires many components developed by a number of independent communities, and when something doesn't work it is not always easy to understand where the problem is and where to look for the solution. I suggest you to test one component at the time from the command line, for instance to test openocd on a nordic dk you should call:

    openocd -f board/nordic_nrf52_dk.cfg

    and look for some positive response, if you get some error you know that it is related to openocd and you won't bother vscode community for that.

    In a similar way you can test arm-none-eabi-gdb. Please search in google a guide to run gdb from command line, in few words you must have the openocd instance running (without errors) and in another terminal you just execute arm-none-eabi-gdb. Once arm-none-eabi-gdb is launched, openocd should print some message informing that a client has connected.

    Once you have all this working, it should work also in vscode, and if it doesn't you have to spend you engineering skills to debug it (this is actually what I do when I start a new project). 

    If you look online there are some tutorials, but I understand that they are not always clear in particular if you have never used vscode. However give it a try, the learning curve is not steep, it took a couple of days for me and I started from zero experience with vscode (but quite a lot of experience in embedded and linux command line).

  • Wow thanks a lot Davide for this complete explanation.

    I understand well how VsCode works now, the difficulty for me is mostly to understand all the embedded tools.

    As I said, for the moment I'm working on another non-embedded project but I'll for sure come read again your comment when I'll be back on embedded stuffs in the future.

    Thanks again

    EDIT: I was at the same time trying to use Zephyr RTOS instead of the Nordic SDK but it's adding even more complexity to the task

Related