Making a mobile app in JavaScript for the Nordic Semiconductor nRF51822 Evaluation Kit

Patrik Dai JavadBlogs, Tutorials

Tweet about this on TwitterShare on FacebookShare on LinkedInShare on Google+

We have looked into the Nordic Semiconductor’s nRF51822-EK Evaluation Kit by making a simple mobile JavaScript app for Android and iOS mobile devices where we control an LED on the board over BLE. The example can be easily modified, serving as a template or starting point for other IoT applications. This tutorial assumes that you are already somewhat familiar with Nordic Semiconductor nRF51822. For the embedded software in the nRF51822-EK we are focusing on some of the relevant parts only – a full description of the embedded software architecture on the development kit is out of scope for this tutorial.

Nordic Semiconductor is one of main companies with chipsets for ultra low power wireless applications based on Bluetooth Low Energy (BLE), ANT and 2.4GHz proprietary RF protocols. Their chipsets are typically found in consumer products, such as wireless keyboards, mouse, remote controls and also inside several modules. Both industrial modules (Laird, Fujitsu) as well in Arduino compliant modules and shields (LightBlueBean, RFduino or the BLENano by RedBearLab).

Nordic Semiconductors have several different kits available, we have chosen to work with their nRF51822-EK Evaluation Kit, which is a small board based on the nRF51822 chipset.

As depicted below the board includes an ARM Cortex M0, a BLE antenna, headers for GPIOs, Buttons, LEDs and a USB connector. The board has a coin cell battery holder on the rear side (not visible below). The board also includes an additional micro-controller by Atmel that is added purely for debugging purposes (for more information, see Segger J-link).

nrf51822-post-image00

While creating a basic example mobile app in Evothings Studio to connects to nRF51822-EK over BLE we focused on accessibility and ease of control. We were inspired by the BLE LED blinking app for Arduino, a perfect example also for the nRF51822-EK as it provides LEDs and push-buttons.

Our simple setup is depicted below.

nrf51822-post-image01
nrf51822-post-image02

Update from Nordic Semiconductor (SDK):

Dear nRF51 developer.
Quite a few changes has been introduced with SDK v7.0.0.
Among them is how the SDK is distributed. From now on, you will find nRF51 SDK downloads at this location: http://developer.nordicsemi.com.
Please spend some time to look into other news and changes
introduced in the SDK described on http://developer.nordicsemi.com as well.

Step 1 – Getting hold of a Nordic nRF51822-EK Evaluation Kit

This tutorial assumes you are using the nRF51822-EK Evaluation Kit. The kit is available from several distributors such as Elfa, Digikey and Mouser Electronics.

Together with the evaluation kit there is a Product Code, the code is needed for accessing relevant documents and software tools available at Nordic Semiconductor’s website. If you don’t already have an account on Nordic’s website you will need to register on their register page.

Once you have received your nRF51822-EK, make sure to register the Product Code here. Otherwise you will not have access to documents and tools needed for nRF51822-EK.

Step 2 – Installation of SDK and software tools

Once you have registered your nRF51822-EK on Nordic Semiconductors website make sure to read their nRF51822-EK user guide to get started with their (Windows based) software tools and SDK. In addition to the tools provided by Nordic Semiconductor, you also need Keil IDE by ARM. The user guide by Nordic describe how to download and install the free version of Keil. This free version has a limit related to code size, but is sufficient for most BLE applications.

We used a laptop with Windows 8.1 (64-bit version) and installed software tools provided by Nordic Semiconductor:

  • nRFgoStudio version 1.17.0
  • MasterControlPanel version 3.7.0
  • nRF51 SDK version 6.1.0

Also we installed the latest version of Keil (currently version 5.12.0.0).

Depending on the intended BLE application there are different software versions available by Nordic Semiconductors. Our idea is to create a simple mobile app using Evothings Studio where a smart phone (acting as BLE central) communicates with our nRF51822-EK configured as BLE peripheral device to blink a LED (blinking a LED is sometimes referred as the “hardware” variant of the classical “Hello World” example). As explained in the user guide the software for nRF51822-EK consist of two parts:

  • Application – provided as source code examples for use with Keil IDE
  • SoftDevice – the “BLE stack” provided as hex file (not as source code)

The SoftDevice package is the BLE stack and this software is Nordic’s proprietary BLE implementation, no source code is available. The SoftDevice is downloaded as a separate hex (binary) file, and the application (which is developed in Keil) use the SoftDevice API for for BLE applications. This is further explained below. The SoftDevice BLE stack is available in different versions depending on use case requirements:

  • S110: SoftDevice for BLE peripheral role
  • S120: SoftDevice for BLE central role
  • S130: SoftDevice for BLE peripheral and central roles

