Clion logo

The CLion Blog

A Cross-Platform IDE for C and C++

Tips & Tricks

Tutorial: Using nRF52 With nRF Connect SDK, CMake, and CLion

Nearly a year ago, our guest Nick Brook, founder at NRB Tech, explained how to use CLion for nRF52. Today, Nick is back with a new tutorial focused on using CMake-based nRF Connect SDK in CLion. Read this tutorial from Nick and give it a try with CLion!

Nick Brook IoT consultant and founder at NRB Tech
Nick founded NRB Tech in 2018 to build useful and sustainable IoT (Internet of Things) products through a combination of in-depth hardware, software, and user experience expertise.

Previously, we established how it is possible to use Nordic’s nRF5 SDK with CMake and CLion. In April 2020, Nordic released version 1.0.0 of nRF Connect SDK, the new platform for Nordic products moving forward. This SDK is based on the Zephyr RTOS, a modern, secure, open source real-time operating system from the Linux Foundation backed by Facebook, Google, Intel, Nordic, NXP, and Opticon. The new SDK allows more complex projects using cellular and WiFi with new and future Nordic modules, while also supporting nRF52 series modules.

Zephyr uses CMake as its build system, making it much easier to use in CLion than the nRF5 SDK. However, there is some setup that we need to do.

Prerequisites

The nRF Connect SDK supports nRF52 series SOCs in addition to the newer nRF53 and nRF91 SOCs. All development kits and Thingy boards are supported. The nRF Connect SDK can be used on Windows, macOS, and Linux.

Setting up the toolchain and SDK

The best way to set up the SDK and toolchain on Windows and macOS is using the nRF Connect Toolchain Manager. This is the simplest way to get set up, and it also ensures that all toolchain dependencies are in one place and are the right versions for that SDK version.

Manual setup instructions are available too, which can be used for setup on Linux.

Throughout this tutorial, when paths to the SDK are needed, we will use <ncsroot> as a placeholder. If using the Toolchain Manager with version 1.5.0, on Windows this would be C:\Users\<user>\ncs\v1.5.0; on macOS this would be /opt/nordic/ncs/v1.5.0.

Creating a custom project to use in CLion

