Long Delay Between ISR and Task Handler

mrobert wrote on Monday, May 07, 2018:

I am trying to handle an ISR in a task. To do so, I call vTaskNotifyGiveFromISR() to a task that is wait on ulTaskNotifyTake(). E.g. In the ISR,

            /* Notification variable for Task */
            BaseType_t xHigherPriorityTaskWoken = pdFALSE;
            
            /* Set the Task to Highest Priority */
            vTaskNotifyGiveFromISR( sLINTaskUART, &xHigherPriorityTaskWoken);

            /* Force a scheduler call on exit */
            if( xHigherPriorityTaskWoken == pdTRUE )
            {
                portYIELD_FROM_ISR();
            }

in the Task

    while(1)
    {
        /* Wait forever for Notification */
        notified = ulTaskNotifyTake( pdTRUE,0xFFFFFFFF );

        if( notified == 0 )
        {
            // We've been idle for a loooong time. Go back to waiting I guess...
            continue;
        }
        
        /* Task do stuff */
     }

I did some timing measurements and I found that there is about a 6 millisecond delay from the ISR to the task executing. I thought this could either be

  1. Context switching just takes that long ( I don’t believe it does )
  2. I wasn’t switching into the task right away (The handler task is the highest priority).

However, when I increased my configTICK_RATE_HZ from 100Hz to 1kHz, the delay between the ISR went down dramatically…

I don’t understand. I have preemption enabled. Shouldn’t that mean that the task is entered immediately from the ISR in either case? If that’s true, then the Tick Rate shouldn’t impact the delay between the ISR and the task.

Can someone clarify for me? I’ve read “Mastering the FreeRTOS Real Time Kernel” but this behavior doesn’t seem to match the behavior there.

I am on an ESP32 and using the ESP-IDF’s version of FreeRTOS, but that shouldn’t change this behavior.

rtel wrote on Tuesday, May 08, 2018:

It doesn’t look like you are doing anything from just from the code you
posted. However I’m not familiar with the port in use as it was not
created by us. Can you check how portYIELD_FROM_ISR() is implemented,
and perhaps post its implementation here.

heinbali01 wrote on Tuesday, May 08, 2018:

However, when I increased my configTICK_RATE_HZ from 100Hz to 1kHz,
the delay between the ISR went down dramatically…

It looks like portYIELD_FROM_ISR() isn’t doing what it should do. I guess that you see the same timings with or without this yield, don’t you?

I think that in your case, the task is only activated after the kernel has seen (from the clock-tick) that your task is runnable. That is not the usual path.

If your task has become the highest-priority-runnable-task, the task should become active without the intervention of the kernel or clock-tick.

portYIELD_FROM_ISR() will have vTaskSwitchContext() called in _frxt_dispatch, and it should cause an immediate task switch. May you can debug that function?

But as Richard said, the ESP port was not created by FreeRTOS. Neither I have much experience with the port or with the part.

mrobert wrote on Tuesday, May 08, 2018:

Richard and Hein,

Thank you for your replies. After reading your replies, I checked the port, and it looked correct; portYIELD_FROM_ISR looked like it was doing what it was suppsed to. I eventually decided that my code was correct as well.

As with many problems, the solution was simple, and makes me look dumb. I checked our config settings and found that a flag was set that changed the behavior of portYIELD_FROM_ISR; It didn’t occur to me that my config was bad before. Once I corrected the flag, the transition from ISR to the task fell to 11 microseconds. Much Better!

You guys did help, and I appreciate your quick replies. Sorry for wasting your time!

heinbali01 wrote on Tuesday, May 08, 2018:

Sorry for wasting your time!

As long as other users can learn from it, you’re not wasting anyone’s time :slight_smile:

So what flag did you have to change to get it correctly?