If you are unfamiliar with BLE technology and want to learn more (information about BLE master/slave or BLE client/server roles etc) there are several tutorials available on the web, for example this one by mbientlab.

For our application we use Nordic SDK version 6.1.0 and their latest available SoftDevice (specifically the S110) for a BLE peripheral device as the mobile phone device is BLE central role.

Step 3 – Download Nordic’s example code from GitHub

After downloading and installing the SDK there will be a number of examples available. Some of these are related to Bluetooth SIG’s standardised BLE services and profiles (such as Heart Rate Sensor, Proximity etc.) while also others are included (iBeacon). In addition there are additional examples available by Nordic Semiconductor on GitHub.

It turned out that there is actually one example called ble-app-lbs on GitHub for controlling LEDs and handling key button presses on the nRF51822-EK, therefore we use this example for our tutorial. The example is available in different versions, and we use the branch for SDK6.0 (which works also for SDK version 6.1.0). The code is available for download here:

https://github.com/NordicSemiconductor/nrf51-ble-app-lbs/tree/SDK6.0

Step 4 – Overview of Nordic’s ble-app-lbs example application

The ble-app-lbs example application demonstrates bidirectional communication over BLE. When it is running, you will be able to toggle an LED on the nRF51822-EK from a central device (the mobile phone) and receive a notification over BLE when a button is pressed.

The application is implemented using one BLE service, with two characteristics – the LED characteristic, which can be used to control the LED remotely through the write without response operation, and the Button characteristic, which sends a notification when the button is pressed or released.

The basic flow of a typical BLE application running on the nRF51822-EK is to initialise all needed parts, start BLE advertising and wait for a BLE event. When a BLE event is received, it is passed to all BLE services and modules.

An event can be (but is not limited to) one of the following:

  • BLE central device connects to nRF51822
  • BLE central device writes to a characteristic (toggling a LED)
  • Indication that advertising has timed out

This flow makes the application modular and a service can usually be added to an application by initialising it and ensuring its event handler is called when an event comes in.

The code related to this example is divided into three files:

main.c
ble_lbs.c
ble_lbs.h

main.c implements application behaviour and the separate service files implements the service and its behaviour. All GPIO handling is left to the application. We will look into the code later, but first we will prepare our nRF51822-EK (target).

Step 5 – Download SoftDevice and ble-app-lps application

In order to try out the example application we first prepare our kit by downloading the software, first the SoftDevice binary file (hex file) by use of nRFgoStudio and then the compiled application file from Keil IDE.

Note that the nRF51822-EK is not preloaded with any firmware.

The procedure of how to download the SoftDevice is explained in nRF51822-EK user guide. Download the latest available SoftDevice version to nRF51822-EK using nRFgoStudio.

nRFgoStudio can actually also be used to download the ble-app-lbs application code, however there is not yet a compiled hex file for download (only source code is provided, no binary files). Therefore, as the next step, open up the ble_app_lbs example in Keil and compile it. Presumed the settings in Keil are correct the compilation should result in no errors or warnings.

The procedure how to open up a project in Keil, how to configure the project, setup flash download configurations are explained in nRF51822-EK user guide while some additional information for the SoftDevice software version used is found in other documents. Therefore make sure to follow the instructions in the documents for the SoftDevice version you are using! Such documents are available on Nordic Semiconductors website.

Once these configurations are working properly, the ble-app-lps example can be compiled and downloaded into nRF518322-EK flash memory be use of Keil or alternatively from nRFgoStudio. We used the SoftDevice version 7.0.0 and SDK version 6.1.0, the files downloaded to nRF51822-EK were s110_nrf51822_7.0.0_softdevice.hex and ble_app_lbs.hex respectively.

If everything is working as expected you should now be able to find the nRF51822-EK from a mobile device using BLE since it does advertising directly after startup. However at this point we did not yet create the mobile app in Evothings Studio, therefore we suggest, as an intermediate step, that you use any of the available BLE utility apps from App Store or Google Play to do this.

We used an iOS app called LightBlue (by a company called PunchThrough Labs who made the LightBlueBean) for scanning and detecting BLE peripheral devices, and conclude that we can find our nRF51822-EK named LedButtonDemo.

NOTE:

We faced a initial problem with how to properly setup the Keil flash download tools related to the RAM memory address (for the flash algorithm), hence we contacted Nordic support team on this issue. Our experience is that support questions are handled very quickly by the Nordic FAE team, inline with what to expect when using professional chipsets and tools.

Step 6 – Looking into BLE and the ble-app-lbs application code

