One of the feature (let’s say most important feature) brought by BLE specifications is the advertisement principle. BLE advertising allows a device to periodically broadcast data to every devices around it. Between each advertisement (the interval time can be set from 20ms to 10 seconds) the device can go in sleep mode, that helps to drastically reduce the power consumption. Before going deeper with advertisement, it’s important to explain some BLE vocabularies. A BLE device can be either a Peripheral or a Central. The Peripheral is mostly the battery powered up device that needs to keep its power consumption low such as a temperature sensor or a heart rate monitor. Since its power consumption has to remains low, it needs to send data to a much powerful device (a smartphone, computer etc…) to process the data, called the Central. BLE advertising is by definition unidirectional that means only the Peripheral can transmit data to the Central. If the Central needs to transmit data to the Peripheral as well, a connection needs to be done between both devices.

Let’s start by creating a new project based on sd_app project. We will call it sd_adv_app.

        $ cd nrf51/sd_app
        $ make clean
        $ cd ..
        $ cp -r sd_app/ sd_adv_app

Update the Makefile with the new project name:

# Project name
PROJECT_NAME = sd_adv_app

To support BLE advertisement in our code we also need to add tow more flags in the Makefile. USE_BLE_ADV to add corresponding advertisement code and USE_DRV_PSTORAGE to support the persistent storage, needed by BLE advertising.

# Drivers
USE_DRV_NOSD := n
USE_LIB_SCHEDULER := y
USE_SD110 := y
USE_BLE_COMMON := y
USE_LIB_TRACE := y
USE_DRV_BLE_FLASH := y
USE_LIB_TIMER := y
USE_BLE_ADV := y
USE_DRV_PSTORAGE := y

If you try to compile your code right now, you’ll get the following error:

../sdk/nRF51_SDK_9.0.0_2e23562/components/drivers_nrf/pstorage/pstorage.h:28:31: fatal error: pstorage_platform.h: No such file or directory
 #include "pstorage_platform.h";
                               ^
compilation terminated.
make: *** [../sdk/nRF51_SDK_9.0.0_2e23562/components/drivers_nrf/pstorage/pstorage.o] Error 1

As you can see pstorage_platform.h is missing, this file has to be added as a project dependent include containing the infromation where the application data is stored in flash. This module is really useful if you need to store persistent data in flash memory.

Create a folder named include in sd_adv_app/ and then copy pstorage_platform.h from an example code provided by Nordic.

        $ cd nrf51/sd_adv_app
        $ mkdir include
        $ cp ../sdk/nRF51_SDK_9.0.0_2e23562/examples/ble_peripheral/ble_app_template/config/pstorage_platform.h include/

The compilation should now works well. And we are now ready to code our first BLE app. To do that open main.c file, we’ll start by enabling Softdevice:

#include "softdevice_handler.h";
...
static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
{
    // Catch BLE event here
}

static void softdevice_init(void)
{
    uint32_t err_code;

    // Initialize the SoftDevice handler module.
    SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, NULL);

    // Enable BLE stack.
    ble_enable_params_t ble_enable_params;
    memset(&ble_enable_params, 0, sizeof(ble_enable_params));

    err_code = sd_ble_enable(&ble_enable_params);
    APP_ERROR_CHECK(err_code);

    // Subscribe for BLE events.
    err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
    APP_ERROR_CHECK(err_code);
}

int main(void){
    softdevice_init();
...

The code above initialize the BLE stack Softdevice and setup the callback function needed to catch BLE events.

Once Softdevice initialized we can setup the GAP (Generic Access Profile) parameters (name of the device, security, connection parameters, etc…).

#define APP_ADV_NAME   "SD_ADV_APP";
...
static void gap_params_init(void)
{
    uint32_t                err_code;
    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 *)APP_ADV_NAME,
                                          strlen(APP_ADV_NAME));
    APP_ERROR_CHECK(err_code);
}

