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

Two GPIOTE PORT Events issue

My device (nrf52832) has two signals triggering GPIOTE interrupts.  I need to be as low power as possible, so both are setup to not use hi accuracy, making them share the PORT event.  One signal is a button, and one is an accelerometer.  After a few button presses, but not a fixed number of presses, the gpiote interrupt stops firing.  I put a breakpoint at the top of nrfx_gpiote_irq_handler, and it never hits after the problem starts.  I'm guessing that both signals are changing at the same time, since the button has tactile feedback when pressed, and the accelerometer is fairly sensitive.  I've checked the NVIC, GPIOTE, and GPIO registers for any changes, and nothing is different after the interrupt stops working.  The RTC interrupt continues to fire, however.

If I set the accelerometer's motion threshold high enough, the issue goes away, telling me that its likely a problem with both signals changing together.  If I change the button's interrupt to be hi accuracy, and the problem also goes away.  Neither of these are acceptable long term fixes though.  The button is set to fire the interrupt on either edge (toggle), and the accelerometer is set to fire on a falling edge.  When I changed the accelerometer's interrupt configuration to also toggle, and then poll the level in my handler, the issue seems to have gone away.  This is acceptable, but it doesn't make sense.  

Why does the interrupt stop firing, and why did this change fix the problem?

  • Hello,

    Sorry for the late reply.

    I have been struggling with pointing out exactly why it is the way it is, but I see that using .hi_accuracy = false and .sense = NRF_GPIOTE_POLARITY_HITOLO, while one of the pins are held low, the other pin doesn't respond.

    The workaround that I have found is to use TOGGLE instead of HITOLO, and check in the interrupt event whether the pin is high or low. This way, you will get all events, but you can filter out those that you do not want to use. 

    Something like this (a modified pin_int_change example):

    void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        bool pressed = !nrfx_gpiote_in_is_set(pin); //nrfx_gpiote_in_is_set() returns false if button is pressed
        
        if(!pressed)
        {
            return;
        }
        if(pin == PIN_IN1)
        {
            nrf_drv_gpiote_out_toggle(PIN_OUT1);
        }
        else
        {
            nrf_drv_gpiote_out_toggle(PIN_OUT2);
        }
    }
    /**
     * @brief Function for configuring: PIN_IN pin for input, PIN_OUT pin for output,
     * and configures GPIOTE to give an interrupt on pin change.
     */
    static void gpio_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_SIMPLE(false);
    
        err_code = nrf_drv_gpiote_out_init(PIN_OUT1, &out_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_out_init(PIN_OUT2, &out_config);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
        in_config.pull = NRF_GPIO_PIN_PULLUP;
    
        err_code = nrf_drv_gpiote_in_init(PIN_IN1, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_in_init(PIN_IN2, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_event_enable(PIN_IN1, true);
        nrf_drv_gpiote_in_event_enable(PIN_IN2, true);
    }

    Best regards,

    Edvin

Related