<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>GPIOTE interrupts with around 30us latency?</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/118111/gpiote-interrupts-with-around-30us-latency</link><description>Hi guys, 
 I&amp;#39;ve been working with the NRF52832 in the past days and I&amp;#39;m having issues with the GPIOTE interrupts. 
 It seems that there a latency of around 30us until the interrupt handler is called? 
 To give a bit of context I&amp;#39;m working with the TDC1000</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Wed, 22 Jan 2025 13:10:46 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/118111/gpiote-interrupts-with-around-30us-latency" /><item><title>RE: GPIOTE interrupts with around 30us latency?</title><link>https://devzone.nordicsemi.com/thread/519561?ContentTypeID=1</link><pubDate>Wed, 22 Jan 2025 13:10:46 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:4afbfaa2-72f3-4741-9af9-964eba7e3c23</guid><dc:creator>Einar Thorsrud</dc:creator><description>&lt;p&gt;Hi&amp;nbsp;&lt;span&gt;Fernando,&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Yes, that is right. If you trigger&amp;nbsp;NRF_TIMER_TASK_CAPTURE0, the result will be in the CC register for channel 0, and the next time you capture on the same channel, it will be overwritten. There are several channels though, so you could map different events to different capture tasks via PPI (in this case you could map each of the three GPIOTE events to separate capture tasks).&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: GPIOTE interrupts with around 30us latency?</title><link>https://devzone.nordicsemi.com/thread/519394?ContentTypeID=1</link><pubDate>Tue, 21 Jan 2025 18:11:35 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:91a5129e-610a-4523-b43b-781991079959</guid><dc:creator>Fernando Fontes</dc:creator><description>&lt;p&gt;Hi Einar,&lt;/p&gt;
&lt;p&gt;Yes, I could do that, but I&amp;#39;m cleaning the timer before starting the reading and the time of flight should not exceed 1ms. So, there turn around is not an issue with the 32 bit counter.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I only have one question left. If I understood correctly ppi will capture the timer value and store it in the timer.p_reg register. Since I&amp;#39;m doing&amp;nbsp;NRF_TIMER_TASK_CAPTURE0, the result will be on CHANNEL0 right? Is it possible that&amp;nbsp;gpiote_event_handler is not fast enough and I could have the ppi capturing the value between two pulses and overwriting the register?&lt;/p&gt;
&lt;p&gt;Best regards,&lt;/p&gt;
&lt;p&gt;Fernando Fontes&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: GPIOTE interrupts with around 30us latency?</title><link>https://devzone.nordicsemi.com/thread/519349?ContentTypeID=1</link><pubDate>Tue, 21 Jan 2025 15:06:47 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:a9bd3a08-7bb0-47c1-a1a9-fbe0415caec8</guid><dc:creator>Einar Thorsrud</dc:creator><description>&lt;p&gt;Hi&amp;nbsp;Fernando,&lt;/p&gt;
&lt;p&gt;Yes, this is what I had in mind, and it looks good. With this, the interrupt latency does not affect the measurements. Note that depending on what fits best, you can also clear the timer like this so you will get an absolute cycle count between each event and not have to handle the timer wraping around.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: GPIOTE interrupts with around 30us latency?</title><link>https://devzone.nordicsemi.com/thread/518908?ContentTypeID=1</link><pubDate>Fri, 17 Jan 2025 18:32:28 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:3d9d11ce-f170-480a-8c6f-0fd1a928d171</guid><dc:creator>Fernando Fontes</dc:creator><description>&lt;p&gt;Ok, I&amp;#39;ve done the following:&lt;br /&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;#if defined(__ZEPHYR__)
    IRQ_DIRECT_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TIMER_INST_GET(TIMER_INST_IDX)), IRQ_PRIO_LOWEST,
                       NRFX_TIMER_INST_HANDLER_GET(TIMER_INST_IDX), 0);
    IRQ_DIRECT_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_GPIOTE), IRQ_PRIO_LOWEST, NRFX_GPIOTE_INST_HANDLER_GET(GPIOTE_INST_IDX),
                       0);
