GPIO Interrupt Latency

Hello DevZone,

My team is developing a wearable that has time constraints which, we believe, are not being respected by Zephyr.

The setup is a nRF52840 based board which is connected to a chip (AS7058A by ams OSRAM) that communicates via I2C.

The chip has an interrupt line which triggers a callback that submits a worker to handle the I2C communiations.

The issue here is the high latency (can be above 2.5ms) between the interrupt rising edge on the chip and its respective detection on the nRF52840 Zephyr based application.

Here is a picture of an oscilloscope measuring the chip interrupt line (yellow) and a pin output (blue) set on interrupt handling (not on the worker).

As shown, interrupt detection has a variable latency and can go above 2.5ms, but sometimes it can be a few us.

The code for this is as follows:

Device tree configuration:

&gpio1 {
    status = "okay";

    as7058a {
        compatible = "gpio-keys";
        
        as7058a_int: as7058a_int {
            gpios = <&gpio1 03 (GPIO_ACTIVE_HIGH)>;
            label = "AS7058A interrupt";
        };
    };
};

Pin configuration and callback registration:

    /* Configure interrupt pin: Input */
    if ((ERR_SUCCESS == result) && (gpio_pin_configure_dt(&as7058a_int_speq, GPIO_INPUT) != 0))
    {
        result = ERR_SYSTEM_CONFIG;
    }
    /* Configure interrupt pin: Triggering on rising edge */
    if ((ERR_SUCCESS == result) && (gpio_pin_interrupt_configure_dt(&as7058a_int_speq, GPIO_INT_EDGE_RISING) != 0))
    {
        result = ERR_SYSTEM_CONFIG;
    }

    // Register AS7058A interrupt callback
    gpio_init_callback(&as7058a_int_cb_data, as7058a_int_callback, BIT(as7058a_int_speq.pin));
    result = gpio_add_callback(as7058a_int_speq.port, &as7058a_int_cb_data);

Interrupt callback:

/*! Interrupt service routine of the interrupt pin */
static void as7058a_int_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
// static void interrupt_callback()
{
    if (pins & BIT(as7058a_int_speq.pin))
    {
        nrf_gpio_pin_set(27);
        if (NULL != g_device_config.callback)
        {
            k_work_submit_to_queue(&int_cb_work_q, &int_cb_work);
        }
    }
}

We have added CONFIG_ZERO_LATENCY_IRQS to prj.conf, but apparently this doesn't affect GPIOTE.

How can we reduce this latency to be constant and as low as a few microsseconds?

We are using SDK v2.6.0.

Thanks in advance.

  • Hello  ,

    Here is a print of the threads' states at the moment the worker is called to handle interrupt off-load communications.

    The only thread preemption is sysworkq.

    Best regards,

    Ricardo

  • Hi,

    Elfving said:

    Strange that this is happening even when the threads are non-preemptive, though I agree that the other threads are probably the culprit here. 

    I take this back; the threads running shouldn't make much of a difference. And 2.5ms is way too long.

    Ricardo Ferreira said:
    The sample at samples/boards/nrf/nrfx has zero latency, but as soon as I add a thread to manage communcations and a worker to handle interrupt, interrupt response goes almost to 3ms (although sometimes it instantaneous).

    Thanks for giving me a way to reproduce it. I'll try this myself later this week.

    Ricardo Ferreira said:
    The sample at samples/boards/nrf/nrfx has zero latency, but as soon as I add a thread to manage communcations and a worker to handle interrupt, interrupt response goes almost to 3ms (although sometimes it instantaneous).

    Regards,

    Elfving

  • Hi Ricardo, 
    I'm taking over the ticket from Håkon because he is on vacation. 

    Could you please send us the code where you modified the samples/boards/nrf/nrfx that reproduce the issue ? 


    I assume you toggle the GPIO when you are in the button_handler ?  2.5ms seems like a lot. Interrupt handler should be able to interrupt works and threads. 


  • Hello Hung Bui,

    I only got back from vacation myself today.

    I picked-up a new nrfx samples and started adding my custom code for my drivers.

    When I add code that used GPIO, the compilation starts failing with this:

    gen_isr_tables.py: error: multiple registrations at table_index 6 for irq 6 (0x6)
    Existing handler 0x9307, new handler 0x9307
    Has IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?

    How can I safely change to IRQ_CONNECT?

    Should my other drivers use another method other than GPIO based functions?

    Best regards,

    Ricardo Ferreira

  • Hi Ricardo, 
    Pleas provide your code. It seems that you have connected two irq handlers to the same IRQ. 

Related