How to Use Visual Studio Code with Your NetBurner Projects

macOS-universal-download

In one of our recent articles, we explained the functionalities of the NetBurner command-line tools and how they can be used to compile and load applications directly to the NetBurner modules. Visual Studio Code is an excellent freeware tool that can integrate this functionality. It is also currently one of the most popular IDEs among multiplatform developers due to its large number of extensions and custom configurations. Visual Studio Code can be run on Windows, Linux, and macOS.

IoT Dev Kit Featured in this Article

Netburner ARM Cortex M7 embedded Development Kit for IoT product development and industrial automation.

Or, learn more about NetBurner IoT.

Visual Studio Code

In this article, we are going to talk about a basic configuration of Visual Studio Code that will allow you to use the functionalities of the command line. This includes using Tasks, configuring auto-completion, and adding descriptions of functions using IntelliSence. Finally, we’ll also cover some tips that can help to enhance your coding.

Requirements

This article assumes the following:

Getting Visual Studio Code

Visual Studio Code is one of the lightest, most flexible, and most customizable IDE’s that exists today. Its large number of extensions and plugins allows the developers to configure their work environment as it is most comfortable for them, supported by a large community and by particularly good documentation.

To get it, go to the official Visual Studio Code page and download the appropriate version according to your operating system. This is shown below in Figure 1.

Figure 1: Visual Studio Code Download.

Once installed on your operating system, start the IDE.

Figure 2: Visual Studio Code Welcome Page

For this example, we will be using Windows 10 and the example ShowInterfaces, found in the NNDK at \nburn\examples\ShowInterfaces. We will also be using the MODM7AE70. To open it, click on the “File->Open Folder” menu option, and select the example folder, as shown in Figure 3.

Figure 3: Open Folder

Once the folder is selected in the “Explorer” window, the files that are in the example folder will appear, as shown in Figure 4.

Figure 4: Explorer Section

Before we go any further, let’s make sure that we can build the application normally with the command line tools. Fortunately, Visual Studio Code has the option of having terminals integrated into the IDE, to open it click on the Terminal> New Terminal option, as shown in Figure 5.

Figure 5: Open a New Terminal

A command terminal will open at the bottom of the IDE using the folder example address, as shown in Figure 6.

Figure 6: The Terminal Through Visual Studio Code

In this terminal you can test the command line tools presented in the article Building Applications with NetBurner Command Line Tools. For example, we are going to execute the fundamental command, make -j, which will compile the ShowInterfaces example. The –j flag allows for multi-job builds, which significantly speeds up compilation time.

Figure 7: Running make -j

If everything is installed correctly, the terminal will begin to show a list of commands running (makefile magic). After a few minutes, we will be able to see the result of the compilation, as shown in Figure 8.

Figure 8: A Successful Build

And yeah… this is nice, but it’s nothing to brag about. So far, we have not done more than test one of the NetBurner command line tools. We could have easily done this without installing any software, and by using our command line directly. In the following sections, we will dive into in-depth explanations of some of the more interesting features of Visual Studio Code.

Integrating Command Line in VS Code via Tasks

Before continuing, we will be required to install a Visual Studio Code extension that will allow us to develop C/C++ applications. To install an extension, click on the “Extensions” option in the left side menu. Then, in the extensions search bar, write “c/c++”. Underneath the search bar, all of the extensions that match the search pattern will appear. From this list, choose the first option (more than 21.4M downloads) and press the “Install” button, as shown below in Figure 9.

Figure 9:Install C/C++ Extension

Once installed, return to the “Explorer” section and create a folder in the root of the example with the name “.vscode”. To create the folder, click on the “New Folder” option from the top menu, as shown in Figure 10.

Figure 10: Create Folder
Figure 11: Create File

Inside this folder, create a file called “tasks.json”. To do this, click on the “.vscode” folder and click on the menu option “New File”, as shown in Figure 11.

