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

NRF_GPIO->IN reading wrong value/pin

Hello,

I have the following issue when trying to detect which GPIO triggered the interrupt:

For my low power application, I was trying to connect two switches to the nRF52DK, via the GPIOs (11 and 12).

The switches are connected between GND and VCC and therefore do not need a pull up. I configured the GPIOs in SW_PIN_CONFIG.

Using the nrf GPIOTE driver works, but I wanted a solution that consumes less power, as this is for a low power application.

Therefore, I was looking at the way the buttons of the DK are used in simple_hal.c

Implementing the switches in a similar way, they worked and toggled each the right if clause.

However they would both have to be high, before one switch could toggle an interrupt. If one switch was low it wouldn't work for some reason.

void GPIOTE_IRQHandler(void)
{
    NRF_GPIOTE->EVENTS_PORT = 0;
    
    if (TIMER_DIFF(m_last_button_press, NRF_RTC1->COUNTER) > HAL_BUTTON_PRESS_FREQUENCY)
    {
      // SW 1 Low
      if ((NRF_GPIO->IN & (1 << 11)) == 0)
      {
          m_button_handler_cb(0);
      }

      // SW 2 Low
      if ((NRF_GPIO->IN & (1 << 12)) == 0)
      {
          m_button_handler_cb(1);
      }

      m_last_button_press = NRF_RTC1->COUNTER;

    }
}

This was weird, but since I wanted the switches to trigger an interrupt on both edges anyways, I continued and added this functionality as well.

#define SW_PIN_CONFIG_LOW ((GPIO_PIN_CNF_SENSE_Low  << GPIO_PIN_CNF_SENSE_Pos)    | \
                           (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)    | \
                           (NRF_GPIO_PIN_NOPULL     << GPIO_PIN_CNF_PULL_Pos)     | \
                           (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | \
                           (GPIO_PIN_CNF_DIR_Input  << GPIO_PIN_CNF_DIR_Pos))

#define SW_PIN_CONFIG_HIGH ((GPIO_PIN_CNF_SENSE_High    << GPIO_PIN_CNF_SENSE_Pos)    | \
                           (GPIO_PIN_CNF_DRIVE_S0S1     << GPIO_PIN_CNF_DRIVE_Pos)    | \
                           (NRF_GPIO_PIN_NOPULL         << GPIO_PIN_CNF_PULL_Pos)     | \
                           (GPIO_PIN_CNF_INPUT_Connect  << GPIO_PIN_CNF_INPUT_Pos)    | \
                           (GPIO_PIN_CNF_DIR_Input      << GPIO_PIN_CNF_DIR_Pos))

void GPIOTE_IRQHandler(void)
{
    NRF_GPIOTE->EVENTS_PORT = 0;
    
    if (TIMER_DIFF(m_last_button_press, NRF_RTC1->COUNTER) > HAL_BUTTON_PRESS_FREQUENCY)
    {
      // SW 1 Low
      if ((NRF_GPIO->IN & (1 << 11)) == 0)
      {
          m_button_handler_cb(0);
          NRF_GPIO->PIN_CNF[11] = SW_PIN_CONFIG_HIGH;
      }

      // SW 1 return to High
      else if (NRF_GPIO->IN & (1 << 11))
      {
          m_button_handler_cb(0);
          NRF_GPIO->PIN_CNF[11] = SW_PIN_CONFIG_LOW;
      }

      // SW 2 Low
      if ((NRF_GPIO->IN & (1 << 12)) == 0)
      {
          m_button_handler_cb(1);
          NRF_GPIO->PIN_CNF[12] = SW_PIN_CONFIG_HIGH;
      }

      // SW 2 return to High
      else if (NRF_GPIO->IN & (1 << 12))
      {
          m_button_handler_cb(1);
          NRF_GPIO->PIN_CNF[12] = SW_PIN_CONFIG_LOW;
      }

      m_last_button_press = NRF_RTC1->COUNTER;

    } // End debounce if
}

This is where stuff got really confusing.

Looking at the LOG output (since NRF_GPIO->IN is restricted memory, that I cannot debug) it does seem like one pin is triggering both if clauses.

Which, if I'm not wrong, should be impossible since x & 1<11 is not the same as x & 1<<12.

So the interrupt basically calls m_button_handler_cb(0) and m_button_handler_cb(1) every time the status of one switch changes.

Is there something wrong with the way I'm checking for the PIN, that toggled the interrupt? Or is there a simpler approach (that is not increasing the power consumption).

Thank you for your help.

Sincerely,

Heiner

Related