nRF52840: How to disable latch detect in SDK v17 GPIO interrupts?

We are in the process of porting from nRF SDK v15.3.0 to v17.1.0.

After updating, we’ve noticed that the device sometimes gets stuck. Investigation shows this is related to GPIO interrupt handling.

The nRF52840 supports two wakeup detect modes: Default detect (non-latch) and Latch detect (LDETECT). In our use case the interrupt source is not an edge but a signal that can stay active (high or low).

SDK v17 introduces new latch handling in the GPIO library. For nRF52840, this is always enabled through NRF_GPIO_LATCH_PRESENT macro.

We never explicitly enable latch mode (via NRF_GPIO->DETECTMODE = GPIO_DETECTMODE_DETECTMODE_LDETECT << GPIO_DETECTMODE_DETECTMODE_Pos;), however the ISR still uses latch detect clearing mechanisms even when this is not enabled.

Because our interrupt signals can stay active, the latch never resets → the MCU ends up stuck in the loop inside port_event_handle(uint32_t * latch) (called from interrupt context). This effectively makes every GPIO interrupt susceptible to the same issue if the input signal stays asserted.

We tested by commenting out #define NRF_GPIO_LATCH_PRESENT, and then everything works fine without latch handling — but this is not expected behaviour. We don’t want to modify the SDK just to achieve this. Is there a supported way to disable latch detect without patching the SDK?

Parents
  • Hello,

    I have not been able to find any other similar reports with this issue. The latch register is used to reduce the chance of missing pin events, which can occur more easily when multiple pins have sense enabled in applications where the GPIOTE IRQ may be blocked or preempted by other interrupts.

    The driver doesn't enable the LDETECT mode, so the latch register bits are not going trigger the PORT event either. The driver will always uses the LATCH register as long as it's supported by the HW (indicated by the presence of the NRF_GPIO_LATCH_PRESENT symbol). This was not designed to be configurable as there are no known drawbacks of using it. It should only make the interrupt handling more robust.

    Because our interrupt signals can stay active, the latch never resets → the MCU ends up stuck in the loop inside port_event_handle(uint32_t * latch) (called from interrupt context). This effectively makes every GPIO interrupt susceptible to the same issue if the input signal stays asserted.

    Note that the sense level is reconfigured in the ISR to prevent exactly this:

    Is the input signal free of glitches?

    Best regards,

    Vidar

  • Thanks for the quick response.

    I don’t think the input signal is completely glitch-free, since it is triggered by the charger connector — that’s probably why the port event is firing.

    From what I observe, it ends up calling port_event_handle, and then contuine; on the below check, so the level reconfiguration is not happening, continues again on the while loop non stop. 

    How to configure this properly ?

    nrfx_gpiote_in_config_t interruptConfig = {
        .sense = NRF_GPIOTE_POLARITY_TOGGLE,
        .pull = NRF_GPIO_PIN_NOPULL,
        .is_watcher = false,
        .hi_accuracy = true,
        .skip_gpio_setup = true,
    };

    I tried configuring .hi_accuracy = false, to force use port events. But still the behaviour is similar, as it is unable to find a matching latch bit set in following, if (nrf_bitmask_bit_is_set(pin, latch))


    I have not been able to find any other similar reports with this issue. The latch register is used to reduce the chance of missing pin events, which can occur more easily when multiple pins have sense enabled in applications where the GPIOTE IRQ may be blocked or preempted by other interrupts.

    The driver doesn't enable the LDETECT mode, so the latch register bits are not going trigger the PORT event either. The driver will always uses the LATCH register as long as it's supported by the HW (indicated by the presence of the NRF_GPIO_LATCH_PRESENT symbol). This was not designed to be configurable as there are no known drawbacks of using it. It should only make the interrupt handling more robust.

    I’m not sure I fully understand — if LDETECT is not enabled, how does using the LATCH register make the interrupt handling more robust?


    As per the nRF documentation I see: A PORT event is triggered if the DETECT signal was low before enabling the sense mechanism”. If I understand correctly, the current port event handler doesn’t account for this case.

  • With this approach we still have an issue.

    If the input latch signal is asserted while enabling WAKEUP sense, we still run in to the same problem. 

  • Not sure what the input latch signal refers to in this context, but does the wake-up signal change between active low and active high? In that case, couldn’t you just read the input first and then set the appropriate sense level (low to high or high to low)?

  • It is always configured as sense on LOW. I could read the input first and then set the appropriate sense level, but that doesn’t sound very robust — if it’s missed once, the device can end up stuck.

  • Just to confirm, you only want the device to wake up when the signal goes from high to low? And in that case, is the issue that the signal is sometimes already low when you try to enter system OFF?

  • For example, we use wake-up sense to detect charger input or button press. If the device starts with the charger already connected, the input is already LOW. Enabling wake-up sense on LOW at this time causes the device to get stuck in the same port_event_handle() ISR. It works fine if the charger is not connected (input HIGH) when enabling.

    Similarly, if a button gets stuck/jammed and stays LOW, we could run into the same issue, making it harder to detect the actual cause.

