VS Code for Embedded Development

Embedded development has always lagged behind the trends that drive the rest of software development. In some ways, that’s a good thing. There are fewer half-baked third-party libraries to integrate with, for instance. However, there are also some good things left behind that could really benefit embedded developers.

One area that has always been less than satisfying is the development environment—specifically, the editors that are used. Many embedded devs are stuck in a pattern of using an IDE that allows them to build, debug, and test the system they are creating or supporting. But it’s a fallacy that all of these things need to be pre-integrated. Doing so can lead to an end solution that is hugely over-bloated and frequently expensive.

Years ago, I started using Sublime Text for embedded development. This broke me out of the aforementioned cycle and opened up many possibilities.

At the time, I was trying to survive using a janky Eclipse-based IDE on a new embedded project when the vendor picked it as the basis for their IDE. I remember how much more satisfying my development was with Sublime Text, though that solution is fading away these days.

Fortunately, Microsoft’s Visual Studio Code (VS Code) has incorporated many of the nice-to-haves and the extensibility on Sublime Text. Therefore, I’ve decided to use VS Code as my editor and development environment.

Though this took some trial and error, I am very happy with my decision. I thought it would make sense to share my experience and setup with those of you who are curious.

Syntax-Highlighting, Navigation, and Completions–Oh MY!

I prefer to use syntax highlighting support to decrease the load on my brain. Easy navigation around the codebase and any libraries I am using is also important to me, and I rely heavily on the completion of function and field names in data structures.

Fortunately, ms-vscode.cpptools accomplishes all of the above, and it doesn’t take a ton of work to get it set up to work with your project.

I’ve included a mocked-up configuration file below, which should give you the basic idea of how to set up paths, #defines, and any coding standards you want to enforce. The CppTools configuration file is in JSON format and should be named “c_cpp_properties.json” and placed in the “.vscode/” folder in the root of your project. That way, it will be shared with all developers via source control.

 {
  "configurations": [
    {
      "name": "My Configuration",
      "includePath": [
        "${workspaceFolder}/",
        "${workspaceFolder}/src/**"
      ],
      "defines": [
        "MY_DEFINE",
        "FOO=bar"
      ],
      "compilerPath": "path/to/compiler",
      "cppStandard": "c++17",
      "cStandard": "c99"
    }
  ],
  "version": 4
}

No More Arguing about Formatting

Another annoying thing about software development, especially compiled languages, is how much everyone argues about how to format your code. There are so many different options: tabs vs. spaces, tab width, indentation, where to put parens and braces…ARGH!!!

Instead, use a code formatting tool to solve this problem at the get-go, and you will save yourself and your team members a lot of frustration and time.

My team decided to try out the clang-format extension, and we have been very happy with it. In order to configure clang-format, simply create a file named “.clang-format” in the root of your repo and configure to your liking. Here is my configuration:


---
Language: C
BasedOnStyle: LLVM
ColumnLimit: 120
TabWidth: 2
ContinuationIndentWidth: 2
IndentWidth: 2
UseTab: Never
SortIncludes: false
IndentCaseLabels: true
AllowShortFunctionsOnASingleLine: false

But What about Debugging!?!?

The biggest thing that ties embedded developers to a given IDE is the debugging facilities, as they change significantly from one IDE to another. This change can ensure that you throw money at a particular vendor for years to come.

I have recently started playing with the Cortex-Debug extension, which is designed for ARM Cortex-based micro-controllers and primarily targets the ARM GCC toolchain. While still a work-in-progress, it is easy to add support for new micro-controllers, and it supports the most popular JTAG debuggers out there.

Here is the “launch.json” file I am using, which is the standard way to configure a debugging tool for VS Code.


{ "version": "0.2.0",
  "configurations": [ {
    "type": "cortex-debug",
    "request": "launch",
    "servertype": "jlink",
    "cwd": "${workspaceRoot}",
    "executable": "build/artifacts/release/brake_monitor.elf",
    "name": "Debug (J-Link)",
    "device": "EFR32FG14PxxxF256",
    "svdFile": "${workspaceRoot}/.settings/EFR32FG14P233F256GM48.svd",
    "interface": "swd",
    "runToMain": true,
    "internalConsoleOptions": "openOnSessionStart",
    "swoConfig": { "enabled": true } 
    } ] 
} 

Wrapping It Up

Though there are a few instabilities, VS Code is proving to be a successful editing and development environment. The fact that it’s cross-platform gives it some significant legs going forward.

The C/C++ navigation and completion can sometimes be finicky, but it works pretty well. Overall, it is significantly better than Eclipse, and more easily extensible than Vim or other lightweight editors.

I’d love to hear others’ experiences with stretching the limits of VS Code. It has been a pretty solid platform for me for several projects now.