Monday, December 18, 2017

Bluetooth LE with Nordic nRF51 & nRF52 Series

The easy way! 

Part 1 


Writing BLE firmware using the Nordic nRF51 & nRF52 SDK is not an easy task. The learning curve is quite steep for a beginner.   The IOsonata library encapsulates all that difficulties by providing a simple way to write BLE application firmware.

Prerequisite 

 

Software 


The IOsonata library development environment is based on Eclipse & GCC compiler.  All projects are eclipse's native.  They can be imported directly into eclipse.  However the source are organized in a specific folder tree.  Follow the blog posts to setup the environment,  for Eclipse setup, for IOsonata setup.

Hardware  


Off course there are hardware needed to write Bluetooth firmware.  Since this is about Nordic nRF5x series, any boards or module based on that chip can be used.  An other tool required is a compatible debug JTag tool to be able to flash and debug the code.   The IDAP-Link debug JTag supports flashing of the nRF5x series.  The IDK-BLYST-NANO and the IDAP-Link would make a great BLE development kit.




nRF52832 finger tip sized module available at CrowSupply

IMM-NRF52832
IDAP-Link


Some basics


Lets start with some basic about Bluetooth LE devices.  We are not attempting to go into the details of BLE specs here but merely some need to know in order to decide the right path to application.   There are 2 main category of BLE devices.  The Peripheral acts as BLE server.  This is usually the sensors, the watch, the tracker, the locks, etc...  The other type of devices are the Central.  It is the one that connects to the Peripheral to get data from.  The Central devices are mostly the computers, the smart phones and tablets.  Further, Nordic provide the BLE stack for their nRF51 & nRF52 series SoC in the form of binary called Softdevice.   This Softdevice support both Peripheral and Central mode.  It has to be flashed with the firmware app in order to use BLE.

BLE Peripheral Firmware 


The BLE Peripheral device always start by advertises its presence so the Central device can see and connect to it or not.   The Peripheral device can be an advertiser only not allowing Central device to connect to it.  This mode is often called connectionless or beacon.  It is the simplest form if BLE Peripheral device.  Here is how we can write the firmware of such device.


Device configuration 


The IOsonata made thing simple and flexible to use any devices in an embedded system.  Only two steps are required prior to use the device.  First, declaring the device configuration by filling a data structure of that device.  This data structure usually contains configuration for all operating mode of a BLE device.  Lets see how to define the device configuration structure for a BLE advertiser peripheral device.




#include "istddef.h" 
#include "ble_app.h" 

#define DEVICE_NAME      "Advertiser"
#define APP_ADV_INTERVAL    MSEC_TO_UNITS(100, UNIT_0_625_MS)

const BLEAPP_CFG s_BleAppCfg = {
   { // Clock config nrf_clock_lf_cfg_t
#ifdef IMM_NRF51822
       NRF_CLOCK_LF_SRC_RC, // Source RC
       1, 1, 0
#else
       NRF_CLOCK_LF_SRC_XTAL, // Source 32KHz XTAL
       0, 0, NRF_CLOCK_LF_ACCURACY_20_PPM 
#endif
   },
   0,    // Number of central link
   0,    // Number of peripheral link
   BLEAPP_MODE_NOCONNECT, // Connectionless beacon type
   DEVICE_NAME,           // Device name
   ISYST_BLUETOOTH_ID,    // PnP Bluetooth/USB vendor id
   1,          // PnP Product ID
   0, // Pnp prod version
   false,  // Enable device information service (DIS)
   NULL,
   NULL,       // Manufacture specific data to advertise
   0,          // Length of manufacture specific data
   BLEAPP_SECTYPE_NONE,    // Secure connection type
   BLEAPP_SECEXCHG_NONE,   // Security key exchange
   NULL,       // Service uuids to advertise
   0,    // Total number of uuids
   APP_ADV_INTERVAL, // Advertising interval in msec
   0,  // Advertising timeout in sec, 0 for never
   0,  // Slow advertising interval, if > 0, fallback to
       // slow interval on adv timeout and advertise until connected
   0,
   0,
   -1,             // Led port nuber
   -1,             // Led pin number
   0,              // Tx power
   NULL            // RTOS Softdevice handler
};

