nrf_drv_gpiote_in_event_enable causes event

Hey,

When I call fn nrf_drv_gpiote_in_event_enable, the event handler is immediately called.  Note that at the beginning of the fn I even read the pin to verify it's high.  I also know it's high because I'm scoping it.   Also, this code does work properly when the line transitions to low.

Is there a way to stop this erroneous event from happening when enabled???

    ret_code_t err_code;

    nrf_gpio_cfg_input(gp_board_config->irq, NRF_GPIO_PIN_PULLUP);

    {
        volatile uint32_t read = nrf_gpio_pin_read(gp_board_config->irq);

        // Setting break point here verifies this line is high.
        read++;
    }

    err_code = nrf_drv_gpiote_init();
    APP_ERROR_CHECK(err_code);

    /**
     * Sam will set the interrupt aka wakeup line low until nrf responds with Ack.
     */

    nrf_drv_gpiote_in_config_t irq_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(false);
    err_code = nrf_drv_gpiote_in_init(gp_board_config->irq, &irq_config, m_gpiote_evt_handler);
    APP_ERROR_CHECK(err_code);

    CRITICAL_REGION_ENTER();
    nrf_drv_gpiote_in_event_enable(gp_board_config->irq, true);

    {

        nrf_gpiote_events_t event   = nrfx_gpiote_in_event_addr_get(gp_board_config->irq);

        nrf_gpiote_event_clear(event);

        NVIC_ClearPendingIRQ(GPIOTE_IRQn);
    }

    CRITICAL_REGION_EXIT();

Note I even tried disabling ints, and then clearing the event and the interrupt - no success.

  • Hi,

    Which GPIO pin are you using? Have you tried other pins?

    Since you have passed "false" to the hi_accu argument of NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(), the pin will use the GPIOTE PORT event and not a dedicated IN event. Have you tried setting this to "true"?

    When you say that the event handler is called immediately, is this your application defined event handler? (m_gpiote_evt_handler) What are the pin and action variables set to?

    The code you have included in your post is not correct to clear events:

    nrf_gpiote_events_t event   = nrfx_gpiote_in_event_addr_get(gp_board_config->irq);
    nrf_gpiote_event_clear(event);

    nrfx_gpiote_in_event_addr_get() will return the address of the event register, while nrf_gpiote_event_clear() expects a nrf_gpiote_events_t enum value.

    Since you have set the hi_accu parameter to false, you can try passing the NRF_GPIOTE_EVENTS_PORT option to nrf_gpiote_event_clear().

    Best regards,
    Jørgen

  • Jorgen,

    Thanks for your reply.

    Thanks for the tip on the param for nrf_gpiote_event_clear, I struggled with that.  Using NRF_GPIOTE_EVENTS_PORT did not fix the problem.

    Setting hi_accu to true does fix this problem.  But this product is powered from coin cells and I believe that causes higher current draw due to use of HFCLK (this solution has a crystal on HFCLK, as the radio is used occasionally)  - so I think setting hi_accu to true is NOT a permanent solution.

    The goal is the get an interrupt when the GPIO line transitions from high to low - should I be using another technique other than nrf_drv_gpiote_in_init?

    
    
  • Hi,

    I tested a simple version of your code in the pin_change_interrupt example in nRF5 SDK v17.1.0. I'm not able to reproduce the issue with interrupt triggering at start of application, or see any problems with the interrupt not triggering.

    Can you try this simple code on your board?

    #include <stdbool.h>
    #include "nrf.h"
    #include "nrf_drv_gpiote.h"
    #include "app_error.h"
    #include "boards.h"
    
    #define GPIO_BUTTON 25
    #define GPIO_LED    16
    
    
    void m_gpiote_evt_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        nrf_gpio_pin_toggle(GPIO_LED);
    }
    
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        ret_code_t err_code;
    
        nrf_gpio_cfg_input(GPIO_BUTTON, NRF_GPIO_PIN_PULLUP);
        nrf_gpio_cfg_output(GPIO_LED);
        nrf_gpio_pin_set(GPIO_LED);
    
        {
            volatile uint32_t read = nrf_gpio_pin_read(GPIO_BUTTON);
    
            // Setting break point here verifies this line is high.
            read++;
        }
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
        /**
         * Sam will set the interrupt aka wakeup line low until nrf responds with Ack.
         */
    
        nrf_drv_gpiote_in_config_t irq_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(false);
        err_code = nrf_drv_gpiote_in_init(GPIO_BUTTON, &irq_config, m_gpiote_evt_handler);
        APP_ERROR_CHECK(err_code);
    
        //CRITICAL_REGION_ENTER();
        nrf_drv_gpiote_in_event_enable(GPIO_BUTTON, true);
    
        //{
        //    nrf_gpiote_event_clear(NRF_GPIOTE_EVENTS_PORT);
        //    NVIC_ClearPendingIRQ(GPIOTE_IRQn);
        //}
    
        //CRITICAL_REGION_EXIT();
    
        while (true)
        {
            __WFE();
            // Do nothing.
        }
    }

    On the nRF52840 DK, this will toggle LED4 in the interrrupt handler when BUTTON4 is pressed. Before the button is pressed, the LED will not light up.

    Namklak said:
    The goal is the get an interrupt when the GPIO line transitions from high to low - should I be using another technique other than nrf_drv_gpiote_in_init?

    The approach you have used is the best method to configure the interrupt using the PORT event. 

    Best regards,
    Jørgen

  • I tried your example of reading the pin after setting pin to an input - if I put a breakpoint on my code's equivalent of your line 32, I do NOT get the false event.  If I run the code without the breakpoint, I do get the false event after nrf_drv_gpiote_in_event_enable.

    Also, before this code runs, the dfu bootloader is running - I wonder if that is causing some uh initial conflict.

Related