Queues#
FIFO
Writing to a queue is atomic which means that another task cannot interrupt it during the writing process.
Adding something to a queue(enqueue) is done using Pass by value not Pass by reference - when you save something to a queue the entire contents of the value(struct, variable, string, buffer) is copied.
You can place a pointer into a queue, but you want to be sure that the referenced value is still in scope by the time the pointer is read by the receiving task.
Example
Suppose Task A sends a pointer to a local variable to Task B via a queue:
void TaskA(void *pvParameters) { int value = 42; int *ptr = &value; xQueueSend(queue, &ptr, portMAX_DELAY); // value goes out of scope when TaskA ends or value is overwritten } void TaskB(void *pvParameters) { int *receivedPtr; xQueueReceive(queue, &receivedPtr, portMAX_DELAY); // Using *receivedPtr here is only safe if value is still valid }FreeRTOS queues can accept any type assuming enough memory space allocation for each element. Keep filling up the queue so long as there are enough elements.
READ: Another task when asynchronously reads from the queue at any time - this will remove the first item in the queue and cause all other items to shif by one element freeing up another spot for other tasks to write to.
Timeout: In the receiving task, you can specify a timeout (in ticks) to wait if the queue is empty. If no new data arrives within that period, the receive function returns a failure status, indicating that nothing was read. Similarly, in the sending task, you can specify a timeout to wait if the queue is full. If no space becomes available within that period, the send function returns a failure status, indicating that the item was not added to the queue and we can try again or drop the data or maybe we can make the queue larger to avoid this issue.
There is 2 types of queues in FreeRTOS:
- Static Queues: The memory for the queue is allocated at compile time. This is more efficient
and deterministic, but you need to know the maximum size of the queue beforehand. Created using
xQueueCreateStatic().- Dynamic Queues: The memory for the queue is allocated at runtime. This is more flexible, but
it can lead to fragmentation and is less deterministic. Created using
xQueueCreate().
- Dynamic Queues: The memory for the queue is allocated at runtime. This is more flexible, but
it can lead to fragmentation and is less deterministic. Created using
- Static Queues: The memory for the queue is allocated at compile time. This is more efficient
and deterministic, but you need to know the maximum size of the queue beforehand. Created using
You should not use the
xQueueSend()orxQueueReceive()functions from an ISR. Instead, you should use thexQueueSendFromISR()orxQueueReceiveFromISR()functions. That is because interrupts do not depend on the tick timer and should not wait any amount of time for the queue.