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

Using more than 4 buttons with GPIOTE interrupts

Hi,

I am using GPIOTE interrupts to detect button presses. It works fine but there are only four channels in GPIOTE->EVENTS_IN[] and each channel can only be assigned to one pin. How should I do if I want to implement more than 4 buttons?

Basically I set up GPIOTE like this:

  pinInput(pin); // make sure the pin is set as input
  NRF_GPIOTE->CONFIG[channel] = (static_cast<uint32_t>(transitionMode) << GPIOTE_CONFIG_POLARITY_Pos) |
      (pin << GPIOTE_CONFIG_PSEL_Pos) |
      (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);
  NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN0_Set << channel; // @warning: we should use bitfields instead
  NRF_GPIOTE->EVENTS_IN[channel] = 0;

and in the GPIOTE_IRQHandler I check which channel has been interrupted and send an appropriate callback.

I do not use any sd by the way.

Thanks!

  • instead of using GPIOTE channels use GPIOTE->PORT event, then you can have 31 buttons .. There are lot of examples for this. In GPIOTE_IRQHandler, you have to remember previous pin state to see which pin has changed state.

  • Hi Aryan,

    Thanks for your reply. I tried using port but I am having som problems with it. In my test program I want to use one button to toggle a green LED. In a while loop a red LED is blinking. When I press the button the green LED is not toggled and the red LED stops blinking, I interpret that as that the program is stuck somewhere. I can't figure out why this does not work. Can you see the problem in my code?

    void GPIOTE_IRQHandler(void) {
      // If PORT event has been called, clear event and toggle LED
      if (NRF_GPIOTE->EVENTS_PORT) {
        NRF_GPIOTE->EVENTS_PORT = 0;
    
        pinToggle(LED_GREEN);
      }
    }
    
    int main() {
      setupLEDPins();
    
      // Set Menu button as input
      nrf_gpio_cfg_input(BUTTON_MENU_PIN, NRF_GPIO_PIN_NOPULL);
    
      // Enable sense on the Menu button
      nrf_gpio_cfg_sense_input(BUTTON_MENU_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_LOW);
    
      // Set the GPIOTE PORT event as interrupt source
      NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Msk;
    
      // Enable interrupts for GPIOTE
      NVIC_EnableIRQ(GPIOTE_IRQn);
    
      // Toggle red LED to show life sign
      while (1) {
        pinToggle(LED_RED);
        delayMs(100);
      }
      return 0;
    }
    
  • is this your full code?, it cannot get stuck here. Is there any part of your code that has APP_ERROR_CHECK? are you doing anything else apart from this with BLE?

  • Hi Aryan, yes, that is basically all code. Made some modifications and used nrf_gpio_cfg_output and nrf_gpio_pin_toggle instead of my own gpio functions and added

    NVIC_ClearPendingIRQ(GPIOTE_IRQn); NVIC_SetPriority(GPIOTE_IRQn, 3);

    before NCIV_EnableIRQ(GPIOTE_IRQn);

    but I still get the same result. I am not using APP_ERROR_CHECK or any softdevice.

    I also have a hard time understanding how it can get stuck. I read that SENSE is used to wake up the nrf, could it be that it does something to the power state of the CPU? Or could it be that the interrupt is called continuously of some reason blocking the execution of the program?

    Can you recommend any good examples where the PORT event is used to read buttons?

    Thanks!

  • sorry for late reply, you need to debug this, where did it get stuck? i cannot see anycode here where it can get stuck. What you have written is a valid code(except that your green led will be toggled for any port event) and should be enough to fulfill your purpose. The only example i found is in the app_gpiote library, check how they use port events

    nRF51_SDK_9.0.0_5fc2c3a\components\libraries\gpiote\app_gpiote_fast_detect.c
    
Related