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

nrf_drv_gpiote_in_event_enable does not work as expected

Hello, we need to first enable GPIOTE+IRQ. Then after 1st IRQ we want to keep only GPIOTE and disable IRQ. We do not want to disable GPIOTE (because it works with PPI), but only to disable IRQ.

We tried to call first: nrf_drv_gpiote_in_event_enable(pin, true)

and then in ISR we tried to call nrf_drv_gpiote_in_event_enable(pin, false) in order to disable IRQ, but it would not work.

I propose to fix the SDK function and add:

else{ nrf_gpiote_int_disable(1 << channel);}

so it would look like:

void nrf_drv_gpiote_in_event_enable(nrf_drv_gpiote_pin_t pin, bool int_enable)
{
    ASSERT(pin < NUMBER_OF_PINS);
    ASSERT(pin_in_use_by_gpiote(pin));
    if (pin_in_use_by_port(pin))
    {
        uint8_t pin_and_sense = m_cb.port_handlers_pins[channel_port_get(pin) - GPIOTE_CH_NUM];
        nrf_gpiote_polarity_t polarity = (nrf_gpiote_polarity_t)(pin_and_sense >> SENSE_FIELD_POS);
        nrf_gpio_pin_sense_t sense;
        if (polarity == NRF_GPIOTE_POLARITY_TOGGLE)
        {
            /* read current pin state and set for next sense to oposit */
            sense = (nrf_gpio_pins_read() & (1 << pin)) ?
                    NRF_GPIO_PIN_SENSE_LOW : NRF_GPIO_PIN_SENSE_HIGH;
        }
        else
        {
            sense = (polarity == NRF_GPIOTE_POLARITY_LOTOHI) ?
                    NRF_GPIO_PIN_SENSE_HIGH : NRF_GPIO_PIN_SENSE_LOW;
        }
        nrf_gpio_cfg_sense_set(pin,sense);
    }
    else if (pin_in_use_by_te(pin))
    {
        int32_t channel = (int32_t)channel_port_get(pin);
        nrf_gpiote_events_t event = TE_IDX_TO_EVENT_ADDR(channel);

        nrf_gpiote_event_enable(channel);

        nrf_gpiote_event_clear(event);
        if (int_enable)
        {
            nrf_drv_gpiote_evt_handler_t handler = channel_handler_get(channel_port_get(pin));
            // Enable the interrupt only if event handler was provided.
            if (handler)
            {
                nrf_gpiote_int_enable(1 << channel);
            }
        }else{
               nrf_gpiote_int_disable(1 << channel);
        }
    }
}

Also I believe that current description of function is not correct. In documentation is written:

int_enable: True to enable the interrupt. Always valid for a high-accuracy pin.

But in fact interrupt is always enabled for PORT event. Thus when high-accuracy = False

  • Have you tried calling
    nrf_drv_gpiote_in_event_disable(PIN)
    nrf_drv_gpiote_in_event_enable(PIN, false) ?

    If you need the IN_EVENT to be operational while you are turning off the interrupt, you can write directly to the clear interrupt register instead:

    NRF_GPIOTE->INTENCLR = mask;

    Where each bit of the mask corresponds to the GPIOTE channel you wish to disable the IRQ for(0x3 disables the IRQs for channel 1 and 2). The trick here is to know which channel the gpio pin is mapped to. Whenever you initialize an IN_EVENT on a pin, you allocate the first available channel, starting at 0 and ending at 7. If you have initialized 3 IN_EVENTS (with interrupts), and you want to disable the second, call
    NRF_GPIOTE->INTENCLR = 0x2;

    Now a problem arises, because the next time you initialize an IN_EVENT the first available channel is channel 2. You will have to keep track of the GPIOTE channels you use.

  • I want functionality when IN_EVENT is functional without pauses and only interrupt is turned off.

    Counting nrf_drv_gpiote_in_init is inconvenient because we are more ppl using FreeRTOS multiple threads.

    Would it be difficult to add one else branch into SDK? So nrf_drv_gpiote_in_event_enable is capable of reconfigure interrupt settings? It seems like small change of SDK. For me counting calls is extra effort in multiple places of code. Also there is no guarantee that your algo of assigning resources would keep same in future SDK versions...

Related