Arduino and Nordic nRF52-DK: debugging and unit testing
The goal of this tutorial is to demonstrate how simple it is to usePlatformIO IDE for VSCode to develop, run and debug a simple project withArduino framework forNordicnRF52-DK
board.
Level: Beginner
Platforms: Windows, Mac OS X, Linux
Requirements:
Downloaded and installedPlatformIO IDE for VSCode
Install drivers forJ-LINK debug tool
Nordic nRF52-DK development board
Setting Up the Project
At first step, we need to create a new project using PlatformIO Home Page (to open this page just press Home icon on the toolbar):

On the next step we need to selectNordicnRF52-DK
as a development board,Arduino as a framework and a path to the project location (or use the default one):

Processing the selected project may take some amount of time (PlatformIO will download and install all required packages)and after these steps, we have a fully configured project that is ready for developing code withArduino framework.
Adding Code to the Generated Project
Let’s add some actual code to the project. Firstly, we open a default main filemain.cpp
in thesrc_dir folder and replace its contents with the following:
#include<Arduino.h>voidsetup(){pinMode(LED_BUILTIN,OUTPUT);}voidloop(){digitalWrite(LED_BUILTIN,HIGH);delay(100);digitalWrite(LED_BUILTIN,LOW);delay(100);}

After this step, we created a basic blink project ready for compiling and uploading.
Compiling and Uploading the Firmware
Now we can build the project. To compile firmware we can use next options:Build option from theProjectTasks
menu, Build button inPlatformIO Toolbar, Task MenuTasks:RunTask...>PlatformIO:Build
or inPlatformIO Toolbar, Command PaletteView:CommandPalette>PlatformIO:Build
or via hotkeyscmd-alt-b/ctrl-alt-b
:

If everything went well, we should see a successful result message in the terminal window:

To upload the firmware to the board we can use next options:Upload option from theProjectTasks
menu, Upload button inPlatformIO Toolbar, Command PaletteView:CommandPalette>PlatformIO:Upload
, using Task MenuTasks:RunTask...>PlatformIO:Upload
or via hotkeyscmd-alt-u/ctrl-alt-u
:

After successful uploading, the green LED1 should start blinking.
Debugging the Firmware
Debugging offers the easiest way to debug the board. Firstly, we need to specifydebug_tool in“platformio.ini” (Project Configuration File). Since the board has an on-boardJLink
debug probe we can directly declare it in“platformio.ini” (Project Configuration File):
[env:nrf52_dk]platform=nordicnrf52board=nrf52_dkframework=arduinodebug_tool=jlink
To start the debug session we can use next options:Debug:Startdebugging
from the top menu,StartDebugging
option from Quick Access menu or hotkey buttonF5
:

We need to wait some time while PlatformIO is initializing the debug session and when the first line after the main function is highlighted we are ready to debug:

We can walk through the code using control buttons, set breakpoints, add variables toWatchwindow
:

