This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Example Using GPIOTE and GPIO modules for future newbs like me

Here is an example main.c which you can use as an example to understand corectly how to use the GPIOTE module and toggle the 4 LEDs numbered 1-4 in the nRF52 DK. Forget about using the BSP as in my opinion its worthless to use functions only usable in the DK, instead you should learn to use the functions and libraries that you will need for the rest of your development cycle.

I hope this saves someone in the future the hours of reading through the infocenter and the other couple hours of going from the "nrf" to the "nrfx" API.

I have documented the code as well as I could with the information I could get, but I am by no means an expert, so please, feel free to correct me if I am wrong

#include "app_error.h"
#include "nrf.h"
#include "nrfx_gpiote.h"
#include <stdbool.h>

//The following defines will only work in the pca10040
//Define the inputs
#define BUTTON_1 13
#define BUTTON_2 14
#define BUTTON_3 15
#define BUTTON_4 16

//Define the outputs
#define LED_1 17
#define LED_2 18
#define LED_3 19
#define LED_4 20

//Separate interrupt handlers for each output pin
//You could also use just one interrupt handler and check which pin generated the interrupt
//But beware, that doing that is also slower, as just one pin can be checked every time the
//device enters the interrupt handler

//Interrupt handler for LED1 on-change interrupt
void Led1InterruptHandler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
  if (nrf_gpio_pin_read(BUTTON_1) == 0) {
    //Print a message
    printf("Button 1 pressed!\r\n");
    //Toggle the pin
    nrf_gpio_pin_write(LED_1, 0);
  } else {
    printf("Button 1 released!\r\n");
    nrf_gpio_pin_write(LED_1, 1);
  }
}

//Interrupt handler for LED2 on-change interrupt
void Led2InterruptHandler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
  if (nrf_gpio_pin_read(BUTTON_2) == 0) {
    //Print a message
    printf("Button 2 pressed!\r\n");
    //Toggle the pin
    nrf_gpio_pin_write(LED_2, 0);
  } else {
    printf("Button 2 released!\r\n");
    nrf_gpio_pin_write(LED_2, 1);
  }
}

//Interrupt handler for LED3 on-change interrupt
void Led3InterruptHandler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
  if (nrf_gpio_pin_read(BUTTON_3) == 0) {
    //Print a message
    printf("Button 3 pressed!\r\n");
    //Toggle the pin
    nrf_gpio_pin_write(LED_3, 0);
  } else {
    printf("Button 3 released!\r\n");
    nrf_gpio_pin_write(LED_3, 1);
  }
}

//Interrupt handler for LED4 on-change interrupt
void Led4InterruptHandler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
  if (nrf_gpio_pin_read(BUTTON_4) == 0) {
    //Print a message
    printf("Button 4 pressed!\r\n");
    //Toggle the pin
    nrf_gpio_pin_write(LED_4, 0);
  } else {
    printf("Button 4 released!\r\n");
    nrf_gpio_pin_write(LED_4, 1);
  }
}

/**
 * @brief Function for application main entry.
 */
int main(void) {
  //Initialization of GPIOTE

  ret_code_t err_code; //The result from the config functions

  //Check if the GPIOTE is initialized
  if (nrfx_gpiote_is_init() == NULL) {
    //If its not initialized, init it now
    err_code = nrfx_gpiote_init(); //Init the GPIO interrupt and tasks
    APP_ERROR_CHECK(err_code); //Check the error code 
    //(0x8 means the GPIOTE module is already enabled)
  }

  //Set the input configuration to interrupt on status change
  nrfx_gpiote_in_config_t inConfig = NRFX_GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
  inConfig.pull                    = NRF_GPIO_PIN_PULLUP;

  //When the interrupt occurs in pin "BUTTON_x", configured as "inConfig", the interrupt
  //will execute the function "LedxInterruptHandler"
  err_code = nrfx_gpiote_in_init(BUTTON_1, &inConfig, Led1InterruptHandler);
  APP_ERROR_CHECK(err_code);
  
  //initialize the button 2 for on-change interrupt, and set the handler function
  err_code = nrfx_gpiote_in_init(BUTTON_2, &inConfig, Led2InterruptHandler);
  APP_ERROR_CHECK(err_code);

  //initialize the button 3 for on-change interrupt, and set the handler function
  err_code = nrfx_gpiote_in_init(BUTTON_3, &inConfig, Led3InterruptHandler);
  APP_ERROR_CHECK(err_code);
  
  //initialize the button 4 for on-change interrupt, and set the handler function
  err_code = nrfx_gpiote_in_init(BUTTON_4, &inConfig, Led4InterruptHandler);
  APP_ERROR_CHECK(err_code);

  //Enable the input change interrupt on button 1-4
  nrfx_gpiote_in_event_enable(BUTTON_1, true);
  nrfx_gpiote_in_event_enable(BUTTON_2, true);
  nrfx_gpiote_in_event_enable(BUTTON_3, true);
  nrfx_gpiote_in_event_enable(BUTTON_4, true);

  //Set the configuration as a simple output
  //I AM SURE YOU CAN CHANGE THE OUTPUT OF A PIN USING TASKS, BUT I DO NOT KNOW HOW TO
  //SO I DO NOT KNOW WHAT THESE INIT FUNCTIONS DO
  //TO TOGGLE THE LEDs I HAVE USED "nrf_gpio_pin_write"
  nrfx_gpiote_out_config_t out_config = NRFX_GPIOTE_CONFIG_OUT_SIMPLE(true);

  //Initialize the outputs for LEDs 1-4
  err_code = nrfx_gpiote_out_init(LED_1, &out_config);
  APP_ERROR_CHECK(err_code);

  err_code = nrfx_gpiote_out_init(LED_2, &out_config);
  APP_ERROR_CHECK(err_code);

  err_code = nrfx_gpiote_out_init(LED_3, &out_config);
  APP_ERROR_CHECK(err_code);

  err_code = nrfx_gpiote_out_init(LED_4, &out_config);
  APP_ERROR_CHECK(err_code);

  while (true) {
    // Do nothing. Everything is handled in the interrupts
  }
}

/** @} */

  • Right, sorry I forgot to actually explain what the code does..

    When you press a button a LED will light and a message will be send to the IDE's console stating when the button was pressed and when it was released.

    Button one lights up LED 1 and so on..

    You can see to which pin each button and LED is connected when you turn around the board.. there's a table there telling you where and how each button and LED is connected. You see there that a pullup is needed in the button pins so we dont leave the terminal floating when the button is not pressed.

    When a button is pressed an interrupt (or an event, idk how you call it) is generated. The microcontroller knows which handler to call because you told him when you called "nrfx_gpiote_in_init" the last argument is the function the generated interrupt is going to call.

    Again.. please review the code, and if you have any questions I will answer them as well as I can. It took me hours to the this thing working, I hope I am saving someone some time.

  • To run this remember to set in GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 4 in sdk_config.h

Related