If you need/want to have nRF development environment in Linux...
- Ubuntu 21.04 x86_64
- nRF52832 DK board
- Getting the SDK and tools
- 1.1 Get basic tools
- 1.2 Get ARM-GCC Compiler
- 1.3 Get nRF SDK and docs
- 1.4 Get command line JTAG tools
- 1.5 Flash SoftDevice
- Building the example
- 2.1 Modify Makefile.Posix for SDK
- 2.2 Compile an Example
- 2.3 Simplify the example
- 2.4 Edit Makefile for the simplified project
- Setting VSCODE as the IDE
- 3.1 Get VSCODE and some extensions
- 3.2 Set Tasks.json for make/clean
- 3.3 Set Launch.json for debugging
- 3.4 Get Python tools
- Conclusion
Install some packages:
$ sudo apt update
$ sudo apt install -y \
git \
libncurses5 \
gdb-multiarch \
build-essential
If libncurses5 installation fails:
$ sudo apt --fix-broken install
ARM provides the ARM-GCC compiler To install the latest release:
# Prep the directory
$ mkdir -p ~/nRF52
$ cd ~/nRF52
# Download and extract
$ wget https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.07/gcc-arm-none-eabi-10.3-2021.07-x86_64-linux.tar.bz2
$ tar jxf gcc-arm-none-eabi-10.3-2021.07-x86_64-linux.tar.bz2 # take ~30 Sec.
$ mv gcc-arm-none-eabi-10.3-2021.07 gcc-arm
# Check
$ ./gcc-arm/bin/arm-none-eabi-gcc -v
...
gcc version 10.3.1 20210621 (release) (GNU Arm Embedded Toolchain 10.3-2021.07)
Don't forget adding ~/nRF52/gcc-arm/bin to your PATH!!
$ echo "export PATH=$PATH:$HOME/nRF52/gcc-arm/bin" >> ~/.bashrc
Download the SDK and install:
$ cd ~/nRF52
$ wget https://developer.nordicsemi.com/nRF51_SDK/nRF5_SDK_v17.x.x/nRF5_SDK_17.0.2_d674dde.zip
$ unzip nRF5_SDK_17*.zip
$ mv nRF5_SDK_17.0.2_d674dde nRF5_SDK
Downloads the documents and install:
$ cd ~/nRF52
$ wget https://developer.nordicsemi.com/nRF51_SDK/nRF5_SDK_v17.x.x/nRF5_SDK_17.0.2_offline_doc.zip
$ unzip nRF5_*doc.zip -d docs
Download nRF5x-Command-Line-Tools for Linux 64 bit from:
Run these commands to install the tools:
$ cd ~/nRF52
$ wget https://www.nordicsemi.com/-/media/Software-and-other-downloads/Desktop-software/nRF-command-line-tools/sw/Versions-10-x-x/10-13-0/nRF-Command-Line-Tools_10_13_0_Linux64.zip
$ unzip nRF-Command-Line-Tools_10_13_0_Linux-amd64.zip -d tools
$ cd tools/nRF-Command-Line-Tools_10_13_0_Linux64
$ tar xvf nRF-Command-Line-Tools_10_13_0_Linux-amd64.tar.gz
$ sudo dpkg -i JLink_Linux_V750b_x86_64.deb
$ sudo dpkg -i nRF-Command-Line-Tools_10_13_0_Linux-amd64.deb
To check the version of installed tools:
$ nrfjprog -v
nrfjprog version: 10.13.0
JLinkARM.dll version: 7.50a
$ mergehex -v
mergehex version: 10.13.0
$ JLinkExe -v
SEGGER J-Link Commander V7.50a (Compiled Jul 8 2021 18:21:10)
DLL version V7.50a, compiled Jul 8 2021 18:20:53
To flash a softdevice to a connected nRF52832-DK (s132) board via JLink,
$ cd ~/nRF52/nRF52_SDK/components/softdevice/s132/hex
$ ls -l
s132_nrf52_7.2.0_licence-agreement.txt
s132_nrf52_7.2.0_softdevice.hex
$ nrfjprog -f NRF52 --chiperase --program s132_nrf52_7.2.0_softdevice.hex
Get the information of the installed compiler:
$ which arm-none-eabi-gcc
$HOME/nRF52/gcc-arm/bin/arm-none-eabi-gcc
$ arm-none-eabi-gcc -v
...
gcc version 10.3.1 20210621 (release) (GNU Arm Embedded Toolchain 10.3-2021.07)
Edit Makefile:
$ cd ~/nRF52/nRF52_SDK/components/toolchain/gcc
$ vi Makefile.posix
Then edit the Makefile looks like based on the information we got:
GNU_INSTALL_ROOT ?= ${HOME}/nRF52/gcc-arm/bin/
GNU_VERSION ?= 10.3.1
GNU_PREFIX ?= arm-none-eabi
Now we can just compile an example:
$ cd ~/nRF52/nRF52_SDK/examples/peripheral/blinky/pca10040/s132/armgcc
$ ls -l
blinky_gcc_nrf52.ld
Makefile
$ make
...
DONE nrf52832_xxaa
nRF52 SDK comes with well organized files, but sometimes simplifying project hierarchy might be a good idea.
$ cd $HOME/nRF52/nRF5_SDK/examples/peripheral/blinky
$ tree
.
├── blinky_gcc_nrf52.ld
├── main.c
├── Makefile
├── sdk_config.h
└── include
├── arm_acle.h
├── arm_cmse.h
├── arm_fp16.h
├── arm_neon.h
├── float.h
├── gcov.h
├── iso646.h
├── mmintrin.h
├── stdalign.h
├── stdarg.h
├── stdatomic.h
├── stdbool.h
├── stddef.h
├── stdfix.h
├── stdint-gcc.h
├── stdint.h
├── stdnoreturn.h
├── tgmath.h
├── unwind-arm-common.h
├── unwind.h
└── varargs.h
1 directory, 25 files
To do so,
$ mkdir ~/example_blinky
$ cd ~/example_blinky
Scratch below items from each directory to the example_blinky:
- ~/nRF52/nRF52_SDK/examples/peripheral/blinky/main.c
- ~/nRF52/nRF52_SDK/examples/peripheral/blinky/pca10040/s132/config/sdk_config.h
- ~/nRF52/nRF52_SDK/examples/peripheral/blinky/pca10040/s132/armgcc/Makefile
- ~/nRF52/nRF52_SDK/examples/peripheral/blinky/pca10040/s132/armgcc/blinky_gcc_nrf52.ld
- All other files in the pca10040 directory can be ignored
The include files might be located at
- $HOME/nRF52/gcc-arm/arm-none-eabi/include
To adjust the Makefile for our project, which has the new and simple structure:
- SDK_ROOT := $(HOME)/nRF52/nRF52_SDK
- PROJECT_DIR := .
- For INC_FOLDERS, remove the line of ../config
- For OPT, Optimization level can be 0 (if you want)
Build again:
$ cd ~/example_blinky
$ make
...
DONE nrf52832_xxaa
Then the "_build" directory might have some image files newly generated (hex and bin) for debugging.
The details can be found from:
Download the installer from:
Some extensions are required as well:
- C/C++ (ms-vscode.cpptools)
- Cortex-Debug (marus25.cortex-debug)
Once VSCODE and the extensions are ready:
$ cd example_blinky
$ code .
To generate a c_cpp_properties.json,
- Press CTRL+Shift+P.
- Then run C/C++: Edit Configuration (JSON)
{
"env": {
"nRF_SDK": "${HOME}/nRF52/nRF5_SDK",
"GNU_GCC": "${HOME}/nRF52/gcc-arm"
},
"configurations": [
{
"name": "nRF52832 DK",
"includePath": [
"${workspaceFolder}/**",
"${env:GNU_GCC}/arm-none-eabi/include",
"${env:nRF_SDK}/modules/**",
"${env:nRF_SDK}/components/**"
],
"defines": [
"BOARD_PCA10040",
"CONFIG_GPIO_AS_PINRESET",
"INITIALIZE_USER_SECTIONS",
"FLOAT_ABI_HARD",
"NRF52",
"NRF52832_XXAA",
"NRF_SD_BLE_API_VERSION=6",
"S132",
"SOFTDEVICE_PRESENT",
"SWI_DISABLE0"
],
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "linux-gcc-arm"
}
],
"version": 4
}
To generate a Tasks.json,
- Press CTRL+Shift+P.
- Then type task.
- Lastly click Tasks: Configure Task.
Above action generates a file (Tasks.json) under .vscode.
By filling the json file, we can invoke make and make clean with shortcuts:
{
"version": "2.0.0",
"tasks": [
{
"label": "make",
"command": "make",
"args": [
"VERBOSE=1"
],
"options": {
// This path should point the Makefile location
"cwd": "${workspaceFolder}/pca10040/s132/armgcc"
},
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
},
{
"label": "clean",
"command": "make",
"args": [
"clean"
],
"options": {
// This path should point the Makefile location
"cwd": "${workspaceFolder}/pca10040/s132/armgcc"
},
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
},
{
"label": "flash",
"type": "shell",
"command": "make flash",
"options": {
// This path should point the Makefile location
"cwd": "${workspaceFolder}/pca10040/s132/armgcc"
},
"group": "build",
"problemMatcher": []
},
{
"label": "flash_softdevice",
"type": "shell",
"command": "make flash_softdevice",
"options": {
// This path should point the Makefile location
"cwd": "${workspaceFolder}/pca10040/s132/armgcc"
},
"problemMatcher": []
},
{
"label": "sdk_config",
"type": "shell",
"command": "make sdk_config",
"options": {
// This path should point the Makefile location
"cwd": "${workspaceFolder}/pca10040/s132/armgcc"
},
"problemMatcher": []
},
{
"label": "serial",
"type": "shell",
"command": "screen /dev/ttyACM0 115200",
"problemMatcher": []
},
{
"label": "erase",
"type": "shell",
"command": "make erase",
"options": {
// This path should point the Makefile location
"cwd": "${workspaceFolder}/pca10056/s140/armgcc"
},
"problemMatcher": []
}
]
}
With this configuration, we can use CTRL+SHIFT+B to open the task dialog and run make or clean.
To generate a launch.json,
- Press CTRL+Shift+P.
- Then type launch.
- Lastly click Debug: Open launch.json and Cortex Debug.
Above action generates a file (launch.json) under .vscode.
By filling the json file, we can invoke the arm-none-eabi-gdb and JLink GDB server.
{
"version": "0.2.0",
"configurations": [
{
"name": "Cortex Debug",
"cwd": "${workspaceRoot}",
"executable": "./_build/nrf52832_xxaa.out",
// Or
// "executable": "${workspaceFolder}/pca10040/s132/armgcc/_build/nrf52832_xxaa.out",
"request": "launch",
"type": "cortex-debug",
"servertype": "jlink",
"device": "nrf52",
"interface": "swd",
// Only absolute path worked for me for some reason...
"armToolchainPath": "/home/bus710/nRF52/gcc-arm/bin/",
"runToMain": true,
}
]
}
With this configuration, we can use F5 to start a debugging session.
Two things need to be adjusted based on your project:
- executable: THE_EXECUTABLE_NAME should ba updated.
- device: the depends on the target MCU.
The detail can be found from the extension's website (>>>).
To test nRF fimware there are well known python tools - nrfutil and pybluez.
Those should be used to update/test the firmware.
$ sudo apt install python-pip
$ sudo pip install --ignore-installed six nrfutil
$ sudo pip install pybluez
In this walkthrough,
- Downloaded and installed the SDK, tools, and IDE
- Learned how to make your own project by scratching
- Compiled and debugged the project
- Used VSCODE as the IDE
...and everything could be well done in Linux!