nrfx_gpiote_irq_handler() stucks when using TWIM

Hi Community,

i recently migrated from sdk16 to sdk17 and I am using FreeRTOS.

My goal is to catch pin interrupts which already worked before migrating. Now I have the problem that if I execute

    err_code = nrf_drv_gpiote_init();
    APP_ERROR_CHECK(err_code);

static void port_event_handle(uint32_t *latch) {
    int i = 0;
    do {
        i++;
        for (uint32_t i = 0; i < NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS; i++) {
            if (m_cb.port_handlers_pins[i] == PIN_NOT_USED) {
                continue;
            }

            /* Process pin further only if LATCH bit associated with this pin was set. */
            nrfx_gpiote_pin_t pin = port_handler_pin_get(i);
            if (nrf_bitmask_bit_is_set(pin, latch)) {
                nrf_gpiote_polarity_t polarity = port_handler_polarity_get(i);
                nrf_gpio_pin_sense_t sense = nrf_gpio_pin_sense_get(pin);

                NRFX_LOG_DEBUG("PORT event for pin: %d, polarity: %d.", pin, polarity);

                /* Reconfigure sense to the opposite level, so the internal PINx.DETECT signal
                 * can be deasserted. Therefore PORT event generated again,
                 * unless some other PINx.DETECT signal is still active. */
                nrf_gpio_pin_sense_t next_sense = (sense == NRF_GPIO_PIN_SENSE_HIGH) ? NRF_GPIO_PIN_SENSE_LOW : NRF_GPIO_PIN_SENSE_HIGH;
                nrf_gpio_cfg_sense_set(pin, next_sense);

                /* Try to clear LATCH bit corresponding to currently processed pin.
                 * This may not succeed if the pin's state changed during the interrupt processing
                 * and now it matches the new sense configuration. In such case,
                 * the pin will be processed again in another iteration of the outer loop. */
                nrf_gpio_pin_latch_clear(pin);

                /* Invoke user handler only if the sensed pin level
                 * matches its polarity configuration. */
                nrfx_gpiote_evt_handler_t handler = channel_handler_get((uint32_t)channel_port_get(pin));
                if (handler &&
                    ((polarity == NRF_GPIOTE_POLARITY_TOGGLE) || (sense == NRF_GPIO_PIN_SENSE_HIGH && polarity == NRF_GPIOTE_POLARITY_LOTOHI) ||
                     (sense == NRF_GPIO_PIN_SENSE_LOW && polarity == NRF_GPIOTE_POLARITY_HITOLO))) {
                    handler(pin, polarity);
                }
            }
        }
        if (i > 100) {
            break;
        }
    } while (latch_pending_read_and_check(latch));

soon the interrupt handler is executed and it seems it stucks at the loop

//nfrx_gpio.c
static void port_event_handle(uint32_t *latch) {
    int i = 0; 
    do {
        i++;
        for (uint32_t i = 0; i < NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS; i++) {
            if (m_cb.port_handlers_pins[i] == PIN_NOT_USED) {
                continue;
            }

            /* Process pin further only if LATCH bit associated with this pin was set. */
            nrfx_gpiote_pin_t pin = port_handler_pin_get(i);
            if (nrf_bitmask_bit_is_set(pin, latch)) {
                nrf_gpiote_polarity_t polarity = port_handler_polarity_get(i);
                nrf_gpio_pin_sense_t sense = nrf_gpio_pin_sense_get(pin);

                NRFX_LOG_DEBUG("PORT event for pin: %d, polarity: %d.", pin, polarity);

                /* Reconfigure sense to the opposite level, so the internal PINx.DETECT signal
                 * can be deasserted. Therefore PORT event generated again,
                 * unless some other PINx.DETECT signal is still active. */
                nrf_gpio_pin_sense_t next_sense = (sense == NRF_GPIO_PIN_SENSE_HIGH) ? NRF_GPIO_PIN_SENSE_LOW : NRF_GPIO_PIN_SENSE_HIGH;
                nrf_gpio_cfg_sense_set(pin, next_sense);

                /* Try to clear LATCH bit corresponding to currently processed pin.
                 * This may not succeed if the pin's state changed during the interrupt processing
                 * and now it matches the new sense configuration. In such case,
                 * the pin will be processed again in another iteration of the outer loop. */
                nrf_gpio_pin_latch_clear(pin);

                /* Invoke user handler only if the sensed pin level
                 * matches its polarity configuration. */
                nrfx_gpiote_evt_handler_t handler = channel_handler_get((uint32_t)channel_port_get(pin));
                if (handler &&
                    ((polarity == NRF_GPIOTE_POLARITY_TOGGLE) || (sense == NRF_GPIO_PIN_SENSE_HIGH && polarity == NRF_GPIOTE_POLARITY_LOTOHI) ||
                     (sense == NRF_GPIO_PIN_SENSE_LOW && polarity == NRF_GPIOTE_POLARITY_HITOLO))) {
                    handler(pin, polarity);
                }
            }
        }
        if (i > 100) { //<-- only works if i do this
            break;
        }
    } while (latch_pending_read_and_check(latch));
gpiogg

I can break the loop as shown above but this is not a beautiful solution. It is also interesting that no pin has to be defined as a gpiote pin to reproduce the problem and i think that the interrupt often happens when the twim module is used.

I am a bit lost in and i don't have any clue anymore what could be the reason for that loop.

My sdkconfig:

// <e> GPIOTE_ENABLED - nrf_drv_gpiote - GPIOTE peripheral driver - legacy layer
//==========================================================
#ifndef GPIOTE_ENABLED
#define GPIOTE_ENABLED 1
#endif
// <o> GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS - Number of lower power input pins
#ifndef GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS
#define GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 4
#endif

// <o> GPIOTE_CONFIG_IRQ_PRIORITY  - Interrupt priority

// <i> Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice
// <0=> 0 (highest)
// <1=> 1
// <2=> 2
// <3=> 3
// <4=> 4
// <5=> 5
// <6=> 6
// <7=> 7

#ifndef GPIOTE_CONFIG_IRQ_PRIORITY
#define GPIOTE_CONFIG_IRQ_PRIORITY 6
#endif

regards

Parents
  • Hi,

    The code is a bit confusing

    static void port_event_handle(uint32_t *latch) {
        int i = 0; 
        do {
            i++;
            for (uint32_t i = 0; i < NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS; i++) {

    There seems to be two definitions of "i" and I am not sure why you need the "int i = 0;" definition in your code. 
    I have not seen this before, and it does not make sense that the for loop keep on advancing even though you clearly mentioned GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS to 4. Can you reproduce this on nRF52832 DK? Can you give me a minimalistic project to reproduce this?

    I can break the loop as shown above but this is not a beautiful solution.

    No, that solution looks very ugly. Can you remove the another definition of "i" and make sure that there are no other definitions of GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS anywhere in your code?

  • Hi,

    You are perfectly right that it is an ugly solution. The problem was that this was quick check if that is the endless loop which is responsible for blocking the system. GCC did not complain so I didnt see that there is a naming conflict. As I found out the system works if i break the loop after 100 passes and the loop's break condition is the reason why the system blocks.

    I later found out that this happens if a pin is configured as SENSE but the GPIOTE module is not introduced to that pin. This way I guess GPIOTE assumes this pin is PIN_NOT_USED and the corresponding latch bit is not reset. I will investigate more about this. Hopfully I will have the time to setup an example project for the PCA10040. I think there might be trap for developers using the GPIOTE driver this way.

  • Sure, if you can setup an example project, I can try debugging it at my end as well. Good luck with your investigation.

  • Ok, I managed it to write a small example project for PCA10040 which (sometimes) reproduces the error: Press button 1 and the led toggles. If you press button 2 it often stucks in

    //nrfx_gpiote.c
        if (status & (uint32_t)NRF_GPIOTE_INT_PORT_MASK) {
            port_event_handle(input); //stucks in the underlying loop within port_event_handle
        }

    and the led won't toggle anymore.

    The link is: https://github.com/pioupus/nrfx_gpiote_irq_handler_stucks_when_using_TWIM.git

    It doesnt crash always. I think, if it is not possible to produce a crash, you have to restart the debugger and powercycle.

    regards

Reply Children
Related