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

Nrf51822 stops handling GPIOTE->PORT interrupts

Hi engineers, Here we are facing a critical problem in which the NRF51822 stops handling/processing the GPIOTE->PORT interrupts after some days good working. This problem is occurring randomly whereby our system will stop working completely. Then, we have to remove the Battery to restart it again. We have two resources on NRF chip that are interrupting on GPIOTE: an Accelerator sensor and a Button.

We already are using this button to start advertising and also to show our connection status using LED and as well the accelerator announces the user's movement on GPIOTE->PORT.

We are handling these interrupts in low-sensitive mode, means the sensor will keep its interrupt PIN in low until we go to process it by reading the related register and as well to release the PIN in order to capture the further interrupts.

The button is connected to another PIN directly and its other side is connected to GND.

  NRF_GPIO->PIN_CNF[ACC_SENSOR_INT_PIN_NUMBER] =      \
    (GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos) \
  | (GPIO_PIN_CNF_DRIVE_S0S1     << GPIO_PIN_CNF_DRIVE_Pos) \
  | (GPIO_PIN_CNF_PULL_Pullup    << 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);
  NRF_GPIO->PIN_CNF[BUTTON_0] =      \
  (GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos) \
| (GPIO_PIN_CNF_DRIVE_S0S1     << GPIO_PIN_CNF_DRIVE_Pos) \
| (GPIO_PIN_CNF_PULL_Pullup    << 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;
  NVIC_ClearPendingIRQ(GPIOTE_IRQn);
  /* Processing button interrupt */
  if((NRF_GPIO->IN & (1<<BUTTON_0))?0:1)/* key pressed */
  {
    nrf_delay_ms(1000);
    if((NRF_GPIO->IN & (1<<BUTTON_0))?0:1)/* key pressed */
    {
      nrf_delay_ms(1000);
      if((NRF_GPIO->IN & (1<<BUTTON_0))?0:1)/* key pressed */
      {
        nrf_delay_ms(1000);
        if((NRF_GPIO->IN & (1<<BUTTON_0))?0:1)/* key pressed */
          NVIC_SystemReset(); // Bye! Use the button to reset when it has pressed down for 3 seconds.
      }
    }
    if(m_conn_handle != BLE_CONN_HANDLE_INVALID) /* is connected */
    {
      InOutSetReset( LED_0, true );
      nrf_delay_ms(3000);
      InOutSetReset( LED_0, false );//It turns on for 3 seconds showing us the connection is active
    }
    else if(bsp_evt_cb)
      bsp_evt_cb(ACC_EVT_WAKE_UP);//Start advertising
  }
  
  
  /* Processing sensor interrupt/registers*/
  //
  ///
  {Sensor registers will be read here.}
  //
  {Sensor will be released here}
}

As a result, we are seeing that our system stops working randomly during a week/day working since we didn't get any interrupt on GPIOTE. It seems there is a similar state on each time having this problem where the Interrupt PIN of the accelerator sensor is yet low. So as we didn't get another interrupt on GPIOTE of both sensor and Button, our system has almost died.

Please consider that we are just losing the interrupts, and the NRF51 is alive as we are running a timer that turns LED with 1 minutes interval.

  • You should say which SD if any you are using.

    Also, I'm not really crazy about those nrf_delay statements. The delay routine literally holds the processor up running NOP's until the delay is over. It is a huge waste of power (significant if battery operated) and also could cause issues with the queuing of ISR's. If you are running the SD there are many tasks that require ISR's and you could simply be overflowing the NVIC. A better way to keep LED's on. or do some other delay is to use the app_timer.

  • @sansei: Please be aware that the DETECT signal is shared between all pins. Meaning if one pin is keeping the DETECT signal high, it will block the GPIOTE PORT even to trigger again by other pins.

    With your setup, I don't see how you can handle the scenario where the button is pressed at the point that you are processing the SENSOR, it will keep the DETECT signal high, and blocks the GPIOTE PORT event to be triggered. This mean the button press will never be handled and if the SENSOR is triggered again, it will too, won't be processed by the CPU. The result is a deadlock and you will see that the device won't respond to the button press to reset.

    So basically, a PORT even can only be triggered if all of the triggers (GPIO pin with SENSE enable) are inactive. You will have to either do a loop to wait and process all the pin before you clear the event NRF_GPIOTE->EVENTS_PORT = 0; or you have to invert the SENSE polarity so that the holding pin won't hold the DETECT signal any more.

    Another option is to use GPIOTE PIN event, so that they don't share the same DETECT trigger, but current consumption of GPIOTE PIN is much higher than GPIOTE PORT.

Related