Inside the “tasks.json” file, add the following code. This includes some of the command line functionality grouped into JSON objects that can be executed from Visual Studio Code directly. Save the file with the <CTRL>+<S> shortcut.

				
					// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
{
  "version": "2.0.0",

  "tasks": [
    {
      "label": "Build Project",
      "type": "shell",
      "command": "make -j",
      "options": {
        "cwd": "${workspaceFolder}"
      },
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "problemMatcher": {
        "base": "$gcc",
        "fileLocation": [
          "relative",
          "${workspaceFolder}"
        ]
      }
    },
    {
      "label": "Build & Load Project",
      "type": "shell", 
      "command": "make -j load DEVIP=192.168.0.100",
      "options": {
        "cwd": "${workspaceFolder}"
      },
      "problemMatcher": {
        "base": "$gcc",
        "fileLocation": [
          "relative",
          "${workspaceFolder}"
        ]
      }
    },
    {
      "label": "Build Debug Project",
      "type": "shell",
      "command": "make -j debug",
      "options": {
        "cwd": "${workspaceFolder}"
      },
      "problemMatcher": {
        "base": "$gcc",
        "fileLocation": [
          "relative",
          "${workspaceFolder}"
        ]
      }
    },
    {
      "label": "Build Debug & Load Project",
      "type": "shell",
      "command": "make -j loaddebug DEVIP=192.168.0.100",
      "options": {
        "cwd": "${workspaceFolder}"
      },
      "problemMatcher": {
        "base": "$gcc",
        "fileLocation": [
          "relative",
          "${workspaceFolder}"
        ]
      }
    },
    {
      "label": "Clean Project",
      "type": "shell",
      "command": "make clean",
      "options": {
        "cwd": "${workspaceFolder}"
      },
      "problemMatcher": {
        "base": "$gcc",
        "fileLocation": [
          "relative",
          "${workspaceFolder}"
        ]
      }
    },
    
    {
      "label": "Run addr2line tool",
      "type": "shell",
      "command": "arm-eabi-addr2line -Cife obj/release/NetburnerBase.elf ${input:addr2line}",
      "options": {
        "cwd": "${workspaceFolder}"
      },
      "problemMatcher": {
        "base": "$gcc",
        "fileLocation": [
          "relative",
          "${workspaceFolder}"
        ]
      }
    },
  ],
  "inputs": [
    {
      "id": "addr2line",
      "type": "promptString",
      "description": "Enter the address to search"
    }
  ]
}
				
			

Here is a short description of the fields in the “tasks.json” file:

  • “label”: Friendly name to identify the task.
  • “type”: This is set to the Shell (Console) type because the command to be executed will be of the bash, cmd, or Powershell type, depending on the operating system.
  • “command”: Command to be executed by this task.
  • “options”: {"cwd": "$ {workspaceFolder}"}: Specifies the current directory.
  • “group”: {"kind": "build", "isDefault": true}: Specifies the group to which this task belongs. Note that there can only be one task in the “isDefault:true” group, and it is executed with the <CTRL> + <SHIFT> + <B> shortcut.
  • “problemMatcher”: {"base": "$ gcc", "fileLocation": ["relative", "$ {workspaceFolder}"]}: Assigns the problem matcher for GCC, which scans the output from the terminal commands for errors, alerts, or build information.

To run the tasks, just click on the “Terminal-> Run Task” option in the top menu, as shown in Figure 12.

Figure 12: Running a Task

A pop-up window will appear with the tasks available in the project.

Figure 13: Application Tasks
Task Description
Build Project Run the make -j command. This is used to compile the program. It can be executed with the <CTRL> + <SHIFT> + <B> shortcut.
Build & Load Project Run the command, make -j load DEVIP=xx.xx.xx.xx. This is used to compile the program and load it into the module. Note: The IP address must be changed manually to the IP of the module used.
Build Debug Project Run the command, make -j debug. It is used to compile the program in debugger mode.
Build Debug & Load Project Run the command make -j loaddebug DEVIP=xx.xx.xx.xx. This is used to compile the program in debugger mode, and then load it into the module. Note: The IP address must be changed manually to the IP of the module used.
Clean Project Run the make clean command. This is used to clean the result of previous compilations.
Run addr2line tool Run the command arm-eabi-addr2line -Cife obj/release/<name>.elf <dir>. This is used to map a memory address to a line of code from the application. (More information on this can be found in the article Tracking Traps on the MODM7AE70 – Part 1). Note: The name of the application must be changed manually. When executing this task, Visual Studio Code will request the search address to be entered.