As mentioned above the ble-app-lbs application code which we need to look into is mainly:

main.c
ble_lbs.c
ble_lbs.h

In main.c initialisations and events are handled. Also there are a number of defines which are related to our BLE application as illustrated below. Especially notice that two LEDs are used, LED_0 indicates advertising and LED_1 indicates a BLE connection. Once a BLE connection is active LED_0 is not used anymore, and our application reuse LED_0. Here also the the Bluetooth Device Name is defined (LedButtonDemo).

#define LEDBUTTON_LED_PIN_NO          LED_0
#define LEDBUTTON_BUTTON_PIN_NO       BUTTON_1
#define DEVICE_NAME                   "LedButtonDemo"
#define ADVERTISING_LED_PIN_NO        LED_0 
#define CONNECTED_LED_PIN_NO          LED_1
#define APP_ADV_INTERVAL              64 
#define APP_ADV_TIMEOUT_IN_SECONDS    180

Apart from the defines above there are many others, mostly related to BLE advertising intervals, BLE connection intervals, BLE security. Please notice above that advertising has a timeout set to 180s. This means that after 180 seconds advertisement will automatically stop, and can be activated by pressing BUTTON_1. We leave all these parameters unchanged, and use the defaults for now.

Further down in main.c we find code for initialisations and error handling. One example is the GAP (Generic Access Profile) initialisations related to BLE (SoftDevice) in the code below. Here we can see how some of the defines explained above are used (DEVICE_NAME) and also see the configurations for BLE connection intervals (MIN_CONN_INTERVAL, MAX_CONN_INTERVAL etc).

The parameter SLAVE_LATENCY is set to zero for most BLE applications, and is mainly relevant for critical applications where both power consumption is and latency (delay) are important (such as a BLE HID mouse or keyboard). The parameter called CONN_SUP_TIMEOUT is a timeout related to when the BLE link is lost like when devices move away and goes out of range.

static void gap_params_init(void)
{
        uint32_t err_code;
        ble_gap_conn_params_t gap_conn_params;
        ble_gap_conn_sec_mode_t sec_mode;

        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
        err_code = sd_ble_gap_device_name_set(&sec_mode,
                                              (const uint8_t *)DEVICE_NAME,
                                              strlen(DEVICE_NAME));
        APP_ERROR_CHECK(err_code);
        memset(&gap_conn_params, 0, sizeof(gap_conn_params));
        gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
        gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
        gap_conn_params.slave_latency = SLAVE_LATENCY;
        gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
        err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
        APP_ERROR_CHECK(err_code);
}

Next we will have a quick look at the code related to BLE security configurations. Below there are a few defines that may need some explanation. The parameter SEC_PARAM_TIMEOUT is a time-out for the pairing (bonding) request in seconds, if bonding is required (here it is) then the applicable time-out is 30 seconds. As can be seen SEC_PARAM_BOND=1, hence bonding is enabled per default.

There are also two parameters called SEC_PARAM_MITM and SEC_PARAM_IO_CAPABILITIES, which are security settings related to Man-In-The-Middle (MITM) attacks. In our simple application using the eval. kit we have limited Input and Output capabilities (neither a display for output, nor a keyboard for PIN code entry input), and our security requirements are not critical. Therefore we use the default settings, and in case you want to experiment without any security you could change SEC_PARAM_MITM=0.

#define SEC_PARAM_TIMEOUT             30
#define SEC_PARAM_BOND                1
#define SEC_PARAM_MITM                0
#define SEC_PARAM_IO_CAPABILITIES     BLE_GAP_IO_CAPS_NONE

The initialization function code for security is included below. As visible there are a few parameters which we did not mention earlier, and we leave these as per default. One parameter, notably OOB is an abbreviation for Out-Of-Band – a method of doing pairing (bonding) by using another technology than Bluetooth (such as pairing over NFC).

static void sec_params_init(void)
{
        m_sec_params.timeout = SEC_PARAM_TIMEOUT;
        m_sec_params.bond = SEC_PARAM_BOND;
        m_sec_params.mitm = SEC_PARAM_MITM;
        m_sec_params.io_caps = SEC_PARAM_IO_CAPABILITIES;
        m_sec_params.oob = SEC_PARAM_OOB;
        m_sec_params.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
        m_sec_params.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
}

Another part of from main.c is related to initialisation of the BLE stack, the code initialise the SoftDevice and the BLE event handler. We are not going into these details here, but you can get a fairly good understanding by reading the comments included in the source code. Instead we will have a brief look at the application specific code related to the LEDs and key button press functions and initializations. Below code snippet is for the button event handler. If pin_no is LEDBUTTON_BUTTON_PIN_NO (Button 1, see also above) is pressed a notification is sent over BLE by ble_lbs_on_button_change function which is in ble_lbs.c.

