FreeRTOS.org provides:
Queues can contain 'items' of fixes size - with the size of each item and the maximum number of items the queue can hold both being defined when the queue is created.
Items are placed into a queue by copy, not by reference. It is therefore preferable to keep the size of each item placed into the queue to a minimum. Placing items into a queue by copy greatly simplifies your application design as two tasks cannot access the data simultaneously. The queue takes care of all mutual exclusion issues for you.
If you wish to queue large items then it might be preferable to instead queue a pointer to each item - but when doing so care must be taken to ensure that your application clearly defines which task and/or interrupt is the 'owner' of the data.
Queue API functions permit a block time to be specified. The block time indicates the maximum number of 'ticks' that a task should enter the Blocked state to either wait for data to become available on a queue (in the case that a task is reading from a queue and the queue is already empty), or wait for space to become available on a queue (in the case where a task is writing to a queue, but the queue is already full). Should more than one task block on the same queue then the task with the highest priority will be the task that is unblocked first.
See the Queue Management section of the user documentation for a list of queue related API functions. Searching the files in the FreeRTOS/Demo/Common/Minimal directory will reveal multiple examples of their usage. Note that interrupts must NOT use API functions that do not end in "FromISR".

Binary semaphores and mutexes are very similar but have some subtle differences: Mutexes include a priority inheritance mechanism, binary semaphores do not. This makes binary semaphores the better choice for implementing synchronisation (between tasks or between tasks and an interrupt), and mutexes the better choice for implementing simple mutual exclusion. The description of how a mutex can be used as a mutual exclusion mechanism holds equally for binary semaphores. This sub section will only describe using binary semaphores for synchronisation.
Semaphore API functions permit a block time to be specified. The block time indicates the maximum number of 'ticks' that a task should enter the Blocked state when attempting to 'take' a semaphore, should the semaphore not be immediately available. If more than one task blocks on the same semaphore then the task with the highest priority will be the task that is unblocked the next time the semaphore becomes available.
Think of a binary semaphore as a queue that can only hold one item. The queue can therefore only be empty of full (hence binary). Tasks and interrupts using the queue don't care what the queue holds - they only want to know if the queue is empty or full. This mechanism can be exploited to synchronise (for example) a task with an interrupt.
Consider the case where a task is used to service a peripheral. Polling the peripheral would be wasteful of CPU resources, and prevent other tasks from executing. It is therefore preferable that the task spends most of its time in the Blocked state (allowing other tasks to execute) and only execute itself when there is actually something for it to do. This is achieved using a binary semaphore by having the task Block while attempting to 'take' the semaphore. An interrupt routine is then written for the peripheral that just 'gives' the semaphore when the peripheral requires servicing. The task always 'takes' the semaphore (reads from the queue to make the queue empty), but never 'gives' it. The interrupt always 'gives' the semaphore (writes to the queue to make it full) but never takes it. The source code provided on the xSemaphoreGiveFromISR() documentation page should make this clearer.
Task prioritisation can be used to ensure peripherals get services in a timely manner - effectively generating a 'differed interrupt' scheme. An alternative approach is to use a queue in place of the semaphore. When this is done the interrupt routine can capture the data associated with the peripheral event and send it on a queue to the task. The task unblocks when data becomes available on the queue, retrieves the data from the queue, then performs any data processing that is required. This second scheme permits interrupts to remain as short as possible, with all post processing instead occurring within a task.
See the Semaphores/Mutexes section of the user documentation for a list of semaphore related API functions. Searching the files in the FreeRTOS/Demo/Common/Minimal directory will reveal multiple examples of their usage. Note that interrupts must NOT use API functions that do not end in "FromISR".

Counting semaphores are typically used for two things:
In this usage scenario an event handler will 'give' a semaphore each time an event occurs (incrementing the semaphore count value), and a handler task will 'take' a semaphore each time it processes an event (decrementing the semaphore count value). The count value is therefore the difference between the number of events that have occurred and the number that have been processed. In this case it is desirable for the count value to be zero when the semaphore is created.
In this usage scenario the count value indicates the number of resources available. To obtain control of a resource a task must first obtain a semaphore - decrementing the semaphore count value. When the count value reaches zero there are no free resources. When a task finishes with the resource it 'gives' the semaphore back - incrementing the semaphore count value. In this case it is desirable for the count value to be equal the maximum count value when the semaphore is created.
See the Semaphores/Mutexes section of the user documentation for a list of semaphore related API functions. Searching the files in the FreeRTOS/Demo/Common/Minimal directory will reveal multiple examples of their usage. Note that interrupts must NOT use API functions that do not end in "FromISR".
When used for mutual exclusion the mutex acts like a token that is used to guard a resource. When a task wishes to access the resource it must first obtain ('take') the token. When it has finished with the resource it must 'give' the token back - allowing other tasks the opportunity to access the same resource.
Mutexes use the same semaphore access API functions so also permit a block time to be specified. The block time indicates the maximum number of 'ticks' that a task should enter the Blocked state when attempting to 'take' a mutex if the mutex is not immediately available. Unlike binary semaphores however - mutexes employ priority inheritance. This means that if a high priority task blocks while attempting to obtain a mutex (token) that is currently held by a lower priority task, then the priority of the task holding the token is temporarily raised to that of the blocking task. This mechanism is designed to ensure the higher priority task is kept in the blocked state for the shortest time possible, and in so doing minimise the 'priority inversion' that has already occurred.
Priority inheritance does not cure priority inversion! It just minimises its effect in some situations. Hard real time applications should be designed such that priority inversion does not happen in the first place.

This type of semaphore uses a priority inheritance mechanism so a task 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the semaphore it is no longer required.
Mutex type semaphores cannot be used from within interrupt service routines.
Any and all data, files, source code, html content and documentation included in the FreeRTOS distribution or available on this site are the exclusive property of Richard Barry.
See the files license.txt (included in the distribution) and this copyright notice for more information. FreeRTOSTM and FreeRTOS.orgTM are trade marks of Richard Barry.