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;
}
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 Project, nRF51 Project. Same code works for both nRF51 & nRF52 series including nRF52840.
Part 2 Part 3