static void button_event_handler(uint8_t pin_no, uint8_t button_action)
{
        uint32_t err_code;
        switch (pin_no)
        {
                case LEDBUTTON_BUTTON_PIN_NO:
                     err_code = ble_lbs_on_button_change(&m_lbs, button_action);
                     if (err_code != NRF_SUCCESS &&
                         err_code != BLE_ERROR_INVALID_CONN_HANDLE &&
                         err_code != NRF_ERROR_INVALID_STATE)
                     {
                             APP_ERROR_CHECK(err_code);
                     }
                     break;

                default:
                     APP_ERROR_HANDLER(pin_no);
                     break;
        }
}

We leave the code related to LED handling as an exercise to the reader, and look at the main function in main.c where several initialisations are included as well as the “main loop”. The initialisations are related to GPIOs, Timers, the BLE stack etc, as illustrated by the code snippet below. Then system timers and advertisements are started and the loop waits for an event to occur (such as BLE connection request, key button press). The function power_manage() is related to minimise overall power consumption during periods of inactivity.

int main(void)
{
        // Initialize
        leds_init();
        timers_init();
        gpiote_init();
        buttons_init();
        ble_stack_init();
        scheduler_init();
        gap_params_init();
        services_init();
        advertising_init();
        conn_params_init();
        sec_params_init();

        // Start execution
        timers_start();
        advertising_start();

        // Enter main loop
        for (;;)
        {
                app_sched_execute();
                power_manage();
        }
}

As mentioned earlier the code of interest for us are in main.c, ble_lbs.c and ble_lbs.h. We’ll start by have a look at ble_lbs.h, where the Service UUID is defined: Generally BLE “non-standardised” BLE services (like our LED key button example) require a 128-bit Universally Unique Identification ID (a.k.a UUID) while Bluetooth SIG standardised services (such as Battery Service) use 16-bit UUIDs.

The ble-app-lps example uses a 128-bit UUID, along with the shortened 16-bit versions for the service and the characteristics. They are defined in ble_lbs.h as following:

#define LBS_UUID_BASE                 {
                                         0x23, 0xD1, 0xBC, 0xEA, 0x5F, 
                                         0x78, 0x23, 0x15, 0xDE, 0xEF, 
                                         0x12, 0x12, 0x00, 0x00, 0x00, 0x00
                                      }
#define LBS_UUID_SERVICE              0x1523
#define LBS_UUID_LED_CHAR             0x1525
#define LBS_UUID_BUTTON_CHAR          0x1524

Our service use UUID 0x1523 and two characteristic UUIDs are used, one for the LED control (0x1525) and one for the key button (0x1524). We use these as is, and note down the UUIDs for later use when we create our BLE app using Evothings Studio. In ble_lbs.h also the service data structure ble_lps_s is defined as illustrated below.

typedef struct ble_lbs_s
{
        uint16_t                    service_handle;
        ble_gatts_char_handles_t    led_char_handles;
        ble_gatts_char_handles_t    button_char_handles;
        uint8_t                     uuid_type;
        uint16_t                    conn_handle;
        ble_lbs_led_write_handler_t led_write_handler;
} ble_lbs_t;

In ble_lbs.c functions for our BLE application are included, for example the function for handling the LED based on a event coming from the BLE stack but also other functions related to BLE events relevant for our application (such as a BLE connection event, BLE disconnection event) The code snippet for handling of write event below use the service structure (ble_lbs_t) above along with the BLE event as input parameters for controlling the green LED.

/**
 * @brief Function for handling the Write event.
 *
 * @param[in] p_lbs LED Button Service structure.
 * @param[in] p_ble_evt Event received from the BLE stack.
 */
static void on_write(ble_lbs_t * p_lbs, ble_evt_t * p_ble_evt)
{
        ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
        if ((p_evt_write->handle == p_lbs->led_char_handles.value_handle) &&
            (p_evt_write->len == 1) &&
            (p_lbs->led_write_handler != NULL))
        {
                p_lbs->led_write_handler(p_lbs, p_evt_write->data[0]);
        }
}

The above code snippets are mainly for explanatory purposes, once you came this far you are probably ready to download the entire code from GitHub here:

https://github.com/evothings/evothings-examples/tree/master/examples/

Step 7 – Making a mobile app for Android and iOS

We will use Evothings Studio to create a mobile app for Android and iOS devices using HTML5 and JavaScript. The simple app has a button that allows us to connect to our nRF51822-EK Evaluation Kit over BLE, and two buttons to turn on or off a green LED – after successful connection the user can control the green LED from the app, as illustrated below.

