Dialog DA14531 — GPIO, buttons and LEDs

Gowtham TS
Vicara Hardware University
6 min readNov 12, 2020

This tutorial will explain the basics of using GPIOs and Interrupts. To get a brief idea on the DA14531, take a look at the first article in this series: https://medium.com/vicara-hardware-university/dialog-da14-getting-started-62a536109b41

The DA14531 has 12 GPIO pins. On the DA14531 module, 9 pins are accessible. Out of these 9 pins, 2 pins are used for debugging and it’s not a great idea to use them while prototyping.

In this tutorial, we will use one pin to get an input from a button and another pin as an output connected to a LED. You will need a DA14531 Pro DK with the DA14531 module daughterboard to follow this tutorial.

The DA14531 module daughterboard has a button SW2 connected to P0_11 and a LED D2 which is connected to P0_9.

The button is connected to P0_11 in an “Active low” configuration i.e. when the button is pressed, the pin state is LOW. The LED on the other hand is “Active high” i.e. the pin state needs to be set HIGH to turn on the LED.

Project setup

The project with the code for this tutorial is available on Github at https://github.com/vicara-hq/da14531-tutorials

Download the project and copy it. The project has to be placed inside the Dialog SDK6 folder. Navigate to <SDK6_ROOT>/projects/target_apps/template and paste it in this folder. The project is a modified version of the empty_peripheral_template project provided by Dialog. But to keep this tutorial series as open source as possible, all the following steps will use the SmartSnippets Studio.

A brief overview on the project structure

Once the project has been opened in the SmartSnippets Studio, you can observe a large number of folders in the project structure.

All the folders named user_* contain files related to the application code and will be most likely be modified. The folders named sdk_* contain the SDK files and it is advisable to not modify the contents of these files.

The DA14531 project is a bit different from the projects which we find in MCUs like the STM32 or the nRF52. The main function for the DA14531 is not accessible to the user. Instead, the SDK uses a number of callbacks to notify the user that a specific event has completed. The user_callback_config.h file lists all the available callbacks. The user can either write a callback function and assign it to a specific callback. Or they can use a default callback function. Few callbacks can be NULL too.

The user_empty_peripheral_template.c file in the user_app folder is where we add custom callbacks or other user defined functions.

The user_periph_setup.c file holds the code for initializing all the peripherals. So we will need to add the code to initialize the two GPIO pins in this file.

Code Overview

The first thing we will need to do is to configure the GPIOs in the user_periph_setup.c file.

void GPIO_reservations(void) 
{
RESERVE_GPIO(BUTTON, GPIO_PORT_0, GPIO_PIN_11, PID_GPIO);
RESERVE_GPIO(LED, GPIO_PORT_0, GPIO_PIN_9, PID_GPIO);
}
void set_pad_functions(void)
{
GPIO_ConfigurePin(GPIO_PORT_0, GPIO_PIN_11, INPUT_PULLUP, PID_GPIO, false);
GPIO_ConfigurePin(GPIO_PORT_0, GPIO_PIN_9, OUTPUT, PID_GPIO, false);
}

The project can be built in two configurations, with Debug mode enabled or disabled. This can be changed using the CFG_DEVELOPMENT_DEBUG macro in the da1458x_config_basic.h file. It is better to leave it enabled for now.

The RESERVE_GPIO as the name says, reserves a pin for a specific use. In Debug mode, if a unreserved pin is used, the code will crash at run time. The GPIO_ConfigurePin handles the confiiguration of a pin. With this function, you can define the functionality of the pin. We define the button pin i.e. Pin 11 as an input pin with the internal pullup resistor enabled. The LED pin i.e. Pin 9 is configured as an output.

Next, we will create a custom callback function and add it to the callbacks structure. In the user_empty_peripheral_template.c, we add the following functions and variable.

uint8_t last_led_state= 0;void button_callback() 
{
if (last_led_state== 0)
{
last_led_state= 1;
GPIO_SetActive(GPIO_PORT_0, GPIO_PIN_9);
} else
{
last_led_state= 0;
GPIO_SetInactive(GPIO_PORT_0, GPIO_PIN_9);
}
}
void user_app_on_init(void)
{
GPIO_EnableIRQ(GPIO_PORT_0, GPIO_PIN_11, GPIO0_IRQn, true, true, 150);
GPIO_RegisterCallback(GPIO0_IRQn, button_callback);
default_app_on_init();
}

The button_callback function is called every time the button is pressed. In this function, we check the current value of the last_led_state variable and accordingly switch on/off the LED. Tldr; The LED is toggled everytime the button is pressed.

The DA14531 has 5 GPIO interrupts, denoted as GPIOx_IRQn where x is 0 to 4. Any of the GPIO pins can be configured to work with one of these 5 interrupts. The GPIO_EnableIRQ function configures one of the GPIO interrupts to a pin. We also configure the interrupt to be triggered when the pin goes low and wait for the button to get released after the interrupt is reset. The function also allows to add a debounce delay which I have set as 150ms.

The GPIO_RegisterCallback function configures the interrupt to call the button_callback function when the button is pressed.

The user_app_on_init is a custom callback function. This function is called after the DA14531 finishes it’s startup configuration and is ready to start executing the user code. The callback function needs to be defined in the user_callback_config.h file. The app_on_init variable in the user_app_main_loop_callbacks structure needs to be set to the function we have written i.e. user_app_on_init.

static
const struct arch_main_loop_callbacks user_app_main_loop_callbacks = {
.app_on_init = user_app_on_init,
// By default the watchdog timer is reloaded and resumed when the system wakes up.
// The user has to take into account the watchdog timer handling (keep it running,
// freeze it, reload it, resume it, etc), when the app_on_ble_powered() is being
// called and may potentially affect the main loop.
.app_on_ble_powered = NULL,
// By default the watchdog timer is reloaded and resumed when the system wakes up.
// The user has to take into account the watchdog timer handling (keep it running,
// freeze it, reload it, resume it, etc), when the app_on_system_powered() is being
// called and may potentially affect the main loop.
.app_on_system_powered = NULL,
.app_before_sleep = NULL,
.app_validate_sleep = NULL,
.app_going_to_sleep = NULL,
.app_resume_from_sleep = NULL,
};

Build and Test the project

The eclipse project can build for the DA14531, DA14585 and the DA14586. So, we should choose the DA14531 configuration and then build the project.

Choose the DA14531 configuration and then build it. Next we will need to create a debug configuration. Create a configuration similar to the below picture.

Verify that the “C/C++ Application” field is pointing to the correct file. Else you might hit an error saying “Program file does not exist”.

Click on debug and then start the program. You can now press the button on the daughterboard and observe the LED toggle.

--

--