#endif

    nrfx_gpiote_t const gpiote_inst = NRFX_GPIOTE_INSTANCE(GPIOTE_INST_IDX);
    status = nrfx_gpiote_init(&amp;amp;gpiote_inst, IRQ_PRIO_LOWEST);
    if (status != NRFX_SUCCESS &amp;amp;&amp;amp; status != NRFX_ERROR_ALREADY_INITIALIZED)
    {
        LOG_ERR(&amp;quot;Error while configuring gpiote for ToF reading: %d&amp;quot;, status);
        return EXIT_FAILURE;
    }

    uint8_t start_pin_ch, stop_pin_ch, errb_pin_ch;
    status = nrfx_gpiote_channel_alloc(&amp;amp;gpiote_inst, &amp;amp;start_pin_ch);
    if (status != NRFX_SUCCESS)
    {
        LOG_ERR(&amp;quot;Error while alloc channel for ToF reading!&amp;quot;);
        return EXIT_FAILURE;
    }

    status = nrfx_gpiote_channel_alloc(&amp;amp;gpiote_inst, &amp;amp;stop_pin_ch);
    if (status != NRFX_SUCCESS)
    {
        LOG_ERR(&amp;quot;Error while alloc channel for ToF reading!&amp;quot;);
        return EXIT_FAILURE;
    }

    status = nrfx_gpiote_channel_alloc(&amp;amp;gpiote_inst, &amp;amp;errb_pin_ch);
    if (status != NRFX_SUCCESS)
    {
        LOG_ERR(&amp;quot;Error while alloc channel for ToF reading!&amp;quot;);
        return EXIT_FAILURE;
    }

    static const nrf_gpio_pin_pull_t rising_input_config = NRF_GPIO_PIN_PULLDOWN;
    static const nrf_gpio_pin_pull_t falling_input_config = NRF_GPIO_PIN_PULLUP;

    const nrfx_gpiote_trigger_config_t start_rising_trigger_config = {
        .trigger = NRFX_GPIOTE_TRIGGER_LOTOHI,
        .p_in_channel = &amp;amp;start_pin_ch,
    };
    const nrfx_gpiote_trigger_config_t stop_rising_trigger_config = {
        .trigger = NRFX_GPIOTE_TRIGGER_LOTOHI,
        .p_in_channel = &amp;amp;stop_pin_ch,
    };
    const nrfx_gpiote_trigger_config_t errb_falling_trigger_config = {
        .trigger = NRFX_GPIOTE_TRIGGER_HITOLO,
        .p_in_channel = &amp;amp;errb_pin_ch,
    };
    static const nrfx_gpiote_handler_config_t handler_config = {
        .handler = gpiote_event_handler,
    };

    static nrfx_gpiote_input_pin_config_t start_cfg;
    start_cfg.p_handler_config = &amp;amp;handler_config;
    start_cfg.p_pull_config = &amp;amp;rising_input_config;
    start_cfg.p_trigger_config = &amp;amp;start_rising_trigger_config;

    static nrfx_gpiote_input_pin_config_t stop_cfg;
    stop_cfg.p_handler_config = &amp;amp;handler_config;
    stop_cfg.p_pull_config = &amp;amp;rising_input_config;
    stop_cfg.p_trigger_config = &amp;amp;stop_rising_trigger_config;

    static nrfx_gpiote_input_pin_config_t errb_cfg;
    errb_cfg.p_handler_config = &amp;amp;handler_config;
    errb_cfg.p_pull_config = &amp;amp;falling_input_config;
    errb_cfg.p_trigger_config = &amp;amp;errb_falling_trigger_config;

    status = nrfx_gpiote_input_configure(&amp;amp;gpiote_inst,
                                         tdc1000_start.pin,
                                         &amp;amp;start_cfg);

    status = nrfx_gpiote_input_configure(&amp;amp;gpiote_inst,
                                         tdc1000_stop.pin,
                                         &amp;amp;stop_cfg);

    status = nrfx_gpiote_input_configure(&amp;amp;gpiote_inst,
                                         tdc1000_errb.pin,
                                         &amp;amp;errb_cfg);

    nrfx_gpiote_trigger_enable(&amp;amp;gpiote_inst, tdc1000_start.pin, 1);
    nrfx_gpiote_trigger_enable(&amp;amp;gpiote_inst, tdc1000_stop.pin, 1);
    nrfx_gpiote_trigger_enable(&amp;amp;gpiote_inst, tdc1000_errb.pin, 1);

    uint8_t gppi_channel1, gppi_channel2, gppi_channel3;
    status = nrfx_gppi_channel_alloc(&amp;amp;gppi_channel1);

    status = nrfx_gppi_channel_alloc(&amp;amp;gppi_channel2);

    status = nrfx_gppi_channel_alloc(&amp;amp;gppi_channel3);

    nrfx_gppi_channel_endpoints_setup(gppi_channel1,
        nrfx_gpiote_in_event_address_get(&amp;amp;gpiote_inst, tdc1000_start.pin),
        nrfx_timer_task_address_get(&amp;amp;tof_timer_inst, NRF_TIMER_TASK_CAPTURE0));

    nrfx_gppi_channel_endpoints_setup(gppi_channel2,
        nrfx_gpiote_in_event_address_get(&amp;amp;gpiote_inst, tdc1000_stop.pin),
        nrfx_timer_task_address_get(&amp;amp;tof_timer_inst, NRF_TIMER_TASK_CAPTURE0));

    nrfx_gppi_channel_endpoints_setup(gppi_channel3,
        nrfx_gpiote_in_event_address_get(&amp;amp;gpiote_inst, tdc1000_errb.pin),
        nrfx_timer_task_address_get(&amp;amp;tof_timer_inst, NRF_TIMER_TASK_CAPTURE0));

    nrfx_gppi_channels_enable(BIT(gppi_channel1));
    nrfx_gppi_channels_enable(BIT(gppi_channel2));
    nrfx_gppi_channels_enable(BIT(gppi_channel3));
    

