FreeRTOS simultaneous tasks - c

I want to create two tasks that run simultaneously in FreeRTOS. The first task will deal with the LED, the second task will monitor the temperature.
I have two questions:
Will this code create two tasks that run simultaneously?
How do I send the data between the tasks, for example: if the temperature is more than x degrees, turn on the LED?
void firstTask(void *pvParameters) {
while (1) {
puts("firstTask");
}
}
void secondTask(void *pvParameters) {
while (1) {
puts("secondTask");
}
}
int main() {
xTaskCreate(firstTask, "firstTask", STACK_SIZE, NULL, TASK_PRIORITY, NULL);
xTaskCreate(secondTask, "secondTask", STACK_SIZE, NULL, TASK_PRIORITY, NULL);
vTaskStartScheduler();
}

Tasks of equal priority are round-robin scheduled. This means that firstTask will run continuously until the end of its time-slice or until it is blocked, then secondTask will run for a complete timeslice or until it is blocked then back to firstTask repeating indefinitely.
On the face of it you have no blocking calls, but it is possible that if you have implemented RTOS aware buffered I/O for stdio, then puts() may well be blocking when its buffer is full.
The tasks on a single core processor are never truly concurrent, but are scheduled to run as necessary depending on the scheduling algorithm. FreeRTOS is a priority-based preemptive scheduler.
Your example may or not behave as you intend, but both tasks will get CPU time and run in some fashion. It is probably largely academic as this is not a very practical or useful use of an RTOS.

Tasks never really run simultaneously - assuming you only have one core. In you case you are creating the tasks with the same priority and they never block (although they do output strings, probably in a way that is not thread safe), so they will 'share' CPU time by time slicing. Each task will execute up to the next tick interrupt, at which point it will switch to the other.
I recommend reading the free pdf version of the FreeRTOS book for a gentle introduction into the basics https://www.freertos.org/Documentation/RTOS_book.html

Related

FreeRTOS task interrupting other tasks