Reply
  • For example, we use wake-up sense to detect charger input or button press. If the device starts with the charger already connected, the input is already LOW. Enabling wake-up sense on LOW at this time causes the device to get stuck in the same port_event_handle() ISR. It works fine if the charger is not connected (input HIGH) when enabling.

    Similarly, if a button gets stuck/jammed and stays LOW, we could run into the same issue, making it harder to detect the actual cause.

Children
  • For example, we use wake-up sense to detect charger input or button press. If the device starts with the charger already connected, the input is already LOW

    This is was the assumption I made when you said the signal came from a charger earlier, and is why I meant ask if the active level would change depending on the charger state at the time of entering system off. How were you handling this in the previous version? Also, were you using GPIOTE PORT events or GPIO IN events previously?

    causes the device to get stuck in the same port_event_handle()

    This indicates that the input pin has not been disabled in the GPIOTE driver. In any case, if you set the sense level to low and the input is low, the device will immediately wake up again if you try to enter system off.

  • This is was the assumption I made when you said the signal came from a charger earlier, and is why I meant ask if the active level would change depending on the charger state at the time of entering system off. How were you handling this in the previous version? Also, were you using GPIOTE PORT events or GPIO IN events previously?

    With SDK 15, currently both .hi_accuracy=true and NRF_GPIO_PIN_SENSE_LOW is enabled. So I assume it uses both GPIOTE PORT events and GPIO IN events.

    Now with SDK 17, currently I am setting .hi_accuracy=false for pins which configure wakeup sense. 

    This indicates that the input pin has not been disabled in the GPIOTE driver. In any case, if you set the sense level to low and the input is low, the device will immediately wake up again if you try to enter system off.

    On power up we are doing, nrf_gpio_cfg(pin, NRF_GPIO_PIN_DIR_INPUT, NRF_GPIO_PIN_INPUT_CONNECT, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_SENSE_LOW);. It straight away goes stuck at port_event_handle() if the input is already low, with SDK 17. 

  • On power up we are doing, nrf_gpio_cfg(pin, NRF_GPIO_PIN_DIR_INPUT, NRF_GPIO_PIN_INPUT_CONNECT, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_SENSE_LOW);. It straight away goes stuck at port_event_handle() if the input is already low, with SDK 17. 

    The DETECT signal is not going to be deasserted until either the SENSE or input level changes. 

    It straight away goes stuck at port_event_handle() if the input is already low, with SDK 17. 

    And this is with .high_accuracy=true for that particular pin?

  • And this is with .high_accuracy=true for that particular pin?

    Based on my tests, it behaves same in this case with .hi_accuracy true / false. 

  • This should not occur if the pin has already been initialized and enabled in the GPIOTE driver, as that would cause execution to reach this code and release the DETECT signal:

    It's also redundant to run enable sense with nrf_gpio_cfg() when it's already done by the GPIOTE driver (in case of .high_accuracy=false). 

Related