When choosing a task to execute (in this case Build Project was chosen), a new tab will appear in the terminal section. This is where the command of the selected task will be executed. This is shown below in Figure 14.

Figure 14: Task Execution

To test the error detection functionality, we are going to purposefully cause an error in the application code. To do this, open “main.cpp”. This can be found in the folder, “src”, from the “Explorer” window. Add an error in the file, as shown in Figure 15 (console.log() is a JavaScript function, and isn’t available in C/C++). Note that when opening the file, it will show some errors related to the C/C++ extension saying that certain header files could not be found. These errors will be removed later. For now, we will focus on the GCC compilation error.

Figure 15: Adding an Error to the Code

Because console.log() only exists in JavaScript, compiling the example (running the task from Terminal> Run Task or by pressing the <CTRL> + <SHIFT> + <B> shortcut) triggers the error which is displayed in the “Problems” tab. It also marks the line in which the error is located, as we see in Figure 16, below.

Figure 16: Problem Matcher in Action

We already have Visual Studio Code configured and the tasks setup to compile and load our code onto a NetBurner module. However, we still have a problem in that it cannot find the header files . We are going to solve this once and for all by giving it a superpower: code completion and code hinting with IntelliSense.

Adding Superpowers: IntelliSense

I would dare to say that this is one of the most important tools to use Visual Studio Code. I won’t lie to you, Eclipse also has a similar function, but it is not as powerful as VS Code. I have always said that the developer’s best friend is code completion. This is especially true if you are a bit dyslexic like me. But enough talk, let’s get to work.

Inside the folder “.vscode”, create a file called, “c_cpp_properties.json”. In it add, the following code, and save the file with the <CTRL>+<S> shortcut:

ARM Based Platforms

				
					{
    "env": {
      "NB_PATH": "C:/nburn"
    },
    "configurations": [
      {
        "name": "Netburner MODM7",
        "cStandard": "c11",
        "cppStandard": "c++17",
        "browse": {
          "path": [
            "${workspaceFolder}",
            "${NB_PATH}"
          ],
          "limitSymbolsToIncludedHeaders": false
        },
        "includePath": [
          "${workspaceFolder}",
          "${workspaceFolder}/src",
          "${workspaceFolder}/**",
          "${NB_PATH}/gcc/arm-unknown-eabi/sys-include/",
          "${NB_PATH}/arch/cortex-m7/cpu/SAME70/include",
          "${NB_PATH}/arch/cortex-m7/include",
          "${NB_PATH}/gcc/arm-unknown-eabi/include",
          "${NB_PATH}/gcc/arm-unknown-eabi/include/c++/8.1.0",
          "${NB_PATH}/gcc/arm-unknown-eabi/include/c++/8.1.0/arm-unknown-eabi",
          "${NB_PATH}/gcc/arm-unknown-eabi/include/c++/8.1.0/backward",
          "${NB_PATH}/gcc/arm-unknown-eabi/sys-include/**",
          "${NB_PATH}/gcc/lib/gcc/arm-unknown-eabi/8.1.0/include",
          "${NB_PATH}/gcc/lib/gcc/arm-unknown-eabi/8.1.0/include-fixed",
          "${NB_PATH}/libraries/include",
          "${NB_PATH}/nbrtos/include",
          "${NB_PATH}/platform/MODM7AE70/include"
        ],
        "intelliSenseMode": "gcc-arm"
      }
    ],
    "version": 4
  }
				
			

