This is a tutorial for people who are new to Bluetooth Smart (also known as Bluetooth low energy) and want to get started using the technology on mbed. As with everything new there are a few things that needs to be learned, but it is more fun to just get started. The theory will come later.
Build and run an application
A good application to start with is the BLE_HeartRate example, not too complicated, and it includes data transfer which is normally required for any application.
Program this example to your nRF51 mbed enabled kit by doing the following:
- Go to the BLE_HeartRate code page, then click Import this program.
- Click through the options and make sure the BLE_HeartRate project is selected. Check that you have selected a Bluetooth Smart enabled platform if you are working with several bed devices.
- Click Compile. A .hex file should download in your browser.
- Have your mbed kit connected; it should appear as a USB mass storage device. Drag or copy the file to this device. It programs and you are done on this side.
The easiest way to test the application is to use a phone app, Nordic Semiconductor has several examples for iOS and Android: nRFready Demo APPS. To connect with nRF Toolbox do the following:
- Start the nRF Toolbox app.
- Click the Heart/HRM icon.
- Click Connect.
- Look for Nordic_HRM (the default name) in the list. Touch it to select.
- Observe the data in the graph.
Congratulations! You have tested your first Bluetooth Smart device!
Walkthrough of the code
Let's see how this magic is achieved. The first thing to notice is the BLEDevice class, which encapsulates the Bluetooth low energy protocol stack. The following code shows how to use the BLEDevice object.
BLEDevice
#include "BLEDevice.h"
BLEDevice ble;
void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
{
ble.startAdvertising(); // restart advertising
}
int main(void)
{
ble.init();
ble.onDisconnection(disconnectionCallback);
...
ble.startAdvertising();
while (true) {
...
ble.waitForEvent();
...
}
}
The object is created in main.cpp and there is an init() method that must be called before using the object. the startAdvertising() method is called to advertise the device's presence allowing other devices to connect to it. With the onDisconnect method a function is added to restart advertising when the connection is lost. The waitForEvent() method should be called whenever the application is 'done' doing any work; it hands the control over to the protocol and lets you save power.
So when will waitForEvent() return? Basically whenever you have an application interrupt. In this example there is a Ticker object that calls a function every second. Whenever the ticker 'ticks' the periodicCallback is called, and then waitForEvent returns, resuming the execution in main.
Interrupt to trigger periodic actions
void periodicCallback(void)
{
led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
/* Note that the periodicCallback() executes in interrupt context, so it is safer to do
* heavy-weight sensor polling from the main thread. */
triggerSensorPolling = true;
}
int main(void)
{
led1 = 1;
Ticker ticker;
ticker.attach(periodicCallback, 1);
...
Some more setup is needed, where one thing is the GATT Services. GATT, or the "Generic Attribute Profile" is the way data is organised in Bluetooth Smart. GATT services adopted by Bluetooth SIG can be found here. The services used in this example are already added to the BLE_API, and the code is found in the source files under BLE_API->services
Service setup
/* Setup primary service. */
uint8_t hrmCounter = 100;
HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
/* Setup auxiliary services. */
BatteryService battery(ble);
DeviceInformationService deviceInfo(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
The next thing is the advertiser payload. This is the data contained in the advertiser packets:
Advertiser setup
ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ble.setAdvertisingInterval(1600); /* 1000ms; in multiples of 0.625ms. */
The first line is mandatory for Bluetooth Smart, and says that this device only supports Bluetooth low energy. The 'general discoverable' is the typical value to set when you want your device to be seen by other devices on order to connect. Next comes the ID for the heart rate sensor service and the name of the device.
After the payload is set the code sets the advertising type and the advertising interval. In Bluetooth Smart timing values are typically multiples of 625 us.
If you are new to Bluetooth Smart there are probably a lot of terms that are new to you. There is a lot of information about this on the internet, so how about doing some self studies? Try to answer the following:
- What is GAP, GATT, and ATT?
- What is a Bluetooth Smart peripheral?
Integrate a real sensor
The BLE_HeartRate example only gives a simulated example, so a next logical step is to use a real sensor. There are many choices here, and some might even have sample code on mbed.org. Otherwise you need to study the sensor and write your own code.
- The Earclip Heart Rate Sensor is fairly simple and gives a pulse on a digital input pin every time it detects a heartbeat. Combine this with a timer to get the bp value.
- Some sensors uses IR diode to emit light through your finger to a photosensor. Unfortunately the sensor picks up a lot more than just the light from the diode, so these are quite challenging to work with.
You may also use a completely different sensor, send the value as a heart rate measurement, and change the GATT service later.
Last advice is to not debug over the air as it takes long to connect, at least longer than connecting to a serial port. The following code sets up a serial port on the USB:
Serial pc(USBTX, USBRX);
pc.printf("Hello!\n");
For setup on the computer see the documentation.
This is a tutorial for people who are new to Bluetooth Smart (also known as Bluetooth low energy) and want to get started using the technology on mbed. As with everything new there are a few things that needs to be learned, but it is more fun to just get started. The theory will come later.
Build and run an application
A good application to start with is the BLE_HeartRate example, not too complicated, and it includes data transfer which is normally required for any application.
Program this example to your nRF51 mbed enabled kit by doing the following:
The easiest way to test the application is to use a phone app, Nordic Semiconductor has several examples for iOS and Android: nRFready Demo APPS. To connect with nRF Toolbox do the following:
Congratulations! You have tested your first Bluetooth Smart device!
Walkthrough of the code
Let's see how this magic is achieved. The first thing to notice is the BLEDevice class, which encapsulates the Bluetooth low energy protocol stack. The following code shows how to use the BLEDevice object.
BLEDevice
The object is created in main.cpp and there is an init() method that must be called before using the object. the startAdvertising() method is called to advertise the device's presence allowing other devices to connect to it. With the onDisconnect method a function is added to restart advertising when the connection is lost. The waitForEvent() method should be called whenever the application is 'done' doing any work; it hands the control over to the protocol and lets you save power.
So when will waitForEvent() return? Basically whenever you have an application interrupt. In this example there is a Ticker object that calls a function every second. Whenever the ticker 'ticks' the periodicCallback is called, and then waitForEvent returns, resuming the execution in main.
Interrupt to trigger periodic actions
Some more setup is needed, where one thing is the GATT Services. GATT, or the "Generic Attribute Profile" is the way data is organised in Bluetooth Smart. GATT services adopted by Bluetooth SIG can be found here. The services used in this example are already added to the BLE_API, and the code is found in the source files under BLE_API->services
Service setup
The next thing is the advertiser payload. This is the data contained in the advertiser packets:
Advertiser setup
The first line is mandatory for Bluetooth Smart, and says that this device only supports Bluetooth low energy. The 'general discoverable' is the typical value to set when you want your device to be seen by other devices on order to connect. Next comes the ID for the heart rate sensor service and the name of the device.
After the payload is set the code sets the advertising type and the advertising interval. In Bluetooth Smart timing values are typically multiples of 625 us.
If you are new to Bluetooth Smart there are probably a lot of terms that are new to you. There is a lot of information about this on the internet, so how about doing some self studies? Try to answer the following:
Integrate a real sensor
The BLE_HeartRate example only gives a simulated example, so a next logical step is to use a real sensor. There are many choices here, and some might even have sample code on mbed.org. Otherwise you need to study the sensor and write your own code.
You may also use a completely different sensor, send the value as a heart rate measurement, and change the GATT service later.
Last advice is to not debug over the air as it takes long to connect, at least longer than connecting to a serial port. The following code sets up a serial port on the USB:
For setup on the computer see the documentation.