[MUSIC] In this lesson we continue our FreeRTOS adventure, and we will study some more advanced concepts in FreeRTOS. More specifically, the part of the OS that is responsible for task management, interclass communication, and synchronization. FreeRTOS might be a small kernel, but it still contains a wide range of basic functionalities needed in and always. Just to mention a few, we have passive waiting, priority modification, task suspension, ways of measuring time, callback hooks, and lightweight notifications. Some platforms also support memory protection by software. And in this lesson we will shortly introduce semaphores and mutexes used for resource sharing and also message queues used to send information between tasks. Going from internal kernel mechanics to user space functionalities, we want to have a look at something needed in most applications which share software resources. I'm of course talking about OS semaphores and mutexes. The different between them is that semaphores do not include priority inheritance while mutexes do. Here is the two task each of them containing different functionality. They also have both a compute function that has to be completed before the other task can access it. So this means that the task must protect this section with a lock. And in this example, we use a mutex. So the mutexes is stating by which ever task happens to get it first. And then the task which got the mutexes begins to compute part of the code. And the other task must simply wait until the mutex is free again. Only now can Task 2 take the mutex and begin its compute section. When Task 2 has completed the section, the mutex is given back and any task can again grab it. We take a similar example with three tasks, but in this case we are using semaphores for locking the resources. Here all the tasks starts from the point indicated by the arrows. Task 1 comes first to the point of lock and resources. It then grabs the semaphore with ID one, so that no other task can take the same semaphore. So now when Task 2 tries to take the semaphore, it will never be successful because it was never returned. We have also a Task 3 which only functionality is to return the semaphore. When the execution of Task 3 starts, it returns the semaphore with the ID one back to the system. And Task 2 can now grab it and enter in the compute stage. Task 2 also rhythms the semaphore when the computation is completed and anybody is again free to grab the semaphore. A binary semaphore is created in FreeRTOS by first creating a SemaphoreHandle same as creating a task handle for tasks. So all the things associated with the semaphore is then done through the semaphore handle. Then the semaphore is initialized by fastening the handle to the correct function. The same thing can be done for mutexes, just by switching out the function call to the mutex call. The second primary functionality that we want to present in this lecture is the data queue. Data cues and FreeRTOS are used to pass data between tasks or between tasks and interrupts. So let's say we have two tasks, Task1 and Task2. And we want to connect these two tasks with a queue. So the queue is allocated in the memory or not. So the task is done through shared memory. You can, for example, have Task1 writing to the queue, and Task2 reading from the queue. You create a queue by defining the queue handle of type xQueueHandle. So as you see, this looks quite the same as creating task handles and semaphore handles. Then the queue must be initialized with a create call that takes the one queue length as an argument and decides per queue item as another argument. The queue item is the message defined with a c struct and this is what the data message will contain. As the queue is created a message is defined. The task can start to read and write to a queue, to send and receive data using the xQueueSend and xQueueReceive commands. So let's say we have a local data structure buffer called Message. To this buffer we can add items that we want to send in the Queue. So now we are ready to send data to the Queue, and this we do with the xQueueSend command. The first argument is the queue handle. And here it is called xQueue. And then we pass the message itself. The last parameter is the timeout we are willing to wait in case the queue is currently full. To receive data from the queue, we basically do the opposite procedure. And here we have two choices, either we can just look at the content of the queue or we can pull the content from the queue. And looking at the content is done with xQueuePeek. And when peeking the Queue, nothing is removed from the Queue, but the content can be copied to local data structure. On the other hand, when receiving a data item from the Queue, the data item is also removed from the Queue. So normally when we read a queue we also want to do some kind of error check when getting the message. So the receive function can be surrounded by an if statement. If we get an item from the Queue successfully, FreeRTOS will pass a pdPass flag. If this one is false, then something went wrong or the Queue was empty. Otherwise, we got good data from the Queue. In conclusion, we have looked at some more advanced functionalities in FreeRTOS, namely synchronization and data queues. And if you want to have a closer look at FreeRTOS you can because it's opensource, so even the kernel source code is available.