I am learning about mutex and semaphore. And got a quick question to clarify:
void task1(void* parameter){
while(1){
global_var++;
}
}
void task2(void* parameter){
while(1){
global_var++;
}
}
xTaskCreate(task1,"task1",10000,NULL,1,NULL); // receiving modem input
xTaskCreate(task2,"task2",10000,NULL,1,NULL); // receiving modem input
If I have 2 tasks that are accessing one global variable. Is there a possibility if one task will interrupt another task if both are the same priority? Or the issues only start happening when one command is different priority or the task is being interrupted via the timer or other interrupts?
The tasks are getting scheduled by the operating system (f.e.: freertos). It depends on which scheduling technique is used. If it uses Round-Robin, the tasks are scheduled fairly, which means task2 will be scheduled after (defined timeslice) task1. Which means no starvation.
But as you mentioned if there is a interrupt, the ISR will be executed instead of task1 or task2.
A example can be found on: freertos page
There are two sheduling policies:
FreeRTOS kernel supports two types of scheduling policy:
Time Slicing Scheduling Policy: This is also known as a round-robin algorithm. In this algorithm, all equal priority tasks get CPU in equal portions of CPU time.
Fixed Priority Preemptive Scheduling: This scheduling algorithm selects tasks according to their priority. In other words, a high priority task always gets the CPU before a low priority task. A low priority task gets to execute only when there is no high priority task in the ready state. (from https://microcontrollerslab.com/freertos-scheduler-learn-to-configure-scheduling-algorithm/)
You can select scheduling algorithms by setting corresponding configuration bits (flags/defines) in theFreeRTOSConfig.h file.
For synchronization you should use a mutex (SO answer mutex). As wovano said semaphores are not exactly the same as a mutex (see semaphores vs. mutex).
Yes, both tasks will be scheduled alternately and thus can "interrupt" each other. By default, the tasks will be switched every millisecond.
Since both tasks share a resource (the global variable) and the increment operation is (in general) not atomic, you should indeed use a mutex to prevent possible errors.
NB: A mutex is not the same as a semaphore. Since you want MUTual EXclusion in this case, a mutex is the right solution.
(Note: this is only true if FreeRTOS is configured to use preemptive scheduling with time slicing, i.e. configUSE_PREEMPTION == 1 amd configUSE_TIME_SLICING == 1, which is the default.)

Effective software scheduling

For example in a code like below
while(1){
task1();
task2();
}
there should be cooperation between task1() and task2() which are executed in rr fashion. However, if task1() is implemented as follows
task1(){
while(1);
}
Is there a way to build a scheduler which avoid monopolization of resources by task1() by only relying on software (for example switching tasks each 500 ms)?
Assume to have available only plain C/Assembly, and not rely on external scheduler/OS.
Is there a way to build a scheduler which avoid monopolization of resources by task1() by only relying on software (for example switching tasks each 500 ms)?
Yes it's possible; but it probably isn't possible in plain C because (at a minimum) you'd need to switch between different stacks during task switches.
However, you should know that just switching tasks every 500 ms is very "not effective". Specifically; when one task has to wait for anything (time delay, data received from network, user input, data to be fetched from disk, a mutex, ...) you want to keep the CPU busy by switching to a different task (if there are any other tasks).
To do that; you either need fully asynchronous interfaces for everything (which C does not have), or you need to control all of the code (e.g. write an OS).
Of course the majority of task switches are caused by "task has to wait for something" or "something task was waiting for occurred"; and switching tasks every 500 ms is relatively irrelevant (it only matters for rare tasks that don't do any IO), and even when it is relevant it's a bad idea (in a "10 half finished jobs vs. 5 finished jobs and 5 unstarted jobs" way).
one easy way is to use
a hardware timer,
a queue of tasks to run,
a scheduler
and a dispatcher.
a pre-allocated stack for each task
the timer interrupt handler triggers the scheduler. The scheduler determines which task is to run next. The scheduler triggers the dispatcher.
The dispatcher performs a 'context' switch between the prior running task and the next task to run, placing the prior running task back into the queue, then restores the 'context' of the next task to run, then
transfers execution control to the 'next' task,
The queue is composed of control blocks. The control blocks contain a copy of all the registers and the address of the entry point for the task

how to print a string not disordered in vxworks multitask environment?

void print_task(void)
{
for(;;)
{
taskLock();
printf("this is task %d\n", taskIdSelf());
taskUnlock();
taskDelay(0);
}
}
void print_test(void)
{
taskSpawn("t1", 100,0,0x10000, (FUNCPTR)print_task, 0,0,0,0,0,0,0,0,0,0);
taskSpawn("t2", 100,0,0x10000, (FUNCPTR)print_task, 0,0,0,0,0,0,0,0,0,0);
}
the above code show:
this is task this is task126738208 126672144 this is task this is
task 126712667214438208
this is task this is task 1266721441 26738208 this is task 126672144
this is task
what is the right way to print a string in multitask?
The problem lies in taskLock();
Try semaphore or mutex instead.
The main idea to print in multi-threaded environment is using dedicated task that printout.
Normally in vxWorks there is a log task that gets the log messages from all tasks in the system and print to terminal from one task only.
The main problem in vxWorks logger mechanism is that the logger task use very high priority and can change your system timing.
Therefore, you should create your own low priority task that get messages from other tasks (using message queue, shared memory protected by mutex, …).
In that case there are 2 great benefits:
The first one, all system printout will be printed from one single task.
The second, and most important benefit, the real-time tasks in the system should not loss time using printf() function.
As you know, printf is very slow function that use system calls and for sure change the timing of your tasks according the debug information you add.
taskLock,
taskLock use as a command to the kernel, it mean to leave the current running task in the CPU as READY.
As you wrote in the example code taskUnlock() function doesn't have arguments. The basic reason is to enable the kernel & interrupts to perform taskUnlock in the system.
There are many system calls that perform task unlock (and sometimes interrupts service routing do it also)
Rather than invent a home-brew solution, just use logMsg(). It is the canonical safe & sane way to print stuff. Internally, it pushes your message onto a message queue. Then a separate task pulls stuff off the queue and prints it. By using logMsg(), you gain ability to print from ISR's, don't have interleaved prints from multiple tasks printing simultaneously, and so on.
For example:
printf("this is task %d\n", taskIdSelf());
becomes
logMsg("this is task %d\n", taskIdSelf(), 0,0,0,0,0,0);

What should C program do in idle time when running on Linux?

I've written many C programs for microcontrollers but never one that runs on an OS like linux. How does linux decide how much processing time to give my application? Is there something I need to do when I have idle time to tell the OS to go do something else and come back to me later so that other processes can get time to run as well? Or does the OS just do that automatically?
Edit: Adding More Detail
My c program has a task scheduler. Some tasks run every 100ms, some run every 50 ms and so on. In my main program loop i call ProcessTasks which checks if any tasks are ready to run, if none are ready it calls an idle function. The idle function does nothing but it's there so that I could toggle a GPIO pin and monitor idle time with an O'scope... or something if I so desired. So maybe I should call sched_yield() in this idle function???
How does linux decide how much processing time to give my application
Each scheduler makes up its own mind. Some reward you for not using up your share, some roll dices trying to predict what you'll do etc. In my opinion you can just consider it magic. After we enter the loop, the scheduler magically decides our time is up etc.
Is there something I need to do when I have idle time to tell the OS
to go do something else
You might call sched_yield. I've never called it, nor do I know of any reasons why one would want to. The manual does say it could improve performance though.
Or does the OS just do that automatically
It most certainly does. That's why they call it "preemptive" multitasking.
It depends why and how you have "idle time". Any call to a blocking I/O function, waiting on a mutex or sleeping will automatically deschedule your thread and let the OS get on with something else. Only something like a busy loop would be a problem, but that shouldn't appear in your design in any case.
Your program should really only have one central "infinite loop". If there's any chance that the loop body "runs out of work", then it would be best if you could make the loop perform one of the above system functions which would make all the niceness appear automatically. For example, if your central loop is an epoll_wait and all your I/O, timers and signals are handled by epoll, call the function with a timeout of -1 to make it sleep if there's nothing to do. (By contrast, calling it with a timeout of 0 would make it busy-loop – bad!).
The other answers IMO are going into too much detail. The simple thing to do is:
while (1){
if (iHaveWorkToDo()){
doWork();
} else {
sleep(amountOfTimeToWaitBeforeNextCheck);
}
}
Note: this is the simple solution which is useful in a single-threaded application or like your case where you dont have anything to do for a specified amount of time; just to get something decent working. The other thing about this is that sleep will call whatever yield function the os prefers, so in that sense it is better than an os specific yield call.
If you want to go for high performance, you should be waiting on events.
If you have your own events it will be something like follows:
Lock *l;
ConditionVariable *cv;
while (1){
l->acquire();
if (iHaveWorkToDo()){
doWork();
} else {
cv->wait(lock);
}
l->release();
}
In a networking type situation it will be more like:
while (1){
int result = select(fd_max+1, &currentSocketSet, NULL, NULL, NULL);
process_result();
}

FreeRTOS tasks are not context switching

I'm using FreeRTOS port for PIC32 microcontroller on the PIC32MX starter kit. Was just playing with tasks but the tasks aren't context switching. Here are my main config settings:
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 )
#define configKERNEL_INTERRUPT_PRIORITY 0x01
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0x03
#define configTICK_RATE_HZ ( ( portTickType ) 100 )
Now I have two tasks defined which blink two LEDs. Both have priority of 4(highest). Under normal operation the LEDs should alternatively blink for each 100 ticks. But this doesn't happen. The second LED blinks for 100 ticks and the control goes to the general exception handler. Why does this happen? Seems like there is no scheduling at all.
FreeRTOS is a priority based pre-emptive scheduler, tasks of equal priority that do not yield processor time will be round-robin scheduled. Relying on round-robin scheduling is seldom suitable for real-time tasks, and depending on the configured time slice, that may mess up your timing. Time-slicing may even be disabled.
Your tasks must enter the Blocked state waiting on some event (such as elapsed time) to allow each other to run as intended.
That said, entering the exception handler rather than simply one task starving another or not running with the intended timing is a different matter. For that you will need to post additional information, though your first approach should be to deploy your debugger.
The absolute first thing to check is your "tick" interrupt. Often interrupts are not enabled, timers aren't set up right, clocks are not configured properly in the #pragma's that set up the PIC32.. and all those issues manifest themselves first in a lack of a "tick".
This is the #1 cause of not task switching: if you're not getting the tick interrupt. That's where the normal pre-emptive task switching happens.
Assuming you're using the "off the shelf demo", in MPLAB, set a breakpoint in the void vPortIncrementTick( void ) function (around line 177 in FreeRTOS\Source\portable\MPLAB\PIC32MX\port.c) and run your code. If it breakpoints in there, your timer tick is working.
Are you sure both tasks are well registered and the scheduler has been launched?
Something like the following code would do the job:
xTaskCreate( yourFirstTask, "firstTask", STACK_SIZE, NULL, TASK_PRIORITY, NULL );
xTaskCreate( yourSecondTask, "secondTask", STACK_SIZE, NULL, TASK_PRIORITY, NULL );
vTaskStartScheduler();
You can also add an application tick hook to see if the tick interruption occurs correctly or if there is a problem with the tick timer.
There are standard demo tasks that just blink LEDs in the FreeRTOS/Demo/Common/Minimal/flash.c source file. The tasks created in that file are included in the standard PIC32 demo application (which targets the Microchip Explorer16 board).
In its very simplest form, a task that just toggles and LED every 500ms would look like this:
/* Standard task prototype, the parameter is not used in this case. */
void vADummyTask( void *pvParameters )
{
const portTickType xDelayTime = 500 / portTICK_RATE_MS;
for( ;; )
{
ToggleLED();
vTaskDelay( xDelayTime );
}
}
Do you have a round-robin scheduler? Are your tasks sleeping for any length of time, or just yielding (or busy waiting)?
A very common gotcha in embedded OSs is that the scheduler will frequently not attempt to schedule multiple processes of the same priority fairly. That is, once A yields, if A is runnable A may get scheduled again immediately even if B has not had any CPU for ages. This is very counterintuitive if you're used to desktop OSs which go to a lot of effort to do fair scheduling (or at least, it was to me).
If you're running into this, you'll want to make sure that your tasks look like this:
for (;;)
{
led(on); sleep(delay);
led(off); sleep(delay);
}
...to ensure that the task actually stops being runnable between blinks. It won't work if it looks like this:
for (;;)
{
led(on);
led(off);
}
(Also, as a general rule, you want to use normal priority rather than high priority unless you know you'll really need it --- if you starve a system task the system can behave oddly or crash.)

Resources