The code 


Now that the type of BLE Peripheral device has been defined.  Lets bring it to live with the main code.  All that is needed is to call 2 functions.


int main()
{
    BleAppInit((const BLEAPP_CFG *)&s_BleAppCfg, true);
    BleAppRun();
 
    return 0;
}


That is all the code you need to write to create a BLE Advertiser firmware.  Nordic NRF-Connect App can be used to see the advertisement.


Use NRF-Connect App to view advertisement data



Now we can see our device shows up on the scan.  That's about it.  What is of interest is that in the advertisement packet there is a little private data that we can use to send data.  Lets try to send a 32bit counter with the advertisement packet to make our Advertise more interesting.  The counter will count every time the advertisement times out.

In order to send the count we need to add it to the config so that the library would know.


#define APP_ADV_TIMEOUT   1 // Advertisement timeout in sec

uint32_t g_AdvCounter = 0;

const BLEAPP_CFG s_BleAppCfg = {
   { // Clock config nrf_clock_lf_cfg_t
#ifdef IMM_NRF51822
       NRF_CLOCK_LF_SRC_RC, // Source RC
       1, 1, 0
#else
       NRF_CLOCK_LF_SRC_XTAL, // Source 32KHz XTAL
       0, 0, NRF_CLOCK_LF_ACCURACY_20_PPM 
#endif
   },
   0,    // Number of central link
   0,    // Number of peripheral link
   BLEAPP_MODE_NOCONNECT, // Connectionless beacon type
   DEVICE_NAME,           // Device name
   ISYST_BLUETOOTH_ID,    // PnP Bluetooth/USB vendor id
   1,          // PnP Product ID
   0, // Pnp prod version
   false,  // Enable device information service (DIS)
   NULL,
   (uint8_t*)&g_AdvCounter,// Manufacture specific data to advertise
   sizeof(g_AdvCounter),   // Length of manufacture specific data
   BLEAPP_SECTYPE_NONE,    // Secure connection type
   BLEAPP_SECEXCHG_NONE,   // Security key exchange
   NULL,       // Service uuids to advertise
   0,          // Total number of uuids
   APP_ADV_INTERVAL, // Advertising interval in msec
   APP_ADV_TIMEOUT,  // Advertising timeout in sec, 0 for never
   0,  // Slow advertising interval, if > 0, fallback to
       // slow interval on adv timeout and advertise until connected
   0,
   0,
   -1,             // Led port nuber
   -1,             // Led pin number
   0,              // Tx power
   NULL            // RTOS Softdevice handler
};


In addition to the config, we need to catch the advertisement timeout to update the counter.  This is accomplished by overloading the function

void BlePeriphEvtUserHandler(ble_evt_t * p_ble_evt)
{
    if (p_ble_evt->header.evt_id == BLE_GAP_EVT_TIMEOUT)
    {
       // Update counter and advertisement data
       g_AdvCnt++;

       BleAppAdvManDataSet((uint8_t*)&g_AdvCnt, sizeof(g_AdvCnt));
    }
}

Complete Eclipse based project is on github:  nRF52 ProjectnRF51 Project. Same code works for both nRF51 & nRF52 series including nRF52840.


Part 2 Part 3






3 comments:

  1. Hi, thank you for the great guide. I try to follow your description, but when I build the project the eclipse return an error saying "cannot find -IEHAL". When I remove that include, then it fails with "cannot find ICMSIS". Is there anything that I miss?

    ReplyDelete
    Replies
    1. Hi,

      There are 2 library projects that you need to import and compile, the CMSIS and the EHAL. Depending on the target your are you using, do the import from the appropriate target folder. For example nRF51, import from ARM/Nordic/nRF51 folder. It will list all available project. Deselect all and select CMSIS & EHAL, Then right click on the project in the Eclipse and select Build configuration/Build All to build the library. After that you can build the example code.

      Delete
  2. Thankyou for poasting informetion about softwer of Nordic nRF51 & nRF52 and code

    JTAG

    ReplyDelete