This example shows how to make an app that controls a Dialog DA1458x Development Kit by communicating over Bluetooth Low Energy. It is a simple application which demonstrates basic initialization of the DA1458x chip and LED blinking. A button is added to the development kit as an extra component. Pressing the button changes the background color of the app to demonstrate the connection is bidirectional.
EquipmentThis is what you'll need in terms of parts, aside from a computer and smartphone:
- DA1458x Development Kit, http://www.dialog-semiconductor.com/bluetooth-smart/development-tools
- Optional - Push button
- Desktop software: Evothings Studio, https://evothings.com/download
- Desktop software: ARM Keil µVision 5, https://www.keil.com/download/product/
- Desktop software: SmartSnippets, http://support.dialog-semiconductor.com/
- Smartphone: Evothings Viewer app, search for “Evothings Viewer” in your app store.
If you have not installed the latest tools and drivers for your development kit, please refer to the "Getting Started" guide on the Dialog customer support site.
Also, make sure the jumpers on your Development Kit are set correctly, refer to the ‘Getting Started’ or user manual.
For example, the DA14580/581 Development Kit will look like this, don’t forget the jumper for the LED.
Start by downloading the latest SDK for DA14580/1/2/3. You can find the latest version of the SDK on the Dialog customer support site. This project uses SDK5.0.2.1.
The SDK comes with several example projects to help you get started with your product. Open the ble_app_peripheral
project in projects/target_apps/ble_examples/ble_app_peripheral/Keil_5
by opening ble_app_peripheral.uvprojx
.
Let’s start by changing the advertising name of our device. This is the name of the device you will see when scanning for Bluetooth devices.
In user_config/user_config.h
on line 110 set the following define to your liking. In this example we will use DIALOG-PRPH-BLINKY.
/// Advertising name
#define USER_DEVICE_NAME ("DIALOG-PRPH-BLINKY")
Build the project by pressing the "F7" key, or click the build button as shown in the following picture:
In Keil, start the debug session by either pressing "CTRL-F5" or in the menu bar, select Debug > Start/Stop Debug Session.
In the debug menu, either press the "F5" key or click the execution button as shown below to start code execution:
Connect the Evothings Workbench to your Viewer app and run the Dialog DA1458x Blinky example on your phone by pressing the 'RUN' button in the example tab of the Workbench.
In the application, press the 'SCAN' button to start scanning for devices in the area. Click the 'CONNECT' button next to the 'DIALOG-PRPH-BLINKY' device to connect via Bluetooth.
Using the SmartSnippets framework it is also possible to store the image file to flash memory of the device. When using Keil to build the software, a binary is generated automatically and stored in /projects/target_apps/ble_examples/ble_app_peripheral/Keil_5/out_58x/ble_app_peripheral_58x.hex
. Where x
corresponds to the chip version.
So far, only the 'TOGGLE LED' button works. To blink the LED and change the background color, follow the rest of the tutorial. You can also download the pre-generated binary from the GitHub repository.
LED BlinkingThe ble_peripheral_example
project does not support LED blinking (yet). We will now add a new GATT characteristic that let's us write a value containing the blink speed.
Open user_config/user_custs_config.h
in Keil and add the following code:
1. Define a new 128 bit UUID.
- Find the following code (line 50).
#define DEF_CUST1_LED_STATE_UUID_128
- Below this define, add a new UUID we will use to control the LED speed:
#define DEF_CUST1_LED_SPEED_UUID_128 {0xD8, 0xB0, 0xCB, 0x64, 0xD5, 0x4D, 0x11, 0xE5, 0x94, 0xC5, 0x1D, 0x66, 0xBB, 0x8E, 0x7F, 0x8B}
2. Define the length of the data we can write to this characteristic.
- Find the following line of code (line 59).
#define DEF_CUST1_LED_STATE_CHAR_LEN 1
- Below this define, add a new define that indicates the length of the data written to the characteristic will be 8 bits
#define DEF_CUST1_LED_SPEED_CHAR_LEN 8
3. Define the description of the characteristic.
- Find the following line of code (line 68).
#define CUST_LED_STATE_USER_DESC "LED State"
- Below this define, add a new description.
#define CUST1_LED_SPEED_USER_DESC "LED Speed"
4. Add new definitions to the Custom1 Service Database characteristic enum.
- Find the following line of code (line 87).
CUST1_IDX_LED_SPEED_USER_DESC,
- Below these definitions, add a new
CHAR
,VAL
andUSER_DESC
definition. These definitions are used to define the GATT database.
CUST1_IDX_LED_SPEED_CHAR,
CUST1_IDX_LED_SPEED_VAL,
CUST1_IDX_LED_SPEED_USER_DESC,
5. Add a new custom server attribute value definition
- Find the following line of code (line 131).
static uint8_t CUST1_LED_STATE_UUID_128[ATT_UUID_128_LEN] = DEF_CUST1_LED_STATE_UUID_128;
- Below this line, define a new server attribute.
static uint8_t CUST1_LED_SPEED_UUID_128[ATT_UUID_128_LEN] = DEF_CUST1_LED_SPEED_UUID_128;
6. Set the properties of the characteristic
- Find the following line of code (line 139).
static const struct att_char128_desc custs1_led_state_char = {ATT_CHAR_PROP_WR_NO_RESP,
{0, 0},
DEF_CUST1_LED_STATE_UUID_128};
- Below this line, define our characteristic.
ATT_CHAR_PROP_WR_NO_RESP
means the characteristic is write only, without response
static const struct att_char128_desc custs1_led_speed_char = {ATT_CHAR_PROP_WR_NO_RESP,
{0, 0},
DEF_CUST1_LED_SPEED_UUID_128};
7. Add the characteristic to the GATT database
- Find the following line of code (line 205).
// LED State Characteristic User Description
[CUST1_IDX_LED_STATE_USER_DESC] = {(uint8_t*)&att_decl_user_desc, ATT_UUID_16_LEN, PERM(RD, ENABLE), sizeof(CUST1_LED_STATE_USER_DESC) - 1, sizeof(CUST1_LED_STATE_USER_DESC) - 1, CUST1_LED_STATE_USER_DESC},
- Below this line, add our new characteristic data to the database, add the following code:
// LED Speed Characteristic Declaration
[CUST1_IDX_LED_SPEED_CHAR] = {(uint8_t*)&att_decl_char, ATT_UUID_16_LEN, PERM(RD, ENABLE), sizeof(custs1_led_speed_char), sizeof(custs1_led_speed_char), (uint8_t*)&custs1_led_speed_char},
// LED Speed Characteristic Value
[CUST1_IDX_LED_SPEED_VAL] = {CUST1_LED_SPEED_UUID_128, ATT_UUID_128_LEN, PERM(WR, ENABLE), DEF_CUST1_LED_SPEED_CHAR_LEN, 0, NULL},
// LED Speed Characteristic User Description
[CUST1_IDX_LED_SPEED_USER_DESC] = {(uint8_t*)&att_decl_user_desc, ATT_UUID_16_LEN, PERM(RD, ENABLE), sizeof(CUST1_LED_SPEED_USER_DESC) - 1, sizeof(CUST1_LED_SPEED_USER_DESC) - 1, CUST1_LED_SPEED_USER_DESC},
These modifications add another characteristic to our custom GATT database. This allows us to write 8 bit values to the characteristic. Now we will use this value to control the LED blink speed.
Open user_app/user_custs1_impl.h
and add the following function declarations
void app_led_timer_cb_handler(void);
void user_custs1_led_speed_wr_ind_handler(ke_msg_id_t const msgid,
struct custs1_val_write_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id);
In user_app/user_custs1_impl.c
we can implement these functions:
void user_custs1_led_speed_wr_ind_handler(ke_msg_id_t const msgid,
struct custs1_val_write_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
uint8_t val = 0;
memcpy(&val, ¶m->value[0], param->length);
// Modify timer if there is a new value and timer exists
// If timer does not exist, create one.
// If timer exists and value is the same, cancel the timer.
if (timer_led != 0x0000)
{
if(led_speed != val)
{
timer_led = app_easy_timer_modify(timer_led, val);
}
else
{
app_easy_timer_cancel(timer_led);
timer_led = 0x0000;
}
}
else
{
timer_led = app_easy_timer(val, app_led_timer_cb_handler);
}
led_speed = val; // Store LED speed for future reference
}
void app_led_timer_cb_handler()
{
if (led_val == CUSTS1_LED_ON)
GPIO_SetActive(GPIO_LED_PORT, GPIO_LED_PIN);
else if (led_val == CUSTS1_LED_OFF)
GPIO_SetInactive(GPIO_LED_PORT, GPIO_LED_PIN);
led_val = !led_val;
if (ke_state_get(TASK_APP) == APP_CONNECTED)
{
// Set it once again until LED command is received in LED State Characteristic
timer_led = app_easy_timer(led_speed, app_led_timer_cb_handler);
}
}
In order to cancel the LED blinking when the 'TOGGLE LED' button is clicked, we must add the following code to the user_custs1_led_wr_ind_handler
if(timer_led != 0x0000)
{
app_easy_timer_cancel(timer_led);
timer_led = 0x0000;
}
The state of the LED and timer are stored in global variables, add a new timer and two 8 bit unsigned integers to the top of the file (line 37)
ke_msg_id_t timer_used, timer_led;
uint8_t led_speed, led_val;
In user_app/user_peripheral.c
, in the switch case, add the following code to line 262. This will call the function we specified above and will handle the LED blink speed.
case CUST1_IDX_LED_SPEED_VAL:
user_custs1_led_speed_wr_ind_handler(msgid, msg_param, dest_id, src_id);
break;
Save your changes, build the code (F7) and run the code via the debug screen. Open the app on your mobile phone and adjust the slider!
Push buttonThis example uses a GPIO push button from Elektor's Arduino 37 in 1 Sensor Kit. The PCB mounted push button has a built in 10k Ohm resistor connected between the center pin and the 'S' pin and can be used as a pull up or pull down resistor. The push button connects the two outer pins ('S' and ground). We connect the 'S' pin to pin P1_1 on the development kit, and the ground pin to one of the available ground pins on the development kit.
For example, the DA14580 Basic Development Kit will look as follows:
We will use one of the already defined characteristics in our GATT database: CUST1_IDX_BUTTON_STATE_VAL
. We can use this characteristic to enable a notification. Each time new data is available, it will be transferred via Bluetooth to our application.
In user_platform/user_periph_setup.h
define the port and pin of our button:
#define GPIO_BUTTON_PORT GPIO_PORT_1
#define GPIO_BUTTON_PIN GPIO_PIN_1
In user_platform/user_periph_setup.c
we must reserve and configure our GPIO pin. Look for the function called void periph_init(void)
(line 68) and add the following line:
// Initialize button
GPIO_ConfigurePin(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN, INPUT_PULLUP, PID_GPIO, true);
Because we are running the code via Development mode. We must also reserve our GPIO pin. Look for the following reservation (line 55):
RESERVE_GPIO(LED, GPIO_LED_PORT, GPIO_LED_PIN, PID_GPIO);
Below this line, add a new reservation:
RESERVE_GPIO(BUTTON, GPIO_BUTTON_PORT, GPIO_BUTTON_PIN, PID_GPIO);
In user_app/user_custs1_impl.h
declare two functions:
void app_button_press_cb(void);
void app_button_enable(void);
In user_app/user_custs1_impl.c
include wkupct_quadec.h
. This is the driver used to enable the interrupt of our button
#include "wkupct_quadec.h"
and implement the two functions:
// Button press callback function.
void app_button_press_cb(void)
{
struct custs1_val_ntf_req* req = KE_MSG_ALLOC_DYN(CUSTS1_VAL_NTF_REQ,
TASK_CUSTS1,
TASK_APP,
custs1_val_ntf_req,
DEF_CUST1_BUTTON_STATE_CHAR_LEN);
uint8_t button_val = GPIO_GetPinStatus(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN);
req->conhdl = app_env->conhdl;
req->handle = CUST1_IDX_BUTTON_STATE_VAL;
req->length = DEF_CUST1_BUTTON_STATE_CHAR_LEN;
memcpy(req->value, &button_val, DEF_CUST1_BUTTON_STATE_CHAR_LEN);
ke_msg_send(req);
app_button_enable(); // Enable callback again.
}
// Enable push button. Register callback function for button press event
void app_button_enable(void)
{
wkupct_register_callback(app_button_press_cb);
wkupct_enable_irq(WKUPCT_PIN_SELECT(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN), // select pin
WKUPCT_PIN_POLARITY(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN, WKUPCT_PIN_POLARITY_LOW), // polarity low
1, // 1 event
0); // debouncing time = 0
}
Look for the empty function user_custs1_button_cfg_ind_handler
. We will use this function to enable the interrupt for our button.
user_custs1_button_cfg_ind_handler(msgid, msg_param, dest_id, src_id);
In this function, simply call app_button_enable();
to enable the interrupt for our button when the app enables the notification.
void user_custs1_button_cfg_ind_handler(ke_msg_id_t const msgid,
struct custs1_val_write_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
app_button_enable();
}
Save your changes, build the code (F7) and run the app on your phone. Each time you press the button, the background color of the application will randomly change!
Comments