The previous program is exactly the same as the second code, but this time the complete structures are not sent to the tasks. Instead, pointers are sent, which contain the memory addresses where these structures are located. This way, more data memory is saved. How much memory is saved in this case, and how much space does the queue reserve?

Code Example:

#include "bsp.h"

#define SENDER_1   1    /* ID of sender to identify on the Queue message */
#define SENDER_2   2    /* ID of sender to identify on the Queue message */

typedef struct                              /* Creation of struct to send as a message */
{
    unsigned char ucValue;                  /* Varible to store the message of the sender */
    unsigned char ucSource;                 /* Variable to identify the Sender */
}_xData;

_xData xDataToSend1 = {101, SENDER_1};      /* Creation of variable struct to fill variables ( used as a message data ) */
_xData xDataToSend2 = {202, SENDER_2};      /* Creation of variable struct to fill variables ( used as a message data ) */

void vSenderTask( void *pvParameters );     /* Declare the sender task function */
void vReceiveTask( void *pvParameters );    /* Declare the receiver task function */

QueueHandle_t xQueue;                       /* Queue handler */

int main( void )
{
    HAL_Init();

    /*enable RTT and system view*/
    SEGGER_SYSVIEW_Conf( );
    SEGGER_SYSVIEW_Start( );
    
    xQueue = xQueueCreate( 3, sizeof( _xData* ) );                          /* Creation of the Queue */

    xTaskCreate(vSenderTask, "task1", 240, (void*)&xDataToSend1, 2, NULL);  /* Resister sender task1 with a priority of 2 */
    xTaskCreate(vSenderTask, "task2", 240, (void*)&xDataToSend2, 2, NULL);  /* Resister sender task2 with a priority of 2 */
    
    xTaskCreate(vReceiveTask, "task3", 240, NULL, 1, NULL);                 /* Register the receiver task with priority of 1 */

    vTaskStartScheduler();                                                  /* Execution of Kernel */
}

void vSenderTask( void *pvParameters )
{
    _xData *xSendStruct = (_xData*)pvParameters;                /* Struct variable casted to receive the parameter function */
    const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;   /* variable to store Ticks to wait in ms */
    
    for(;;)
    {
        xQueueSend( xQueue, &xSendStruct, xTicksToWait );       /* Send the message */
        taskYIELD();                                            /* Change the context to other task task with the same priority */
    }
}

void vReceiveTask( void *pvParameters )
{
    _xData *xReceivedStruct;                                    /* Struct variable to receive the message */
    const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;   /* variable to store Ticks to wait in ms */
    
    for(;;)
    {
        xQueueReceive( xQueue, &xReceivedStruct, xTicksToWait ); /* Wait to receive data */
        
        if( xReceivedStruct->ucSource == SENDER_1 )              /* Check in struct parameter if the sender is the SENDER_1 */
        {
            /* Execute only if message is from task sender 1 */   
            SEGGER_SYSVIEW_PrintfHost("Tarea Sender 1 = %d", xReceivedStruct->ucValue);   /* Print the message on Terminal */    
        }
        else
        {
            /* Execute only if message is from task sender 2 */
            SEGGER_SYSVIEW_PrintfHost("Tarea Sender 2 = %d", xReceivedStruct->ucValue);   /* Print the message on Terminal */
        }
    }
}
💡
Before proceeding: Create a timeline graph that shows how the tasks occupy processor time, including the IDLE task.

SystemView Output

The system View output is equal to the previous program. The Receiver task processes the messages and identifies which sender task sent the message.

Document

Timeline:

Document

Exactly like the previous example, Task1 and Task2 init sending messages to the queue, when the receiver task executes the first message read is the message from Task1.

Next, Task1 sends the message to the queue.
When the receiver task executes, read the message from Task2 sent before the last execution of Task1.

When Task2 executes sends the struct message to the queue, but again the receiver task going to read the message from the last execution of Task1.