Analysing tasks management and priorities on FreeRTOS

Thread Starter

Xavier Pacheco Paulino

Joined Oct 21, 2015
728
A task has been created that reads a value of the ADC of a temperature sensor of a battery every 100 ms, calculate the value of it from the reading and update the value of a variable with it. My first iteration of the routine is as follows:

C:
#define DELAY_TICKS 100 // tick period 1 ms => 100 ms delay
volatile float battery_temperature;

void temperature_task(void* parameters) {

TickType_t current_tick_count, expired_tick_count;

while (1) {
// Read ADC
unsigned short adc_value = read_temperature_adc();

// Compute temperature
float temperature = compute_temperature(adc_value);

// Update variable
battery_temperature = temperature;

// Get current system tick count and compute expired count
current_tick_count = xTaskGetTickCount();
expired_tick_count = current_tick_count + DELAY_TICKS;

// Wait until the number of ticks has happen (100 ms)
while (xTaskGetTickCount() < expired_tick_count) {} } }
Once incorporated into the system, other tasks have begun to have problems because they are receiving less processing time, and even one of them has stopped working completely.

The task has been created with "normal" priority and the tick of the system is 1 ms (time of change between concurrent tasks). And the function to read the ADC works waiting for the reading, but it only takes a few nanoseconds and is not considered to impact the system, like the routine that computes the temperature.

So these are my questions:

What happens with tasks that have been receiving less processing time, but still running? Specifically about their priority and the way they use their time.

What happened to the task that has stopped running completely?

What is the problem that I have caused with my routine and how can I solve it?

P.D.: I'm using FreeRTOS Cortex M3

Mod edit: code tags
 
Last edited by a moderator:

miniwinwm

Joined Feb 2, 2018
67
C:
while (xTaskGetTickCount() < expired_tick_count) {} } }
You give little information how you have set up your scheduling and priorities, but as @nsaspook has said, the while delay is what is causing problems. A busy-wait loop like that should never be implemented in a RTOS. This is what the docs say...

The FreeRTOS scheduler ensures that tasks in the Ready or Running state will always be given processor (CPU) time in preference to tasks of a lower priority that are also in the ready state.

FreeRTOS is a real-time OS (clue is in the name :) ) which means that if you have configured it to run as a RTOS then a high priority task will block a lower priority task as long as the higher priority one has something to do and is not blocked by a busy resource. A while loop waiting for a tick time means that the task is busy, not waiting on a resource, and therefore will block the lower ones.

There are various solutions. A quick one is as already suggested - use a FreeRTOS wait routine that gives other tasks a chance. An alternative is to wait on a semaphore or message which is signalled when the required time has passed or some other event notifies your thread that it needs to wake up.

Programming for RTOS's is not the same as programming for bare bones systems where a busy wait loop doesn't matter. Task priorities need careful planning and care must be taken not to block in your code (calling blocking RTOS calls such as waiting for an event is ok, because the OS will use the blocking time to schedule other tasks).
 
Last edited:

Thread Starter

Xavier Pacheco Paulino

Joined Oct 21, 2015
728
I just want to understand something in this example: I know that the while loop doesn't block, so it takes as much time as it is possible. But, how can other tasks get less processing time and still executing? I mean, in this example, a task with higher priority will pre-empts my ADC task without taking into account that ADC task doesn't block. But, if the other tasks have the same priorities, I think they might execute really fast and then get pre-empted by my ADC task again, right?

The problem is about guessing, because the approach doesn't give more information. That's all it says. That's a problem that I found in an article and I was interested in analysing it. So, we can guess what it sounds more reasonable. We can assume that other tasks have same priorities. But, as the problem says, there is a task that stopped executing, so it has to be the iddle task. So, as the ADC task doesn't block, the only way that other tasks are able to execute, is either if they have higher priorities and they block or if they have the same priorities and don't block, so there is time-slicing and that's why they receive less time than the ADC task.

Is it my approch good?
Now, the way to solve this is replacing the while loop with a TaskDelay or TaskDelayUntil function
What do you think?
 
Last edited:

miniwinwm

Joined Feb 2, 2018
67
I'm also not an RTOS programmer, but I believe busy loops always matter.

That's why I never use them.
Yes, I should have said 'are a bit less of a cardinal sin in a bare bones system', rather than don't matter. I agree that they are generally not good and are often inaccurate, but sometimes they are unavoidable, and occasionally they don't matter. An example of the former is during system and driver initialisation before tasking has started in a RTOS (part of my work is porting RTOS's to new processors, so I see this use sometimes). Examples of the latter is a system that's so simple and non-time critical that there's not really anything else going on.
 
Last edited:

nsaspook

Joined Aug 27, 2009
7,587
Yes, I should have said 'are a bit less of a cardinal sin in a bare bones system', rather than don't matter. I agree that they are generally not good and are often inaccurate, but sometimes they are unavoidable, and occasionally they don't matter. An example of the former is during system and driver initialisation before tasking has started in a RTOS (part of my work is porting RTOS's to new processors, so I see this use sometimes). Examples of the latter is a system that's so simple and non-time critical that there's not really anything else going on.
I completely agree. I've used udelay for a simple delay for a Linux kernel driver of a simple device.
https://github.com/torvalds/linux/blob/master/drivers/staging/comedi/drivers/ni_daq_700.c
https://www.kernel.org/doc/Documentation/timers/timers-howto.txt

but for a more complex routine with actual timing and task concerns the Linux hrtimers are much better.
 

Thread Starter

Xavier Pacheco Paulino

Joined Oct 21, 2015
728
You give little information how you have set up your scheduling and priorities, but as @nsaspook has said, the while delay is what is causing problems. A busy-wait loop like that should never be implemented in a RTOS. This is what the docs say....
I know. But I'm just looking into what is happening here.

My question is: How can other tasks execute with less processing time even though there is a while loop which is taking all CPU time? What if all tasks have the same priorities, including the one that have the while loop?
 

miniwinwm

Joined Feb 2, 2018
67
I know. But I'm just looking into what is happening here.

My question is: How can other tasks execute with less processing time even though there is a while loop which is taking all CPU time? What if all tasks have the same priorities, including the one that have the while loop?
It still depends... on the configuration of FreeRTOS, the tasks and what the other tasks are doing (i.e. are they calling an OS function that yields or waiting for a resource). For example, if all the tasks are running at idle priority state, then config settings like configIDLE_SHOULD_YIELD will vary the behaviour of task switching. If config setting configUSE_TIME_SLICING is set to a non-default value, then the thread switching might also be a bit unexpected and not context switch as required. But generally, if the thread priorities are equal, configuration is standard, then switching will take place on every processor tick, each getting an equal go.
 

Thread Starter

Xavier Pacheco Paulino

Joined Oct 21, 2015
728
It still depends... on the configuration of FreeRTOS, the tasks and what the other tasks are doing (i.e. are they calling an OS function that yields or waiting for a resource). For example, if all the tasks are running at idle priority state, then config settings like configIDLE_SHOULD_YIELD will vary the behaviour of task switching. If config setting configUSE_TIME_SLICING is set to a non-default value, then the thread switching might also be a bit unexpected and not context switch as required. But generally, if the thread priorities are equal, configuration is standard, then switching will take place on every processor tick, each getting an equal go.
Alright. So the task that has the while loop will somehow lose the CPU control if all the tasks have the same priority. Would it be time-slicing anyways? The ADC task monopolize the CPU for 100 ms, and then release the control?

It's all about guessing in this problem.
 
Top