FreeRTOS provides various communication mechanisms for inter-task communication, including queues, semaphores, mutexes, event groups, and task notifications. Below is a detailed introduction to queues.Queues Queues support asynchronous data transfer between tasks and between tasks and ISRs. They can transfer any type of data and support multiple tasks sending data to the same queue, as well as multiple tasks receiving data from a single queue. The default mode is first-in, first-out, but it can be configured to last-in, first-out. The sender can block when the queue is full, and the receiver can block when the queue is empty.Kernel Implementation PrinciplesThe core data structure is the Queue Control Block (QueueCB_t).
typedef struct QueueCB { uint8_t *pcHead; // Start address of the queue storage area uint8_t *pcTail; // End address of the queue storage area (+1) uint8_t *pcWriteTo; // Next write position uint8_t *pcReadFrom; // Next read position UBaseType_t uxMessagesWaiting; // Number of messages currently in the queue UBaseType_t uxLength; // Maximum number of messages in the queue (capacity) UBaseType_t uxItemSize; // Size of a single message in bytes // List of tasks waiting for the queue (sorted by priority) List_t xTasksWaitingToSend; // List of tasks waiting to send List_t xTasksWaitingToReceive; // List of tasks waiting to receive volatile BaseType_t xRxLock; // Receive lock counter (0 means unlocked) volatile BaseType_t xTxLock; // Send lock counter (0 means unlocked) #if (configUSE_QUEUE_SETS == 1) struct QueueCB *pxQueueSetContainer; // Associated queue set (if any) #endif} QueueCB_t;
Queue Creation Methods:(1) Dynamically create a queue:QueueHandle_t xQueueCreate(UBaseType_t xQueueLength,UBaseType_t uxItemSize);This function dynamically allocates two blocks of memory: the queue control block and the data storage area (on the heap), with a size of uxQueueLength * uxItemSize (queue length * element size).(2) Statically create a queue:QueueHandle xQueueCreateStatic( UBaseType_t uxQueueLength, UBaseType_t uxItemSize, uint8_t *pucQueueStorageBuffer,// User-provided storage buffer StaticQueue_t*pxQueueBuffer// User-provided queue control block buffer};The location of the data storage area is determined by the pointer provided by the user, which can be a user-defined global array, stack, or dynamically allocated manually managed heap.Enqueue Operation Process:(1) Enter critical section: disable interrupts to prevent task switching, ensuring atomicity of operations.(2) Check queue status:If the queue is not full: Copy data from pvItemToQueue to the location pointed to by pcWriteTo -> Update the pcWriteTo pointer (circular buffer) -> check if there are tasks waiting, see if the xTaskWaitingToReceive list is empty; if not, wake up the highest priority task among them and move it to the ready list -> function returns pdPASS.If the queue is full: If the blocking time is 0, return immediately; if the blocking time > 0, move the current task from the ready list to the xTasksWaitingToSend list -> set a timeout timer -> exit the critical section and trigger the scheduler to switch to other tasks.
Queue Data Reception (xQueueGenericReceive):(1) Enter critical section.(2) Check queue status:If the queue is not empty: Copy data from the location pointed to by pcReadFrom to pvBuffer -> update the pcReadFrom pointer -> check if there are tasks waiting to send, see if the xTasksWaitingToSend list is not empty; if so, wake up the highest priority task among them, function returns pdPASS.If the queue is empty: If the blocking time is 0, return immediately; if the blocking time > 0, move the current task from the ready list to the xTasksWaitingToReceive list -> set a timeout timer -> exit the critical section and trigger the scheduler to switch to other tasks.