Exercise: Creating FreeRTOS Tasks Part-1
Now let’s implement two tasks called task 1 and task 2.
You already know the API to create a task, i.e., xTaskCreate(). Now let’s select that API. Remember that in order to use this API, you have to include task.h.
#include<stdio.h> #include<stdint.h> #include<string.h> #include "stm32f4xx.h" #include "task.h" int main(void) { //1. Reset the RCC clock configuration to the default reset state. //HSI ON, PLL OFF, HSE OFF, system clock = 16MHz, cpu_clock = 16MHz RCC_DeInit(); //2. update the SystemCoreClock variable SystemCoreClockUpdate(); //3. lets create 2 tasks , task-1 and task-2 xTaskCreate()
API for the creation of tasks
Now let’s explore the task creation API. You have to give all the parameters shown in Figure 1. Just copy the API shown in Figure 1 and paste it into your project, as shown in Figure 2.
You have to pass the following values as a parameter of xTaskCreate API.
- Now the first thing is you have to mention the task handler or task function. Let’s give the task handler the name as a first parameter of the xTaskCreate() API. Give the task handler name as vTask1_handler, as shown below.
- The second parameter is giving a name for that task. This name must describe the particular task since it is used for identification purposes. Depending on your application, it may be a USB stack, a packet reception task, UART task, timer task, or whatever.
//3. lets create 2 tasks , task-1 and task-2
xTaskCreate( vTask1_handler,"Task-1", configMINIMAL_STACK_SIZE,NULL,2,&xTaskHandle1 );
Call for xTaskCreate() API in main.c.
- Now the third parameter that you have to mention is stack depth. It holds the value of the amount of stack memory you want to assign for that particular task. In this case, the task is Task1. Remember that each task in FreeRTOS will have its own stack memory in the main system RAM in order to do push and pop operation, save some local variables, etc. Whatever the value you mention as the third parameter of the API, that many numbers of bytes will be allocated as a stack for this particular task in the RAM memory. Since our “Hello World” project is a very trivial application, it doesn’t require more stack.
Let’s see, is there any minimal stack setting for a particular task? For that, let’s go to the FreeRTOSConfig.h file (Figure 3), and here you will see one configurable item named configMINIMAL_STACK_SIZE, which is initialized to 130. Here 130 means 130 words. If you want to convert this into bytes, you have to multiply it by the word size. The word size for ARM Cortex MX-based microcontroller is 1 word = 4 bytes. So, you have to multiply the minimal stack size value by 4 in order to convert it into a number of bytes. Now the minimal stack size will be 130 x 4 = 520 bytes. Now let’s use this configurable item as the third parameter of task create API (Figure 4). Basically, we dedicated 520 bytes of stack memory for Task 1.
- Any parameter that you want to pass when the task handler executes must be passed as the fourth parameter. Currently, we don’t want to send any parameters. So, let’s make it NULL.
- After that, what is the priority of this task? Remember, every task will have its own priority. The lowest priority that you can give to a task is 0. Zero is considered as an idle priority, i.e., the priority of the idle task. Either you can mention the lowest priority possible, i.e., actually 0, you cannot give negative numbers here or give the maximum priority. The maximum priority that you can assign for a task is configurable, which you can get from FreeRTOSConfig.h. In FreeRTOSConfig.h, there is a configurable item called configMAX_PRIORITIES, and that is initialized to 5 (Figure 4).
The value of maximum priority is highly application-specific. There is no hard and fast rule that you should keep this as 5. You can change it. Currently, the value is 5, which is the maximum priority you can assign for a particular FreeRTOS task. Let’s use a priority value 2 (Figure 4) that is higher than idle priority and less than the maximum priority.
- The last parameter is the task handle. Every task you create will have its own task handle, and by using that task handle, you can handle the particular task like deleting a task, suspending a task, resuming a task, etc. This is like an identification number for a particular task, for which you just created a handle in order to twist that task the way you want, like deleting and changing its properties, etc. You have to send one argument as a 6th parameter to catch hold up that task handler. This is very important. Let’s do that as follows:
- For that, first, create a variable for a task handle and initialize it to NULL. Also, create another task handle variable and call it a xTaskHandle2.
#include "stm32f4xx.h" #include "task.h" TaskHandle_t xTaskHandle1=NULL; TaskHandle_t xTaskHandle2=NULL;
Creation of task handle variable
- After that, send the address of the task handle because the API needs an address or a pointer. So, let’s send the address.