1. RTOS
RTOS stands for Real Time Operating System. And as the name suggests, it is capable of doing tasks, as an
operating system does. The main purpose of an OS is to have the functionality, where we can use multiple
tasks at the same time.
2. 1.) Define A ThreadID for the task. This variable will store the unique ID of the
task, once created. Later, all the operations will require this ID.
osThreadId Task3Handle;
2.) Define the entry function for the task. This is the main function of the
task. Your program will be written inside it.the entry function should always
have an infinite loop, inside which, your whole program should be written.
void Task3_init (void const * argument)
{
While (1)
{
// do something
osDelay (1000); // 3 sec delay
}
}
osThreadId Task3Handle;
osThreadId Task3Handle;
Task/Thread Creation
3. 3.) Inside our main function, we need to define the task first and than create it.
Eg: // define thread
osThreadDef(Task3, Task3_init, osPriorityBelowNormal, 0, 128);
//create thread
Task3Handle = osThreadCreate(osThread (Task3), NULL);
osThreadDef takes the parameters as the name of the task, the entry function, the priority,
instance, and the stack size.
After the task is defined, we can create it using osThreadCreate, and assign the ID to
the Task3Handle
Task Priorities
osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
osThreadDef(Task2, Task2_init, osPriorityAboveNormal, 0, 128);
osThreadDef(Task3, Task3_init, osPriorityBelowNormal, 0, 128);
Now the Task2 have the highest priority, than Default task, and Task3 with the lowest.
When the program runs, Task2 will execute first, than default task and at last the Task3. And
all three tasks will send the data at the same time.
4. Suspend and Resume
Tasks
Whenever a Task is suspended, it will stay in the blocked state, until it is resumed
again.
if (indx==4)
{
osThreadSuspend(defaultTaskHandle);
}
if (indx ==7)
{
osThreadResume(defaultTaskHandle);
}
void task2_init (void const * argument)
{
while (1)
{
printf ("Task2 = %dn", indx++);
osDelay(2000);
if (indx==4)
{
printf ("suspending DefaultTaskn");
osThreadSuspend(defaultTaskHandle);
}
if (indx ==7)
{
printf ("Resuming DefaultTaskn");
osThreadResume(defaultTaskHandle);
}
}
}
The tasks will run in proper order till the indx was equal to 3. After printing the indx=3 statement, indx will increment to 4.
The Task2 will go in the blocking state at this point and default task will run.
After 2 seconds, task2 gets the control, and execute next statement in line. Indx is actually 4, and defaultTask will be suspended.
Now the kernel only have 1 task to run, and it will keep running Task2 every 2 seconds.
After the indx becomes 7, the default task will be resumed, and the both tasks will continue to run simultaneously.
5. Terminating the
Task
Unlike Suspend, once the Task is terminated, it can’t be resumed. To terminate the task, we will use
the osThreadTerminate function
void task2_init (void const * argument)
{
while (1)
{
printf ("Task2 = %dn", indx++);
osDelay(2000);
if (indx == 3)
{
printf ("Terminating DefaultTaskn");
osThreadTerminate(defaultTaskHandle);
}
}
}
As you can see above, when the indx variable becomes 3, the default task gets terminated, and only the task
2 runs after that.
6. Block the task for some
time
This is like, auto resuming of the task after some particular amount of time. We will use the function osDelayUntil to do
so. The arguments of this function as as follows:
osDelayUntil (uint32_t *PreviousWakeTime, uint32_t millisec)
PreviousWakeTime Pointer to a variable that holds the time at which the task was last unblocked.
void task2_init (void const * argument)
{
while (1)
{
printf ("Task2 = %dn", indx++);
osDelay(2000);
if (indx == 3)
{
uint32_t PreviousWakeTime =
osKernelSysTick();
osDelayUntil(&PreviousWakeTime,
4000);
}
}
}
So both the tasks run until the indx becomes 3. Once it does, the Task2 get suspended and default task keep running for 3
more seconds. The task 2 resumes itself after 3 seconds, and again both tasks run simultaneously.
7. Semaphores
Semaphores are basically used to synchronize tasks with other events in the system. In FreeRTOS, semaphores are
implemented based on queue mechanism.
There are 4 types of semaphores in FreeRTOS:-
1.) Binary Semaphore 2.) Counting Semaphore 3.)Mutex 4.)Recursive
A Binary Semaphore is called Binary because either it is there (1) or it is not (0). There is no third condition in it.
So, a Task either have the semaphore or it simply doesnot.
There are some problems associated with it. The most common one is Priority Inversion.
Basically, when a HIGH Priority Task have to wait for the LOWER Priority Task to finish, its called Priority Inversion.
8.
9.
10.
11. Counting Semaphore
SemaphoreHandle_t CountingSem;
CountingSem = xSemaphoreCreateCounting(3,0);
if (CountingSem == NULL)
HAL_UART_Transmit(&huart2, (uint8_t *) "Unable to Create Semaphorenn", 28, 100);
else
HAL_UART_Transmit(&huart2, (uint8_t *) "Counting Semaphore created successfullynn", 41, 1000);
xSemaphoreCreateCounting takes 2 parameters, First is the maximum number of count, second is the initial value.
Here it created a semaphore with 3 tokens, and initial number of tokens available will be 0.
// create TASKS
xTaskCreate(HPT_TASK, "HPT", 128, NULL, 3, &HPThandler);
xTaskCreate(MPT_TASK, "MPT", 128, NULL, 2, &MPThandler);
xTaskCreate(LPT_TASK, "LPT", 128, NULL, 1, &LPThandler);
xTaskCreate(VLPT_TASK, "VLPT", 128, NULL, 0, &VLPThandler);
vTaskStartScheduler();
Here HPT_TASK is the function, where the task code is written
“HPT” is just a name of this task. This name is not used anywhere in the program.
128 is the stack size
NULL indicates that I am not passing any argument to the Task
3 is the Priority of the Task
&HPThandler is the handler of the Task
12. void HPT_TASK (void *pvParameters)
{
char sresource[3];
int semcount = 0;
char ssemcount[2];
// Give 3 semaphores at the beginning..
xSemaphoreGive(CountingSem);
xSemaphoreGive(CountingSem);
xSemaphoreGive(CountingSem);
while (1)
{
char str[150];
xSemaphoreTake(CountingSem, portMAX_DELAY);
strcat (str, "n Not releasing the Semaphorennn");
HAL_UART_Transmit(&huart2, (uint8_t *)str, strlen (str), HAL_MAX_DELAY);
indx++;
if (indx>2) indx=0;
vTaskDelay(3000);
}
}
13.
14. Mutex
Mutex, which is short for Mutual Exclusion, does what’s it name indicates. It prevents several tasks from accessing a resource mutually.
It ensures that at one time, only one task have access to the resource.
15. Below are the functions for two tasks. Both of them will make a call to the function, Send_Uart.
16.
17.
18.
19.
20. Queues
xQueueHandle SimpleQueue;
SimpleQueue = xQueueCreate(5, sizeof (int));
if (SimpleQueue == 0) // Queue not created
{
char *str = "Unable to create Integer Queuenn";
HAL_UART_Transmit(&huart2, (uint8_t *)str, strlen (str), HAL_MAX_DELAY);
}
else
{
char *str = "Integer Queue Created successfullynn";
HAL_UART_Transmit(&huart2, (uint8_t *)str, strlen (str), HAL_MAX_DELAY);
}
21.
22.
23. Timers
A software timer allows a function to be executed at a set time in the future.
The function executed by the timer is called the timer’s callback function.
There are two types of timers, one-shot timers, and auto-reload timers.
A one-shot timer can execute its callback function only once. It can be manually re-started, but will not automatically re-start itself.
Conversely, an auto-reload timer will automatically re-start itself after each execution of its callback function, resulting in periodic callback execution.
/* Create the timer(s) */
/* definition and creation of periodicTimer */
osTimerDef(periodicTimer, PTCallback);
periodicTimerHandle = osTimerCreate(osTimer(periodicTimer), osTimerPeriodic, NULL);
/* definition and creation of onceTimer */
osTimerDef(onceTimer, OTCallback);
onceTimerHandle = osTimerCreate(osTimer(onceTimer), osTimerOnce, NULL);