Pre-emptive mode starves task of exec time

tomwbarclay wrote on Friday, May 24, 2013:

I am using FreeRTOS 7.3.0 on an Atmel SAM4 chip using the ASF library.  I have a task that executes 4 calls in sequence then blocks. Each one is an interrupt driven state machine that issues an event from the ISR at the end. Each call waits for such an event before exiting. Each call invokes some SPI traffic which I can monitor on an external logic analyzer. What I observe is

Set the tick rate to 1ms and I see approx 1ms gaps between the calls.
Set the tick rate to 5ms and I see approx 5ms gaps between the calls.

Set the config_USEPREEMPTIVE to 0

And I see very small gaps between the calls.

Clearly when ‘preemtive’, the RTOS is going off to do something else during these gaps.

In my code all tasks block, either on input Qs or output Q’s or wait for events. The entire design is asynchronous
and event driven.
In my test setup I have no regular activity other than an LED flasher running at 100ms period.
I start the test activity by a keypress.

I had presumed that at the RTOS tick the kernel would go around the other tasks, find they were all blocked
and come back pretty sharpish to continue executing the test task … but it appears not.

Anyone have any ideas ??? …before I get down and dirty and start putting debug code into FreeRTOS itself.

Any help appreciated.

rtel wrote on Friday, May 24, 2013:

Sorry, but I’m struggling to understand either the scenario or the problem you are describing.  I think you have several event driven tasks that run through a state machine in response to events originating from interrupts, but I’m not sure what “that issues an event from the ISR at the end” as tasks can issue events *from* interrupts.  Equally I don’t understand “Each call waits for such an event before exiting”.

Please post a little outline of the tasks, with a description of the behaviour you are seeing, and I may be able to explain why you are seeing that behaviour.


tomwbarclay wrote on Saturday, May 25, 2013:

OK…hope it all makes more sense after reading this….

I have 14 tasks. Each task has the pattern

task start
forever loop
            wait on event or message
            do something
loop end
task end

One of the tasks waits on a 200ms timer expiring (using vTaskDelay) which flashes an LED. All the other tasks block indefinitely.

In my test task, the do something part,  there are 4 methods executing sequentially, call them A,B,C,D

Each method starts a sequence of SPI transactions that happens purely in the interrupt domain and then  waits for the final interrupt to issue a xSemaphoreGiveFromISR. The sequence of actions in the interrupt domain is a state machine,
each interrupt setting up the next SPI transfer and next state. The interrupts occur when an SPI transfer completes. The
important point (I think) as its at the end of the interrupt sequence when an RTOS call is made.

So basically once the test task runs it executes as
  methodA entry
       start SPI transactions  ----> SPI transfers in sequence of  interrupts --> send event from ISR
       wait for event from ISR
methodA end

methodB entry
etc etc etc

On the logic analyzer I observe the bursts of  SPI data transfer (shown below)

….!!!..……………………!!! ………………….!!!..………………………!!!..….

as each method executes.

The odd thing is that the gap between the bursts correlates (roughly)  to the tick period. There is virtually no gap when I switch of the pre-emptive mode of RTOS operation.

Hope this helps … Tom

davedoors wrote on Saturday, May 25, 2013:

Seems clear. Are you context switching in the interrupt using portEND_SWITCHING_ISR or portYILD_FROM_ISR (depending on the port) when the event is sent to the task? If not then the switch will only happen on the next tick and the next task wont initiate its SPI transfer until that time.

tomwbarclay wrote on Saturday, May 25, 2013:


In the interrupt routine there is

1) … higher_prio_task_woken = event_ISR_signal(* txfr_complete); // signal data ready

then on exit

2) …portEND_SWITCHING_ISR(higher_prio_task_woken);

Just out of interest, in FreeRTOS 7.3.0 the ‘higher_prio_task_woken’ can be set to NULL.

What would be the impact ?

… Tom

tomwbarclay wrote on Saturday, May 25, 2013:

Thinking about the scheduling points… given that the only task available to run (ie not blocked) is the one task that was running, then would the call portEND_SWITCHING_ISR(pdTRUE) at the end of the interrupt force the same task to be re-scheduled ?  Its not after all a higher priority !!!

or is the label of the variable “higher_prio_task_woken”  misleading ? and a task of the same priority would also be
scheduled ?

I’ll try forcing the re-schedule and let you know what happens.

tomwbarclay wrote on Saturday, May 25, 2013:

OK … looks like its a issue with value of  “higher_prio_task_woken”.  I’ll have to walk through and check all the code to make sure I haven’t missed any execution steps or that the value of  “higher_prio_task_woken” is not being overwritten somewhere  but forcing the issue by using


at the end of the interrupt fixes the problem.

Thanks for all your help,

rtel wrote on Saturday, May 25, 2013:

Also ensure configIDLE_SHOULD_YIELD is set to one in FreeRTOSConfig.h, otherwise if the idle task is running it will continue to run until the next tick interrupt occurs.


rtel wrote on Saturday, May 25, 2013:

Forgot to say if you leave the xHigherPriorityTaskWoken parameter NULL then you have no way of knowing if calling the function caused a higher priority task to unblock or not.  It is only meant as an optimisation that can be used when you know that a context switch is never needed.