int main(void){
    softdevice_init();
    gap_params_init();
...

This code allows to setup the connection security in open mode (anyone can initiate a connection to the device) and to set the device name (the name we will see on a host during a BLE scan).

Then we can initialize the data that will be broadcasted during BLE advertising. We’ll setup the advertisement behaviour at the same time (advertisement interval, timeout, type, ect…)

#include "ble_advdata.h";
#include "ble_advertising.h";
...
#define APP_ADV_INTERVAL                320        // 320 * 0.625ms = 200ms
...
static void advertisement_evt_cb(ble_adv_evt_t ble_adv_evt)
{
	// Catch Advertisement events here
}
...
static void advertising_init(void)
{
    uint32_t      err_code;
    ble_advdata_t advdata;
    memset(&advdata, 0, sizeof(advdata));

    // advertise the the full device name
    advdata.name_type = BLE_ADVDATA_FULL_NAME;
    //LE General Discoverable Mode, BR/EDR not supported.
    advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;

    ble_adv_modes_config_t options = {0};

    // enable fast advertisement
    options.ble_adv_fast_enabled  = BLE_ADV_FAST_ENABLED;
    // set advertisement interval to 200 ms, 320 * 0.625ms
    options.ble_adv_fast_interval = APP_ADV_INTERVAL;
    // set advertisement timeout to infinite
    options.ble_adv_fast_timeout  = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED;

    err_code = ble_advertising_init(&advdata, NULL, &options, advertisement_evt_cb, NULL);
    APP_ERROR_CHECK(err_code);
}

int main(void){
    softdevice_init();
    gap_params_init();
    advertising_init();
...

Finally we just need to call ble_advertising_start function to start advertisement:

int main(void){
    softdevice_init();
    gap_params_init();
    advertising_init();
    // start fast advertisement
    ble_advertising_start(BLE_ADV_MODE_FAST);

Compile your code and flash it on your dev board:

        $ cd nrf51/
        $ JLinkExe sh/nrf51_load_sd.sh
        J-Link>loadbin sd_adv_app/sd_adv_app.bin 0x18000
        J-Link>r
        J-Link>g

The green led should blink and now thanks to LightBLue Explorer app (ios/mac) you should be able to see your device advertising device name data:

LightBlue on Mac:

bluetooth low energy advertisement nrf51

LightBlue on ios:

bluetooth low energy advertisement nrf51

For Android users you can use a similar application called BLE Scanner.

If you click on SD_ADV_APP you’ll open a BLE connection with the device. Then if you click on Show advertisement data you’ll see the data advertised by the device.

bluetooth low energy advertisement nrf51

So far only the local name is broadcasted. We can add some data thanks to the manufacturer specific data field in an advertisement packet. To do that we just need to add our data in advdata.p_manuf_specific_data field in main.c file:

#define APP_ADV_CUSTOM_DATA     "hello world!";
...
static void advertising_init(void)
{
    uint32_t err_code;
    ble_advdata_t advdata;
    ble_advdata_manuf_data_t manfdata;

    memset(&advdata, 0, sizeof(advdata));

    // advertise the the full device name
    advdata.name_type = BLE_ADVDATA_FULL_NAME;
    // LE General Discoverable Mode, BR/EDR not supported.
    advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;

    // Set the manufacturer specific data below
    memset(&manfdata, 0, sizeof(manfdata));

    manfdata.company_identifier = 0x1234;
    manfdata.data.size = strlen(APP_ADV_CUSTOM_DATA);
    manfdata.data.p_data = (uint8_t *)APP_ADV_CUSTOM_DATA;

    advdata.p_manuf_specific_data = &manfdata;

    ble_adv_modes_config_t options = {0};
...

The result on LightBlue Explorer application should be as below:

bluetooth low energy advertisement nrf51

Here we are! We are now able to advertise data over BLE, in the next post we’ll see how to transfert data from our smartphone to the device in order to control remotely the LED.

Links:

LightBlue Explorer

BLE Scanner

You can retrieve the source code on the following github link: github

2 thoughts on “BLE application with nRF51822: Advertising data

Leave a comment