Additionally, if pressing “Button 1” on nRF51822-EK, the lowermost text will reflect the state of the key button (pressed=1, not pressed=0).

nrf51822-post-image03

There are a few main components in the Evothings app which are briefly explained below. The complete code can be downloaded from GitHub.

The first part of the Evothings Studio HTML code configures the basic appearance of the app. Also the title is set to “Nordic nRF51822-EK LED On/Off” and paths to libraries are defined. Especially notice that there is a path to Nordic’s library called nordic-ble.js.

<head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
        <title>Nordic BLE nRF51822-EK LED On/Off</title>
        <style>
                @import 'evothings-app.css';
        </style>
        <script src="libs/jquery/jquery-2.0.3.js"></script>
        <script src="cordova.js"></script>
        <script src="easy-ble.js"></script>
        <script src="nordic-ble.js"></script>
</head>

Next informative text and a static image are added in the HTML code. Also 3 buttons are added, one used for initiating the BLE connection and two buttons for toggling the green LED On/Off. As can be seen in the code the first button will call app.connect and the other two buttons are used to call app.ledOn respective app.ledOff.

        
        <h1>Nordic nRF51822-EK LED On/Off
        
        <p><img src="nRF51822EK_Image.jpg" style="max-height:20%;" /></p>
        <p id="info">Initializing...</p>
        <button class="yellow" onclick="app.connect()">CONNECT</button><br />
        <button class="green" onclick="app.ledOn()">LED ON</button><br />
        <button class="red" onclick="app.ledOff()">LED OFF</button>

Another of the main components is the JavaScript code related to the BLE connection establishment and the data sent from the app to the nRF51822-EK to turn the LED On or Off. Below the two functions app.ledOn and app.ledOff are defined. As can be seen in the code below data=1 corresponds to LED On and data=0 turns the LED Off.

The function for connection establishment app.connect first checks if there is already an on-going BLE connection, if so the link is first disconnected and a reconnection is initiated. The function device.setNotification is used for get a notification over BLE when the button 1 on nRF51822-EK is pressed, the app will show “Button state: 0” or “Button State: 1” as text.

We also added some status information in the code as well as error handling for convenience.

        // Application object.
        var app = {}
        // Connected device.
        app.device = null;
        // Turn on LED.
        app.ledOn = function()
        {
                app.device && app.device.writeDataArray(new Uint8Array([1]));
        }
        // Turn off LED.
        app.ledOff = function()
        {
                app.device && app.device.writeDataArray(new Uint8Array([0]));
        }
        app.showMessage = function(info)
        {
                document.getElementById('info').innerHTML = info
        };
        app.showData = function(data)
        {
                document.getElementById('data').innerHTML = data
        };
        // Called when BLE and other native functions are available.
        app.onDeviceReady = function()
        {
                app.showMessage('Touch the connect button to begin.');
        };
        app.connect = function()
        {
                nordicble.close();
                app.showMessage('Scanning...');
                nordicble.connect(
                        function(device)
                        {
                                app.device = device;
                                app.showMessage('Connected! Touch buttons ...');
                                app.showData('Press Button 1 on the ...');
                                device.setNotification(function(data)
                                {
                                        app.showData('Button state: '+new                         
                                        Uint8Array(data)[0]);
                                });
                        },
                        function(errorCode)
                        {
                                app.showMessage('Connect error: ' + errorCode + '.');
                        });
        };

The code above is mainly for explanatory purposes and should be fairly self explanatory, also you could check the JavaScript files if you want to learn more on the details. Download the complete code from GitHub for Evothings Studio here:

https://github.com/evothings/evothings-examples/tree/master/examples

Step 8 – Test your new app with nRF51822-EK

Once everything is prepared, it should be pretty straight forward to successfully execute the LED On/Off example, and as a next step also to include your specific ideas into the code.

In case you have questions, or run into problems of any sort, don’t hesitate to let us know via the Evothings forum: http://forum.evothings.com

Conclusions

Our impression of the nRF51822-EK is that it’s very capable, and it should be very well suitable for all possible BLE applications. We experienced some initial difficulties getting the Keil IDE configuration correct, while Nordic technical support assisted us to resolve this issue quickly.

One of the benefits with this type of professional dev kits, as opposed to Arduino compatible BLE kits, is that there are no restrictions related to the use of BLE custom services or any of the Bluetooth SIG standardised services such as Battery Service (which would make sense for our application). On the other hand it’s more challenging and time consuming to get up and running and understand the software code and technical documentation.