Let’s get some facts about FreeRTOS tasks before attempting to create one. A task has four states it can be in: Running, Ready, Blocked or Suspended state. So a task is running if it’s been allocated time and is executing in the CPU. A task is ready if it is not running, simply because there is another task running in the CPU and its waiting its turn, kinda. A task is blocked if it’s waiting for an external event or it’s called the delay function. It’s worth noting that a blocked task usually has a timeout after which it will enter the ready state whether the external event already happened or not. And finally a task is in suspended state if it calls the function to suspend itself, vTaskSuspend(NULL) or another task calls that function passing the task’s handle, vTaskSuspend(xTaskHandle). A task will only come out of the suspended state if there is a call to the vTaskSuspend( xTaskHandle ) function passing the task’s handle, xTaskHandle.
Each task also has a priority which can have a value from 0 upto (configMAX_PRIORITIES -1). For now lets assume this maximum priority value is 32. You can read up on the details of what determines this maximum value in the docs.
To create a task, we will need to decide the priority we need to assign it. The priority number denotes the urgency of running the task in the the CPU. The bigger the number, the higher the priority. The system has what is called the idle task with priority 0. We will talk more about it later, but for now we can base our tasks’ priorities on the idle task’s priority, tskIDLE_PRIORITY. Priorities make sense if you have multiple tasks in the system, so we will create two tasks. One task to print “hello” and the other one to print “world” to the standard output. We will assign both tasks priority 1 and test, then change the priorities to see what happens.
We need to understand the FreeRTOS API functions necessary to create a task and schedule it.
Writing code for a task
Tasks in FreeRTOS are created to execute C functions with infinite loops in them. In C, we declare a function in a .h file, define it in a .c file and then you call it in the main method. Similarly, we need to declare and define a task before we can create it.
The process of a task goes something like:
So for our hello task will have have the following code in the .h and .c files.
We can do the exact same thing for the “world” task .
We also need to modify the main.c file to remove all the tests and only run our two tasks. We need to leave the standard FreeRTOS callback/hook functions in place but comment anything inside so to remove the functionality. We can use them later and the build also complains without them.
Finally, we need to edit the makefile to remove the demo objects and include our two object files in the binary by including the two .c files.
Now we can build and test the simulation.
What if we edit hello.h and change line 4 to
And now we build and test:
This is really a simplistic test, as you can see, although both tasks have exactly same execution time, world runs first just because it has higher priority. We can do further tests with more complex tasks later. I hope this makes things super easy for someone to create some tasks and schedule them in FreeRTOS.