nRF52: Buttons and LEDs


Prerequisites:

To proceed with this tutorial, you will need a nRF52 Development kit and have Segger Embedded Studio installed on your computer. You will also need to have the nRF5 SDK downloaded and extracted. You can refer the last post [TODO: enter first post name]

nRF52 Development Kit (DK):

Image for post

The nRF52 DK has a nRF52832 as it’s core. It also has 4 LEDs, 4 buttons and Segger J-Link for debugging. It also has a Virtual COM port which means that you will not need a USB to TTL adapter. This will come in handy in the UART post.

The nRF52 DK can also simulate the functioning of a nRF52810 i.e. you can develop for a nRF52832 or a nRF52810. This DK is denoted by the code pca10040. The pca10040e projects simulate the nRF52810

General Purpose Input / Output (GPIO) Pins:

The nRF52832 has 32 pins which make up Port 0. The pins are denoted as P0.x where x is the pin number ranging from 0 to 31. The GPIO pins can be mapped to almost all the peripherals with a few exceptions.

The nRF52 DK has 4 buttons and 4 LEDs. They are connected to the following pins:

Image for post

The buttons and LEDs are active LOW i.e. when the button is pressed, the state of the pin will be LOW as it get’s connected to GROUND. Similarly, the LEDs are connected to VDD and can be turned on when the pin state is LOW.

Image for post

To detect the button press i.e. to detect when the pin goes LOW, we need to use a pull-up resistor. A pull up resistor keeps the state of the pin HIGH. One terminal of the pull up resistor is connected to the pin while the other terminal is connected to VDD. Similarly, pull down resistors pull the pin state to LOW by connecting to ground. The GPIOs on the nRF52832 have configurable pull up/down resistors connected internally. The typical value of the internal pull up/down resistors is 13 kΩ.

Image for post

Creating the project:

  • Navigate to the location where you have extracted the nRF5 SDK.
  • Go to “examples/peripheral”.
  • Search for a project named “template_project”.
  • Copy it and rename the folder.
  • Open the copied folder and go to “pca10040/blank/ses/”.
  • Open the “template_pca10040.emProject” file.
  • In the opened SES window, you can observe a list of folders on the left under “Project items”. Right click on the nRF_micro folder and select “Exclude from build”

If the last step is missed, you will get the following error:

Image for post

Code overview:


#include "nrf_gpio.h"
#include "nrf_delay.h"

The above two headers need to be included. “nrf_gpio.h” includes the functions for controlling the GPIO and “nrf_delay.h” has the nrf_delay_msfunction which is a very easy method to introduce delays


#define LED_1       17
#define LED_2       18
#define LED_3       19
#define LED_4       20
#define BUTTON_1    13
#define BUTTON_2    14
#define BUTTON_3    15
#define BUTTON_4    16
#define DEBOUNCE_MS 150

It is a good practice to define all constants like the pin numbers for the LEDs and buttons should be defined as macros. The DEBOUNCE_MS macro is quite essential for properly detecting a button press. When we press a button, we assume that it is simple transition from HIGH to LOW state. But when we look at the electrical signal, there are often multiple transitions when the two pieces of metal in the button make contact. Once they are properly conducting, the signal is stable. The debounce delay is to avoid these transitions. There are multiple hardware and software methods on fixing the debounce problem but the easiest is to use a delay. I have used a delay of 150ms but this can be changed according to what you feel is suitable for you. You can try different values between 50 ms to 500ms and notice the difference in behaviour of the LEDs.




static void gpio_init()
{
   nrf_gpio_cfg_input(BUTTON_1, NRF_GPIO_PIN_PULLUP);
   nrf_gpio_cfg_input(BUTTON_2, NRF_GPIO_PIN_PULLUP);
   nrf_gpio_cfg_input(BUTTON_3, NRF_GPIO_PIN_PULLUP);
   nrf_gpio_cfg_input(BUTTON_4, NRF_GPIO_PIN_PULLUP);    nrf_gpio_cfg_output(LED_1);
   nrf_gpio_cfg_output(LED_2);
   nrf_gpio_cfg_output(LED_3);
   nrf_gpio_cfg_output(LED_4);
}

This function holds the code which initializes pins as inputs or outputs.

nrf_gpio_cfg_input configures the specified pin as an input. It takes the pin number and pull configuration as it’s parameters. The pull configuration can be pull up, pull down or no pull.

nrf_gpio_cfg_output configures a pin as an output pin and takes the pin number as a parameter.



int main(void)
{
   gpio_init();
   while (true)
   {
      if(!nrf_gpio_pin_read(BUTTON_1))
      {
           nrf_delay_ms(DEBOUNCE_MS);
           if(!nrf_gpio_pin_read(BUTTON_1))
           {
               nrf_gpio_pin_toggle(LED_1);
           }
      }
      else if(!nrf_gpio_pin_read(BUTTON_2))
      {
           nrf_delay_ms(DEBOUNCE_MS);
           if(!nrf_gpio_pin_read(BUTTON_2))
           {
               nrf_gpio_pin_toggle(LED_2);
           }
      }
      else if(!nrf_gpio_pin_read(BUTTON_3))
      {
           nrf_delay_ms(DEBOUNCE_MS);
           if(!nrf_gpio_pin_read(BUTTON_3))
           {
               nrf_gpio_pin_toggle(LED_3);
           }
      }
      else if(!nrf_gpio_pin_read(BUTTON_4))
      {
           nrf_delay_ms(DEBOUNCE_MS);
           if(!nrf_gpio_pin_read(BUTTON_4))
           {
               nrf_gpio_pin_toggle(LED_4);
           }
      }
   }
}

This block of code is placed in an infinite while in main. It constantly checks for the state of each pin. If a pin goes LOW, we wait for 150ms and then check the pin state again. If the pin state is still LOW, then we toggle the state of the respective LED’s pin.

Build the project and program the nRF52 DK. All the LEDs should be on. Pressing a button will toggle the respective LED i.e. pressing button 1 will toggle LED 1.