Skip to main content

Setting up Zephyr and NCS

Author: Tim de Laat, Company: I-IKIGAI, Date: Sep 3, 2021

To get started with nRF Connect SDK development. Follow step 1 to 4 from this guide of the manual installation of the nRF Connect SDK and install the latest version of nRF Connect SDK (at the moment v1.6.1).

Step 5 (for Windows):#

Download Windows 32-bit ZIP package of GNU Arm Embedded Toolchain version 9-2019-q4-major it in directory c:\gnuarmemb in Windows.

In Windows, search to "edit environment variables for your account". This should open a System Properties window in the "Advanced" label. In the bottom right corner, there is a button with "Environment Variables...". Click on it to open the Environment Variables windows. There under the User variables you must add three new User Variables.

Variable name: ZEPHYR_TOOLCHAIN_VARIANT
Variable value: gnuarmemb
Variable name: GNUARMEMB_TOOLCHAIN_PATH
Variable value: C:\gnuarmemb
Variable name: ZEPHYR_BASE
Variable value: C:\Users\{user}\ncs\zephyr

With the third user variable, replace {user} with your username. Also, if you stored the Zephyr or gnuarmemb on different locations, modify the paths accordingly.

After this step restart your computer to load the new variables.

Step 5 (for Linux):#

Download GNU Arm Embedded Toolchain version 9-2019-q4-major for your operating system Windows 32-bit ZIP package on Windows and Linux x86_64 Tarball on Linux). Extract it directory c:\gnuarmemb in Windows or ~/gnuarmemb on Linux.

Open a terminal and enter nano ~/.bashrc which among other this holds your environment variables.. Go to the end of the file, there add the following lines:

export ZEPHYR_TOOLCHAIN_VARIANT="gnuarmemb"
export GNUARMEMB_TOOLCHAIN_PATH="/home/{user}/gnuramemb"
export ZEPHYR_BASE="/home/{user}/ncs/zephyr"

Save the file (ctrl+x โ†’ y โ†’ Enter).

Then enter in the terminal source ~/.bashrc to load the new environment variables.

Step 6 & 7#

Skip step 6 (Install the SEGGER Embedded Studio Nordic Edition) and 7 (Set up the build environment in SES) as you will use VS Code for the development. Nordic has a preference for using Segger Embedded studio for Zephyr development. But in my experience, it is more difficult and takes more time to use than other IDE. My preference goes to VS Code.

In Zephyr development, a big part is to setup and edit the CMake (CMakeLists.txt) and configuration files (Kconfig and prj.conf) and devicetree files (.devicetree and .overlay) files. This is harder and takes more time to do in Segger.

After the guide:#

Install the latest version of nRF Command line tools (nrfjprog) for your operating system. Click here to go to the download page.

Setting up VS Code:#