ColdFire Based Platforms

				
					{
  "env": {
    "NB_PATH": "${NNDK_ROOT}"
  },
  "configurations": [
    {
      "name": "Netburner MOD5441X",
      "cStandard": "c11",
      "cppStandard": "c++17",
      "browse": {
        "path": 
            "${workspaceFolder}",
            "${NB_PATH}"
        ],
        "limitSymbolsToIncludedHeaders": false
      },
      "includePath": [
        "${workspaceFolder}",
        "${workspaceFolder}/src",
        "${workspaceFolder}/**",
        "${workspaceFolder}/overload",
        "${NB_PATH}/gcc/m68k-unknown-elf/sys-include",
        "${NB_PATH}/arch/coldfire/cpu/MCF5441X/include",
        "${NB_PATH}/arch/coldfire/include",
        "${NB_PATH}/gcc/m68k-unknown-elf/include",
        "${NB_PATH}/gcc/m68k-unknown-elf/include/c++/8.1.0",
        "${NB_PATH}/gcc/m68k-unknown-elf/include/c++/8.1.0/m68k-unknown-elf",
        "${NB_PATH}/gcc/m68k-unknown-elf/include/c++/8.1.0/backward",
        "${NB_PATH}/gcc/m68k-unknown-elf/sys-include/**",
        "${NB_PATH}/gcc/lib/gcc/m68k-unknown-elf/8.1.0/include",
        "${NB_PATH}/gcc/lib/gcc/m68k-unknown-elf/8.1.0/include-fixed",
        "${NB_PATH}/libraries/include",
        "${NB_PATH}/nbrtos/include",
        "${NB_PATH}/platform/MOD5441X/include"
      ],
      "intelliSenseMode": "${default}"
    }
  ],
  "version": 4
}
				
			

Here is a short explanation of the fields in this file:

  • “env”: {"NB_PATH": "c: / nburn"}: Path where NNDK is installed.
  • “name”: Name of the configuration.
  • “cStandard” / “cppStandard”: Standard versions of C and C ++ used.
  • “browse”: {"path": […,…]}: Addresses to search for declarations and definitions.
  • “includePath”: […]: Addresses in which the files and libraries used are stored.

Saving the file with these changes automatically resolves the errors that we had in the previous section. This is because VS Code now knows where to look for the header files. From now on we can position the cursor on a function and see its documentation. Because NetBurner uses Doxygen to document its code and VS Code recognizes the Doxygen syntax natively, you’ll usually see the function description along with its associated parameters and return values.

Figure 17: Documentation with Doxygen syntax.

In addition, when we start writing something, the editor will give us recommendations for possible parts of the code that we want to write.  Just choose the desired option from the pop-up menu and press the TAB key for the code to complete itself.

Figure 18: Code Hinting and Code Completion

Another handy feature can be observed if you hold down the CTRL key and position the cursor on a function. This will show you the content of that function.

Figure 19: Function Peeking

There are several other important features that are also available. These can be found by right clicking on a function. Some of the most useful are:

  • Go to Definition: Open the .c/.cpp file where the function definition is located.
  • Go to Declaration: Open the .h file where the function declaration is located.
  • Peek Definition / Peek Declaration: Opens a pop-up window with the declaration or definition of the function.
Figure 20: Declarations and Definitions

More Information

Wrapping Up

Hopefully this information will help all those developers who prefer to use Visual Studio Code in their applications and projects, especially those who program in multiple languages and who like to customize their work environment. If you have some tricks of the trade on how to use Visual Studio Code, we would love to hear it! Let us know in the comments below. If you have any other questions or issues, please feel free to email us directly at sales@netburner.com.

In a future post we will talk about another key piece of Visual Studio Code functionality: Debugging using GDB. Stay tuned!

About the Author

Jordan Garcia, IoT and industrial protocols engineer at Racom Microelectronics.

Dog lover, bookworm, and sweet tooth. Fan of embedded systems, back-end and front-end development and a constant joy in learning new things. Special ability: to finding bugs in systems.

Share this post

Subscribe to our Newsletter

Get monthly updates from our Learn Blog with the latest in IoT and Embedded technology news, trends, tutorial and best practices. Or just opt in for product change notifications.

Leave a Reply
Click to access the login or register cheese