Writing Unit Tests
Unit Testing test cases can be added to a single file that may include multiple tests. First of all, in this file, we need to add four default functions:setUp
,tearDown
,setup
andloop
. FunctionssetUp
andtearDown
are used to initialize and finalize test conditions. Implementations of these functions are not required for running tests but if you need to initialize some variables before you run a test, you use thesetUp
function and if you need to clean up variables you usetearDown
function. In our example we will use these functions to accordingly initialize and deinitialize LED.setup
andloop
functions act as a simple Arduino program where we describe our test plan.
Let’s createtest
folder in the root of the project and add a new filetest_main.cpp
to this folder. Next basic tests forString
class will be implemented in this file:
test_string_concat
tests the concatenation of two stringstest_string_substring
tests the correctness of the substring extractiontest_string_index_of
ensures that the string returns the correct index of the specified symboltest_string_equal_ignore_case
tests case-insensitive comparison of two stringstest_string_to_upper_case
tests upper-case conversion of the stringtest_string_replace
tests the correctness of the replacing operation
Note
2 sec delay is required since the board doesn’t support software resetting via
Serial.DTR/RTS
#include<Arduino.h>#include<unity.h>StringSTR_TO_TEST;voidsetUp(void){// set stuff up hereSTR_TO_TEST="Hello, world!";}voidtearDown(void){// clean stuff up hereSTR_TO_TEST="";}voidtest_string_concat(void){Stringhello="Hello, ";Stringworld="world!";TEST_ASSERT_EQUAL_STRING(STR_TO_TEST.c_str(),(hello+world).c_str());}voidtest_string_substring(void){TEST_ASSERT_EQUAL_STRING("Hello",STR_TO_TEST.substring(0,5).c_str());}voidtest_string_index_of(void){TEST_ASSERT_EQUAL(7,STR_TO_TEST.indexOf('w'));}voidtest_string_equal_ignore_case(void){TEST_ASSERT_TRUE(STR_TO_TEST.equalsIgnoreCase("HELLO, WORLD!"));}voidtest_string_to_upper_case(void){STR_TO_TEST.toUpperCase();TEST_ASSERT_EQUAL_STRING("HELLO, WORLD!",STR_TO_TEST.c_str());}voidtest_string_replace(void){STR_TO_TEST.replace('!','?');TEST_ASSERT_EQUAL_STRING("Hello, world?",STR_TO_TEST.c_str());}voidsetup(){delay(2000);// service delayUNITY_BEGIN();RUN_TEST(test_string_concat);RUN_TEST(test_string_substring);RUN_TEST(test_string_index_of);RUN_TEST(test_string_equal_ignore_case);RUN_TEST(test_string_to_upper_case);RUN_TEST(test_string_replace);UNITY_END();// stop unit testing}voidloop(){}
Now we are ready to upload tests to the board. To do this we can use next options:Test button onPlatformIO Toolbar, Test option from theProjectTasks
menu orTasks:RunTask...>PlatformIOTest
from the top menu:

After processing we should see a detailed report about the testing results:

As we can see from the report, all our tests were successful!
Adding Bluetooth LE features
To add the basic BLE functionality to our project we need to define the SoftDevice versionand install a library calledBLEPeripheral.Both these modifications can be specified in“platformio.ini” (Project Configuration File):
[env:nrf52_dk]platform=nordicnrf52board=nrf52_dkframework=arduinodebug_tool=jlink; SoftDevice versionbuild_flags=-DNRF52_S132lib_deps=BLEPeripheral
Now let’s create a basic application that can interact with other BLE devices (e.g phone)For example, next code declares a BLE characteristic that controls the state of the LED1.
#include<Arduino.h>#include<SPI.h>#include<BLEPeripheral.h>BLEPeripheralledPeripheral=BLEPeripheral();BLEServiceledService=BLEService("19b10000e8f2537e4f6cd104768a1214");BLECharCharacteristicledCharacteristic=BLECharCharacteristic("19b10001e8f2537e4f6cd104768a1214",BLERead|BLEWrite);voidsetup(){pinMode(LED_BUILTIN,OUTPUT);ledPeripheral.setAdvertisedServiceUuid(ledService.uuid());ledPeripheral.addAttribute(ledService);ledPeripheral.addAttribute(ledCharacteristic);ledPeripheral.setLocalName("Nordic NRF52 DK");ledPeripheral.begin();}voidloop(){BLECentralcentral=ledPeripheral.central();if(central){while(central.connected()){if(ledCharacteristic.written()){if(ledCharacteristic.value()){digitalWrite(LED_BUILTIN,HIGH);}else{digitalWrite(LED_BUILTIN,LOW);}}}}}
Now we can compile and upload this program to the board as described in previous sections.To verify that our application works as expected, we can use any Android smartphone with BLE feature andNordic nRF Connect tool.
At first, we need to scan all advertising BLE devices and connect to the device calledNordicNRF52DK
.After a successful connection to the board, we should see one “Unknown Service” with one “Unknown Characteristic” fields:

To switch the LED on or off we just need write0
or1
asUINT8
to the BLE characteristic:

Conclusion
Now we have a project template for NordicnRF52-DK
board that we can use as a boilerplate for the next projects.