static void gpiote_event_handler(nrfx_gpiote_pin_t pin, nrfx_gpiote_trigger_t action, void *unused)
{
    // LOG_INF(&amp;quot;INT on pin: %u&amp;quot;, pin);

    static gpio_int_context_t int_context = {0};

    int_context.cycle_count = nrf_timer_cc_get(tof_timer_inst.p_reg, NRF_TIMER_CC_CHANNEL0);
    
    if (pin == tdc1000_start.pin) {
        int_context.pin = TDC1000_START_PIN;
    }
    else if (pin == tdc1000_stop.pin) {
        int_context.pin = TDC1000_STOP_PIN;
    }
    else if (pin == tdc1000_errb.pin) {
        int_context.pin = TDC1000_ERRB_PIN;
    }
    else {
        return;
    }

    // add to the queue
    k_msgq_put(&amp;amp;gpio_interrupt_q, &amp;amp;int_context, K_NO_WAIT);
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;This seems indeed to improve a lot the timing.&amp;nbsp;Can you just take a look to make sure that I&amp;#39;m doing everything ok?&amp;nbsp;&lt;/p&gt;
&lt;p&gt;My take was, since I want to read the time that it&amp;nbsp;takes between the trigger command (writing&amp;nbsp;to gpio) and the start interrupt followed by the echos (stop pin interrupt) i&amp;#39;ve configured ppi to&amp;nbsp;NRF_TIMER_TASK_CAPTURE0. Then on the interrupt handler I&amp;#39;m&amp;nbsp;retrieving the captured value.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Best regards,&lt;/p&gt;
&lt;p&gt;Fernando Fontes&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: GPIOTE interrupts with around 30us latency?</title><link>https://devzone.nordicsemi.com/thread/518891?ContentTypeID=1</link><pubDate>Fri, 17 Jan 2025 16:11:58 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:77f07a01-901a-4309-9ee9-826b1b82cb61</guid><dc:creator>Fernando Fontes</dc:creator><description>&lt;p&gt;But I think I will have issues when trying to attach an interrupt to GPIOTE since when GPIO is enabled on zephyr it already does that.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Is it possible to count the time between two pulses on different pins without having to enable interrupts to start/stop the timers from counting?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: GPIOTE interrupts with around 30us latency?</title><link>https://devzone.nordicsemi.com/thread/518872?ContentTypeID=1</link><pubDate>Fri, 17 Jan 2025 14:07:17 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:ae4ed04e-c6fe-450e-8b57-ffee2627ecc0</guid><dc:creator>Einar Thorsrud</dc:creator><description>&lt;p&gt;Hi Fernando,&lt;/p&gt;
&lt;p&gt;It is possible to use PPI without disabling the GPIO lib. It is a common thing to do, and this is a situation where PPI is a very good match. You can see another unofficial PPI example here (where GPIO is not disabled).&amp;nbsp;&lt;a href="https://github.com/too1/ncs-nrfx-pulse-count-example/blob/master/src/main.c"&gt;https://github.com/too1/ncs-nrfx-pulse-count-example/blob/master/src/main.c&lt;/a&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: GPIOTE interrupts with around 30us latency?</title><link>https://devzone.nordicsemi.com/thread/518857?ContentTypeID=1</link><pubDate>Fri, 17 Jan 2025 13:33:15 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:35e9c0c8-2148-413f-b303-c1a351f7b8ea</guid><dc:creator>Fernando Fontes</dc:creator><description>&lt;p&gt;Hi Thorsrud,&lt;/p&gt;
&lt;p&gt;Thank you for the response. Using PPI would require to set CONFIG_GPIO to &amp;#39;n&amp;#39; which would then make everything else to stop working.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I have other sensors on the board, a modem and they also require the GPIO lib to work.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Is there any other way?&lt;/p&gt;
&lt;p&gt;Best regards,&lt;/p&gt;
&lt;p&gt;Fernando&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: GPIOTE interrupts with around 30us latency?</title><link>https://devzone.nordicsemi.com/thread/518847?ContentTypeID=1</link><pubDate>Fri, 17 Jan 2025 13:09:12 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:493c53d7-e9ae-4b22-9072-1e93d7325335</guid><dc:creator>Einar Thorsrud</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;I suggest you do this measurement with PPI instead of software, by hooking the TIMER to GPIOTE via PPI, similarily to whta is done &lt;a href="https://github.com/zephyrproject-rtos/hal_nordic/blob/13ac55b5b52c905642e9c54f069109d188aa5840/nrfx/samples/src/nrfx_gppi/one_to_one"&gt;here&lt;/a&gt;&amp;nbsp;(this use GPIO as output so some changes are needed, but it shows how you can hook things up). With this, you can do the measurements in hardware and interrupt latency will not affect th emeasurment results.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>