Let’s create a custom project from a sample Nordic project.

  1. Find a relevant sample from the SDK in the <ncsroot>/nrf/samples directory. Copy this to a convenient location on your system. Rename the directory if you wish. If you are very new to nRF52, the peripheral_hids_mouse example is recommended. The example simulates a regular computer mouse. For more details refer to the example’s README.rst file.
  2. Open the project in CLion. Ignore any errors for now.
  3. In CLion preferences, go to Build, Execution, Deployment | Toolchains and add a new toolchain. Configure as shown:
    NRF Toolchain

    1. Name: “nRF Connect SDK <version>”, replacing <version> with the version of the SDK you are using
    2. CMake: <ncsroot>/bin/cmake
    3. C Compiler: <ncsroot>/bin/arm-none-eabi-gcc
    4. C++ Compiler: <ncsroot>/bin/arm-none-eabi-g++
    5. Debugger: <ncsroot>/bin/arm-none-eabi-gdb
    6. Click “Apply”
  4. In CLion preferences, go to Build, Execution, Deployment | CMake and then select the existing "Debug" profile.

    1. Set Build type to ZDebug (this is explained further towards the end of the article)
    2. Set Toolchain to the nRF Connect SDK <version> toolchain we just created
    3. In CMake options add -G Ninja. Ninja is the recommended generator for Zephyr and prevents issues on Windows.
  5. To provide Zephyr with the system and project specific configuration it needs, we must set the environment variables. We need to set the environment variables in the CLion profile because this propagates them to processes launched by CMake, so targets that use west will work. If we set the environment variables in CMakeLists.txt, they would not propagate to launched processes.

    1. If you are using the toolchain manager, click the down arrow next to the NCS version installed and:

      1. On Windows, click "Open command prompt" and paste:
        echo BOARD=nrf52dk_nrf52832;ZEPHYR_BASE=%ZEPHYR_BASE%PATH=%PATH%;GIT_EXEC_PATH=%GIT_EXEC_PATH%;ZEPHYR_TOOLCHAIN_VARIANT=%ZEPHYR_TOOLCHAIN_VARIANT%;GNUARMEMB_TOOLCHAIN_PATH=%GNUARMEMB_TOOLCHAIN_PATH% | clip
      2. On macOS, click “Open Terminal” and paste:
        echo "BOARD=nrf52dk_nrf52832;ZEPHYR_BASE=$(pwd)/zephyr;PATH=$PATH:/usr/local/bin;GIT_EXEC_PATH=$GIT_EXEC_PATH;ZEPHYR_TOOLCHAIN_VARIANT=$ZEPHYR_TOOLCHAIN_VARIANT;GNUARMEMB_TOOLCHAIN_PATH=$GNUARMEMB_TOOLCHAIN_PATH" | pbcopy

      The result is automatically copied to your clipboard. Paste it into the "Environment" box in CLion’s CMake Profile configuration.

    2. If you have installed manually, paste the following in the “Environment” box and modify.
      BOARD=nrf52dk_nrf52832;ZEPHYR_BASE=<ncsroot>;PATH=<ncsroot>/toolchain/bin:<existing path>;GIT_EXEC_PATH=<ncsroot>/toolchain/Cellar/git/2.26.2/libexec/git-core;ZEPHYR_TOOLCHAIN_VARIANT=gnuarmemb;GNUARMEMB_TOOLCHAIN_PATH=<ncsroot>/toolchain

      1. Modify ZEPHYR_BASE, GIT_EXEC_PATH, and GNUARMEMB_TOOLCHAIN_PATH replacing <ncsroot>.
      2. The NCS toolchain must come before other paths in the PATH variable. CLion does not yet support variable expansion in environment variables, so you need to enter the whole path, replacing <existing path>. To obtain the path to use, enter echo $PATH in a shell (macOS and Linux) or enter echo %PATH% in the command prompt (Windows).
    3. If you want to use a board other than the nRF52 DK, you will need to modify the BOARD environment variable to the board you want to use. The boards available are defined here in the "Build target" column. There is also a webinar and guide you can follow to create a custom board.
      CMake Profiles
  6. Duplicate the "ZDebug" profile and modify the new profile’s "Build type" to "ZRelease". Click OK.
  7. Most of the project configuration is done in the prj.conf file. Rename this file to prj.common.conf. This will contain the configuration common to both ZDebug and ZRelease builds. Open the file and at the bottom add:
    # Use RTT instead of UART for debug output (optional)
    CONFIG_USE_SEGGER_RTT=y
    CONFIG_RTT_CONSOLE=y
    CONFIG_UART_CONSOLE=n
  8. Create a new file prj.ZDebug.conf and add:
    # Optimize for debug
    CONFIG_DEBUG_OPTIMIZATIONS=y
  9. Create a new file prj.ZRelease.conf and add:
    # Optimize for speed. See https://docs.zephyrproject.org/latest/reference/kconfig/choice_471.html#choice-471 for other options
    CONFIG_SPEED_OPTIMIZATIONS=y
    # Disable assertions in the Zephyr Kernel. This improves the execution speed and prevents a CMake configure warning. See https://docs.zephyrproject.org/latest/reference/kconfig/CONFIG_ASSERT.html
    CONFIG_ASSERT=n
  10. Open the CMakeLists.txt file. Before the find_package(Zephyr ...) line, insert:
    if (NOT CMAKE_BUILD_TYPE)
      set(CMAKE_BUILD_TYPE ZDebug)
    endif()
    # Point to the build type and common config files
    set(CONF_FILE "prj.${CMAKE_BUILD_TYPE}.conf" "prj.common.conf")

  11. Click Tools | CMake | Reset Cache and Reload Project.
  12. You can now use the zephyr_final target to build <project dir>/cmake-build-<profile>/zephyr.hex, and the flash target to build and flash to the board.
  13. You can get RTT output by following the steps in Nordic’s Testing With a Sample Application guide. Essentially, after installing the JLink software and documentation pack, run:

    • On Windows: JLinkRTTViewer.exe
    • On macOS: open /usr/local/bin/JLinkRTTViewer.app
    • On Linux: JLinkRTTViewerExe

    Then select the Nordic SOC that you are using; the other defaults should be fine.

  14. Next we will set up debugging.

    1. On the top right of the CLion window, click the configuration drop-down and “Edit Configurations”. Then add a new “Embedded GDB Server” configuration:
      Embedded GDB Configuration
    2. Configure as shown:
      Configuration details

      1. Set a name
      2. Check "Store as project file" to share this with other CLion users of your project
      3. Select the zephyr_final target
      4. Select the zephyr_final executable
      5. Set Target remote args to tcp:localhost:2331
      6. Set GDB Server to

        • Mac: /usr/local/bin/JLinkGDBServer.
        • Windows: C:\Program Files (x86)\SEGGER\JLink\JLinkGDBServerCL.exe.
        • Or the appropriate path for your system.
      7. Set GDB Server args to
        -device nrf52 -strict -timeout 0 -nogui -if swd -speed 4000 -endian little -s
      8. Note that you may need to adjust the -device parameter to match your device. A full list is available – select “Nordic Semi” from the drop down, and use the relevant “Device name” for this parameter.
    3. To avoid a known issue with CLion/JLink GDB Server, you can work around it. Press Shift twice, type "registry", open the Registry, and change the "cidr.debugger.gdb.interrupt.signal" to "SIGTRAP".
    4. Now you can build this target, which will build and flash, or you can debug. When debugging, if your breakpoint is not hit when the debugger starts, just click the reset button and continue:
      Debug process
    5. You can also view the state of peripherals on the device when debugging. Click the "Peripherals" tab and click "Load .svd file":
      Load SVD
    6. Browse to <ncsroot>/modules/hal/nordic/nrfx/mdk and select the .svd file for your hardware (for nRF52832 use nrf52.svd), then select the peripherals you want to monitor. When the debugger is paused, you will then be able to inspect the values of peripheral registers:
      Peripherals view
  15. In addition to using CLion for debugging, it’s sometimes useful to use Segger Embedded Studio (SES). This is Nordic’s officially supported IDE, so it is good to test with if you are having issues. In addition, when debugging you can see RTT output directly in the IDE with no configuration. With nRF Connect SDK, you can open your project just like any sample project by following the instructions in the guide.
  16. As in Nordic’s tutorials, in this guide we used ZDebug and ZRelease build types. This avoids CMake using built-in defaults for C and C++ compiler flags, which conflict with the flags defined by Zephyr from KConfig. If you want to use the standard "Debug" and "Release" build types, for example if these are used by libraries you add to your project, you can. However, you must reset CMake’s default flags and disable the warning that Zephyr emits.

    1. Open the CMakeLists.txt file. After the CONF_FILE line we added earlier, insert:
      # CMake sets some default compiler flags in CMAKE_<LANG>_FLAGS_<CONFIG>. Zephyr sets all required flags from KConfig so
      # clear CMake defaults to avoid any conflicts.
      foreach(lang C CXX)
          set(CMAKE_${lang}_FLAGS "")
          foreach(type DEBUG RELEASE RELWITHDEBINFO MINSIZEREL)
              set(CMAKE_${lang}_FLAGS_${type} "")
          endforeach()
      endforeach()
      # Suppress a warning from Zephyr about a mismatch between CMAKE_<LANG>_FLAGS_<CONFIG> optimization flags (now empty) and
      # Zephyr's KConfig optimization flags.
      set(NO_BUILD_TYPE_WARNING ON)
    2. In CMakeLists.txt change the default build type from ZDebug to Debug.
    3. Rename prj.ZDebug.conf and prj.ZRelease.conf to prj.Debug.conf and prj.Release.conf
    4. In CLion Settings/Preferences | Build, Execution, Deployment | CMake change the Build type of your profiles to Debug and Release.

We’ve now finished setting up a sample project in CLion for nRF Connect SDK development! To learn more about nRF Connect SDK development, you may want to explore:

  • Other samples in the nRF connect SDK:

    • <ncsroot>/nrf/samples/bluetooth – Bluetooth samples
    • <ncsroot>/nrf/samples/sensor – Sensor samples

      • <ncsroot>/nrf/samples/sensor/bh1749 – I2C example
    • <ncsroot>/nrf/samples/bootloader – Bootloader sample
  • The Application Development guide, which walks through the files you will find in the samples that configure the project.
  • The Device tree guide, which is how you configure hardware in Zephyr.

Now you are ready to give it a try!

DOWNLOAD CLION

Discover more