To setup Zephyr development for VS Code (open-source variant of Visual Studio), first download the IDE (if you don't have it installed already). Follow this link to download the IDE. Then you need a couple of extension to start working on the Zephyr project.

Go to the extensions tab (top left tabs, or click Ctrl+Shift+X). There search for the following extensions:

  • C/C++
  • DeviceTree for the Zephyr Project
  • Kconfig for the Zephyr Project
  • CMake

For VS Code intellisense, look bottom of this document.

Building your first project#

In this example, I show how to build and flash the modem shell.

  1. Open the AT Client example (ncs/nrf/sample/nrf9160/modem_shell) in VS Code (in terminal you can enter code ~/ncs/nrf/sample/nrf9160/modem_shell.
  2. Open the integrated terminal in VS Code (`Ctrl+`` or click F1 to search menu and search Toggle Terminal).
  3. You will use West to build and flash your projects. When it is the first time building the project, you have to define a board. In that case enter: west build --board nrf9160dk_nrf9160ns or west build -b nrf9160dk_nrf9160ns. This will first compile all your config and CMake files (prj.conf and CMakeLists.txt and .overlay), and then compile all the code. This can take minute to compile. After this, you can just enter west build in the integrated terminal. This will also create a build directory. When using Git, make sure this entire directory is added to your .gitignore file.

This will only rebuild the added/modified files (which means much quicker build times). If you modify a CMakeLists.txt, prj.conf of a nrf9160dk_nrf9160ns.overlay file, it will recompile the whole project and this takes a while. If you need to modify the board or want to recompile for a clean build, you can use add -p or --pristine to the west build (west build -p -b nrf9160dk_nrf9160ns). 4. To flash your code, make sure the nrf91 DK is connected via a usb cable. Also make sure the PROG/DEBUG switch is set to nRF91 . Then in your integrated terminal, type west flash . This will flash the software to the nrf9160 and your good to go. 5. The next step is to connect the nrf9160 to a serial monitor (On Windows I recommend using MobaXTerm, on Linux Screen but you are free to use whatever you like). You can see that three new COM Ports popped up, this is because multiple devices with com port functionality are present on the DK. Usually, this is the first port is used by the nrf9160, but try the ports out and see whichever posts data when you flash it or press the reset button. The baudrate is 115200. Once connected, you can hit TAB to see the available commands of the shell. 6. The final step is to just play around in the shell, and try out different commands.

Get started with building your own project#

To get started with building your project, I recommend copy a sample project that closest resembles what you want to build (i.e., you want to use mqtt on the nrf9160dk, copy "mqtt_simple" in nrf9160 samples folder). The destination of the copy does not matter as the CMakeLists.txt uses the environment variables set in step 5 of this guide. If the folder already has a build folder, rebuild the project using the -p or --pristine argument.

From there, start adding/removing things to the project. Try looking at other examples how those projects did things. Uses as many features provided by Zephyr and nRF Connect SDK as possible as this will save you a lot of time. For function descriptions look at Nordic drivers, Nordic Libraries, Nordic Protocols and Zephyr API. And for additional information look at the Nordic and Zephyr documentation websites.

When you want to add a new .c file to the project, go to CMakeLists.txt , and there in the line target_sources(app PRIVATE src/main.c), add after src/main.c a space or enter and add the path to the new file relative to the file CMakeLists.txt. As example if you add the file hello_world.c in src directory, then your target_sources would could look like:

target_sources(app PRIVATE src/main.c src/hello_world.c)

For header .h files, you don't have to add them individually. You just have to include the directory in which the .h files are present using target_include_directories(app PRIVATE ) under the target_sources command. If you add hello_world.h to the include directory, a part of CMakeLists.txt would look like this:

target_sources(app PRIVATE src/main.c src/hello_world.c)
target_include_directories(app PRIVATE include)

For sake of completion, this is how the complete CMakeLists.txt for the project would look like.

#
# Copyright (c) 2021 I-IKIGAI
#
# License information
#
cmake_minimum_required(VERSION 3.13.1)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(hello_world)
target_sources(app PRIVATE src/main.c src/hello_world.c)
target_include_directories(app PRIVATE include)

VS Code intellisense#

In the project, add a folder call .vscode and in this folder add a file call c_cpp_properties.json. There add the following code showed below. If it does not automatically

{
"configurations": [
{
"name": "Win32",
"cStandard": "c99",
"includePath": [
"${workspaceFolder}/**",
"~/ncs/nrfxlib/**",
"~/ncs/modules/**",
"~/ncs/modules/hal/cmsis/CMSIS/Core/Include",
"~/ncs/mbedtls/**",
"~/ncs/nrf/boards/**",
"~/ncs/nrf/drivers/**",
"~/ncs/nrf/dts/**",
"~/ncs/nrf/ext/**",
"~/ncs/nrf/include/**",
"~/ncs/nrf/lib/**",
"~/ncs/nrf/modules/**",
"~/ncs/nrf/subsys/**",
"~/ncs/nrf/dts/**",
"~/ncs/zephyr/arch/**",
"~/ncs/zephyr/boards/**",
"~/ncs/zephyr/drivers/**",
"~/ncs/zephyr/dts/**",
"~/ncs/zephyr/include/**",
"~/ncs/zephyr/kernel/**",
"~/ncs/zephyr/lib/**",
"~/ncs/zephyr/misc/**",
"~/ncs/zephyr/modules/**",
"~/ncs/zephyr/soc",
"~/ncs/zephyr/soc/arm/nordic_nrf/nrf52",
"~/ncs/zephyr/subsys/**",
"~/gnuarmemb/**",
""
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"path": [
"${workspaceFolder}/**",
"~/ncs/zephyr/soc",
"~/ncs/zephyr/soc/arm/nordic_nrf/nrf52",
"~/ncs/modules/hal/cmsis/CMSIS/Core/Include",
"~/ncs/nrfxlib/**",
"~/ncs/modules/**",
"~/ncs/mbedtls/**",
"~/ncs/nrf/boards/**",
"~/ncs/nrf/drivers/**",
"~/ncs/nrf/dts/**",
"~/ncs/nrf/ext/**",
"~/ncs/nrf/include/**",
"~/ncs/nrf/lib/**",
"~/ncs/nrf/modules/**",
"~/ncs/nrf/subsys/**",
"~/ncs/nrf/dts/**",
"~/ncs/zephyr/arch/**",
"~/ncs/zephyr/boards/**",
"~/ncs/zephyr/drivers/**",
"~/ncs/zephyr/dts/**",
"~/ncs/zephyr/include/**",
"~/ncs/zephyr/kernel/**",
"~/ncs/zephyr/lib/**",
"~/ncs/zephyr/misc/**",
"~/ncs/zephyr/modules/**",
"~/ncs/zephyr/subsys/**",
"${env:GNUARMEMB_TOOLCHAIN_PATH}/**",
""
]
},
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE",
"__GNUC__",
"__LITTLE_ENDIAN__",
"sizeof(a)=1",
"size_t=int",
"DT_N_INST_P_label",
"uint32_t=unsigned int",
"int32_t=int",
"int64_t=long int",
"uint64_t=unsigned long int",
"int16_t=short",
"uint16_t=unsigned short",
"int8_t=signed char",
"uint8_t=unsigned char",
""
],
"forcedInclude": [
"${workspaceFolder}/build/zephyr/include/generated/autoconf.h",
"~/ncs/zephyr/include/toolchain/zephyr_stdint.h",
""
],
"compilerPath": "C:/gnuarmemb/bin/arm-none-eabi-gcc "
},
{
"name": "Linux",
"cStandard": "c99",
"includePath": [
"${workspaceFolder}/**",
"~/ncs/nrfxlib/**",
"~/ncs/modules/**",
"~/ncs/modules/hal/cmsis/CMSIS/Core/Include",
"~/ncs/mbedtls/**",
"~/ncs/nrf/boards/**",
"~/ncs/nrf/drivers/**",
"~/ncs/nrf/dts/**",
"~/ncs/nrf/ext/**",
"~/ncs/nrf/include/**",
"~/ncs/nrf/lib/**",
"~/ncs/nrf/modules/**",
"~/ncs/nrf/subsys/**",
"~/ncs/nrf/dts/**",
"~/ncs/zephyr/arch/**",
"~/ncs/zephyr/boards/**",
"~/ncs/zephyr/drivers/**",
"~/ncs/zephyr/dts/**",
"~/ncs/zephyr/include/**",
"~/ncs/zephyr/kernel/**",
"~/ncs/zephyr/lib/**",
"~/ncs/zephyr/misc/**",
"~/ncs/zephyr/modules/**",
"~/ncs/zephyr/soc",
"~/ncs/zephyr/soc/arm/nordic_nrf/nrf52",
"~/ncs/zephyr/subsys/**",
"~/gnuarmemb/**",
""
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"path": [
"${workspaceFolder}/**",
"~/ncs/zephyr/soc",
"~/ncs/zephyr/soc/arm/nordic_nrf/nrf52",
"~/ncs/modules/hal/cmsis/CMSIS/Core/Include",
"~/ncs/nrfxlib/**",
"~/ncs/modules/**",
"~/ncs/mbedtls/**",
"~/ncs/nrf/boards/**",
"~/ncs/nrf/drivers/**",
"~/ncs/nrf/dts/**",
"~/ncs/nrf/ext/**",
"~/ncs/nrf/include/**",
"~/ncs/nrf/lib/**",
"~/ncs/nrf/modules/**",
"~/ncs/nrf/subsys/**",
"~/ncs/nrf/dts/**",
"~/ncs/zephyr/arch/**",
"~/ncs/zephyr/boards/**",
"~/ncs/zephyr/drivers/**",
"~/ncs/zephyr/dts/**",
"~/ncs/zephyr/include/**",
"~/ncs/zephyr/kernel/**",
"~/ncs/zephyr/lib/**",
"~/ncs/zephyr/misc/**",
"~/ncs/zephyr/modules/**",
"~/ncs/zephyr/subsys/**",
"${env:GNUARMEMB_TOOLCHAIN_PATH}/**",
""
]
},
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE",
"__GNUC__",
"__LITTLE_ENDIAN__",
"sizeof(a)=1",
"size_t=int",
"DT_N_INST_P_label",
"uint32_t=unsigned int",
"int32_t=int",
"int64_t=long int",
"uint64_t=unsigned long int",
"int16_t=short",
"uint16_t=unsigned short",
"int8_t=signed char",
"uint8_t=unsigned char",
""
],
"forcedInclude": [
"${workspaceFolder}/build/zephyr/include/generated/autoconf.h",
"~/ncs/zephyr/include/toolchain/zephyr_stdint.h",
""
],
"compilerPath": "~/gnuarmemb/bin/arm-none-eabi-gcc "
}
],
"version": 4
}

Note#

Students can visit the repo here IntegrityKey Repo