ISR handler task starving other lower priority task

seanbzd wrote on Wednesday, April 01, 2015:

Hi,
I’m using FreeRTOS on Xilinx Zynq Soc, c++ compiler. I have 2 tasks.
Task 1 is the handler task to service ISRs. It is created with a priority of say, 4.
Task 2 is another task doing other work totally unrelated to ISRs/Task1 and created with priority 3.

Task1 // priority 4
{
while (1)
{
SemaphoreTake(xbinary);
do something();
}
}

ISR()
{
SemaphoreGive(xbinary);
Context Switch(); //to make Task1() run
}

Task2() // priority 3
{
while(1)
{
do something else()
}
}

In the above scheme, Task2() is not running even though the higher priority Task1() is blocked on a semaphore. Any ideas??
If I create Task2() with the same priority as the handler Task1(), then both of them run; but I would like to keep Task2() at lower priority than the handler Task.

heinbali01 wrote on Wednesday, April 01, 2015:

Hi Sean,


static xSemaphoreHandle xISREventSemaphore;

void ISR_handler( void )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    /* Beside setting the semaphore, also make sure that the
    same ISR won't re-occur immediately after returning (IRET).
    In some cases this is automatic: the CPU or peripheral
    denotes the interrupt as "handled" just before calling the
    ISR.
    In other cases, you must write a '1' to some flag which
    triggered this interrupt (timer-interrupt), or read a byte
    (UART RX interrupt), see the manual. */
    if( xISREventSemaphore != NULL )
    {
        //to make Task1() run
        xSemaphoreGiveFromISR( xISREventSemaphore,
            &xHigherPriorityTaskWoken );
        portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
    }
}

void Task1( void *pvParameters ) // priority 4
{
BaseType_t xTicksSecond = 1000 / portTICK_PERIOD_MS;

    vSemaphoreCreateBinary( xISREventSemaphore );
    install_ISR();

    while (1)
    {
        if( SemaphoreTake( xISREventSemaphore, xTicksSecond ) != pdFALSE )
        {
            /* An ISR has occurred. */
            do_something();
        }
        else
        {
            /* A time-out occurred while waiting for an ISR event. */
        }
    }
}

void Task2( void *pvParameters ) // priority 3
{
BaseType_t xSleepTicks = 10 / portTICK_PERIOD_MS;
xSemaphoreHandle xTask2Semaphore;

    vSemaphoreCreateBinary( xTask2Semaphore );
    while(1)
    {
        /* Let it sleep for 10 ms. */
        SemaphoreTake( xTask2Semaphore, xSleepTicks );
        /* and do something else. */
        do_something_else();
    }
}

If you look carefully at the above example, you might find the answer to your question.

Regards.

seanbzd wrote on Wednesday, April 01, 2015:

Hein,
Thanks for responding and the nicely formatted code example. I don’t think I understand what you are trying to tell me. Please note that even though Task2() is of lower priority, the other higher priority Task1() is blocked on a Semaphore, so, shouldn’t that relinquish some CPU to the lower priority Task2()? Thanks in advance.

heinbali01 wrote on Wednesday, April 01, 2015:

Sean,

I don’t think I understand what you are trying to tell me

The fact that your lower-priority task-2 doesn’t get attention, probably means that either the ISR or task-1 is consuming all CPU time.
Maybe task-1 takes all CPU time because it does not sleep (when xBlockTime == 0)
Maybe your ISR takes all CPU time because the cause of the interrupt is not properly reset / cleared.

Could you compare the code that I provided with your own implementation, line-by-line?

And if you can NOT find the cause, you might want to submit some real C-code that you are using.

Regards, Hein

seanbzd wrote on Sunday, April 05, 2015:

Thanks.
The tick interrupt is 1000Hz, the external interrupt is fired every 1ms. Since the scheduler can only run at 1 ms, I suppose the context switch from Task1 to Task2 cannot happen sooner than that. So, I increased the tick interrupt to 2000 Hz, but it still did not help. I’m looking into this statement “Maybe your ISR takes all CPU time because the cause of the interrupt is not properly reset / cleared.” I’ll report back.

richard_damon wrote on Sunday, April 05, 2015:

Who says the scheduler can only run at 1 ms? The scheduler will be run whenever it is called! The timer tick will force a scheduler run (if premeption is allowed) to let multiple tasks at the same priority automatically share time.

The scheduler will also run whenever a task blocks.

An ISR can also request the scheduler to run (details on how are port specific) when it has unblocked a higher priority task, thus switching to it immediately.

seanbzd wrote on Sunday, April 12, 2015:

Thanks Hein and Richard. This problem is now resolved. The issue was same what Hein suspected. The Interrupt was not getting cleared properly. We were configuring the interrupt for ACTIVE LOW where as it was required to be configured ACTIVE HIGH or rising edge. Once we resolved this, we are able to get multiple tasks with different priorities working without problems.

Thanks for your support.