Message queue send and receive

Hello,

In FreeRTOS on TI C2000 MCU, I added a message queue to pass a command from the serial communication task to the LED display task. The command can be passed successfully. But after a few times communication, the program doesn’t run anymore. After stopping the program, the CCS shows below information, different at each time:
No source available for “$…/device/f28004x_codestartbranch.asm:81:95$() at C:/work\prj-freertos\Freertos280049\CPU1_RAM\Freertos280049.out:{3} 0x85{4}”
No source available for “_system_post_cinit() at C:/work\prj-freertos\Freertos280049\CPU1_RAM\Freertos280049.out:{3} 0x180000{4}”
No source available for “SysCtl_delay() at C:/work\prj-freertos\Freertos280049\CPU1_RAM\Freertos280049.out:{3} 0x9817{4}”
Sometimes, it causes illegal instruction interrupt, but not always.

What might be the reason and how to track what’s happening with message queue send and receive with FreeRTOS?

Thanks!
Crane

Have you worked through the list of usual suspects on this page of the faq?

Thanks Richard! Yes, it is relevant to memory use. Now it is addressed.

Just realize that if the task receiving a queue has higher priority than the task sending the queue, the queue will never be empty.
My case is like this, but the result is not like this. The queue is full and causes the issue in the first post in this thread. Eventually I have to empty the queue when it is full to address this issue. But it looks it should not be addressed this way.
Anyone knows what might cause this to happen?

That is only true if the sending task doesn’t need to wait for something to produce a result. (and I presume you mean sender higher than receiver, or the queue should be empty most the time).

Personally, a task that isn’t waiting for something but just running should be at at the idle priority. Higher priorities are for things that need to give a quick response from when something happens that unblocks the task.

When you say “That is only true if …”, does “That” refer to what I realized “if the task receiving a queue has higher priority than the task sending the queue, the queue will never be empty.”?
I mean receiver is higher than sender. So once the sender sends out a queue, the receiver will receive it right away and the queue will be emptied. See the Figure 31 in Richard Barry’s tutorial. Here is the part of Figure 31:

Right, so task B should continue and read that last value from the queue.

If it is waiting elsewhere, then what it is waiting for there is the cause for the queue to not empty. In fact, what is stopping Task B from reading the 10 before the 20 was written, since you say B is higher in priority than A?

I am a bit confused. Let’s go back my case.
One task A is sending the queue and another task B is receiving the queue. No other task is involved in the message queue send and receive. Task B has higher priority. So, according to what’s explained in the book Figure 31, which is logical, once a message is written to the queue by Task A, it is supposed to be read by the Task B. The queue is supposed to be empty all the time.
But what I see in my code is that the message is still there even after the message is received by Task B. Later, the queue gets full and I have to use a function to empty the queue. What I observe is not in comply with what’s said in the book Figure 31. This is what I don’t understand.

If you read a message from a queue, the message is not in the queue anymore. The data will still show up if you look at the raw memory of the queue, but the pointers will indicate that it isn’t part of the queue contents.

If you just “peek” the data, it will stay in the queue, you need to actually “Receive” the data.

Something is wrong with your code if this isn’t happening.

Ok. What’s the different between “peek” and “receive” then?
This is how I receive:
if(pdPASS == xQueueReceive(xQueue_Command,
&command,
(TickType_t)(100/portTICK_PERIOD_MS)))
Anything wrong with this way to actually receive instead of to just “peek” the data?

xQueuePeek is different and somewhat special. Usually you have to xQueueReceive otherwise the queue overflows sooner or later.
However, as Richard pointed out there is a bug somewhere in your code (or in the port for your CPU ?) because the behavior you see is broken.
Did you define configASSERT and enabled stack overflow checking ?
Or post the relevant code (task and queue creation/send/receive). Otherwise it’s hard to guess what’s going wrong.

Thanks Hartmut for your reply.
Yes, stack overflow checking is enabled.
configASSERT is defined, but not in the FreeRTOS config file. Once I add its definition in the config file, there will be compiler error.

Below is the task creation for the two tasks:

    xTaskCreateStatic(LED_TaskBlue,         // Function that implements the task.
                      "Blue LED task",      // Text name for the task.
                      STACK_SIZE_UART_CONFIG,           // Number of indexes in the xStack array.
                      ( void * ) BLUE,      // Parameter passed into the task.
                      tskIDLE_PRIORITY + 2, // Priority at which the task is created.
                      blueTaskStack,        // Array to use as the task's stack.
                      &blueTaskBuffer );    // Variable to hold the task's data structure.

    xTaskCreateStatic(Uart_TaskConfig,      // Function that implements the task.
                      "UART Config task",   // Text name for the task.
                      STACK_SIZE_UART_CONFIG,           // Number of indexes in the xStack array.
                      ( void * ) 0,         // Parameter passed into the task.
                      tskIDLE_PRIORITY + 1, // Priority at which the task is created.
                      uartTaskStack,        // Array to use as the task's stack.
                      &uartTaskBuffer );    // Variable to hold the task's data structure.

Below is the queue creation code:

    xQueue_Command = xQueueCreateStatic(COMMAND_QUEUE_LENGTH,
                                        COMMAND_ITEM_SIZE,
                                        ucQueueStorageArea_Command,
                                        &xStaticQueue_Command);
    configASSERT(xQueue_Command);

Below is the queue send code in UART Config task:

if(pdPASS != xQueueSend(xQueue_Command,
                                        (void*)&command,
                                        (TickType_t)(10 / portTICK_PERIOD_MS)))
{
...
}

Below is the queue receive code in Blue LED task:

        if(pdPASS == xQueueReceive(xQueue_Command,
                                   &command,
                                   (TickType_t)(100/portTICK_PERIOD_MS)))
{
...
}

So STACK_SIZE_UART_CONFIG intentionally applies to both tasks, right ?
How are the stacks and the queue storage area defined/allocated ?
I guess xQueue_Command is a global variable, right ?
And also important, what’s the task code where send/receive are called ?
I mean is there anything else which might block or prevent the LED task from receiving items from the queue ?
If you have a debugger attached, it should be straight forward to follow the way of a queue item sent. Put a breakpoint right after the (successful) xQueueReceive and it should be hit right after successfully executing xQueueSend because this task has a higher priority than the sending task and should be activated immediately after getting unblocked by putting an item into the (empty) queue.

Yes, STACK_SIZE_CONFIG intentionally applies to both task.

Here are the storage area definition:
static StaticTask_t uartTaskBuffer;
static StackType_t uartTaskStack[STACK_SIZE_UART_CONFIG];
static StaticTask_t blueTaskBuffer;
static StackType_t blueTaskStack[STACK_SIZE];
QueueHandle_t xQueue_Command = NULL;
StaticQueue_t xStaticQueue_Command;
uint16_t ucQueueStorageArea_Command[COMMAND_QUEUE_LENGTH * COMMAND_ITEM_SIZE];

Yes, xQueue_Command is a global variable.
I don’t think there is anything that could block the LED task from receiving items. I set the breakpoint and it can receive every message sent from another task. But it just doesn’t clear the queue buffer.

Do you need the code for the whole task of the two tasks?

The code you shared does not seem to create the stacks using the same size -

static StackType_t uartTaskStack[STACK_SIZE_UART_CONFIG];
static StackType_t blueTaskStack[STACK_SIZE];

How do you verify that?

That will be helpful. It will be even better if you can share minimal code example showing the problem.

Yes, they use different stack size. Do they need to use the same stack size?

It cause problems when running. I set break point and find they queue gets full. Then I add the code to empty the queue after it is full, then the program is able to run.

Click Here , you will be able to see the whole project.

No, they DO NOT need to use the same stack size. But look at the following 2 calls to xTaskCreateStatic and both of them use STACK_SIZE_UART_CONFIG for stack size:

   xTaskCreateStatic(LED_TaskBlue,         // Function that implements the task.
                      "Blue LED task",      // Text name for the task.
                      STACK_SIZE_UART_CONFIG,           // Number of indexes in the xStack array.
                      ( void * ) BLUE,      // Parameter passed into the task.
                      tskIDLE_PRIORITY + 2, // Priority at which the task is created.
                      blueTaskStack,        // Array to use as the task's stack.
                      &blueTaskBuffer );    // Variable to hold the task's data structure.

    xTaskCreateStatic(Uart_TaskConfig,      // Function that implements the task.
                      "UART Config task",   // Text name for the task.
                      STACK_SIZE_UART_CONFIG,           // Number of indexes in the xStack array.
                      ( void * ) 0,         // Parameter passed into the task.
                      tskIDLE_PRIORITY + 1, // Priority at which the task is created.
                      uartTaskStack,        // Array to use as the task's stack.
                      &uartTaskBuffer );    // Variable to hold the task's data structure.

This is because you call vTaskDelayUntil in LED_TaskBlue - why do you do that? This task should only block on the queue receive. Right now this task is blocked after processing one command (because of vTaskDelayUntil) and therefore, the queue is getting full.

Your sender and receiver task should roughly look like the following -

void ReceiverTask(void * pvParameters)
{
    for(;;)
    {
        /* Block here waiting for a command. */
        if( pdPASS == xQueueReceive( xQueue_Command,
                                     &command,
                                    (TickType_t)(100/portTICK_PERIOD_MS)) )
        {
            /* Process command. */
        }
        else
        {
            /* A command was not received within the specified timeout. Probably
             * the sender is slow. */
        }
    }
}


void SenderTask(void * pvParameters)
{
    for( ;; )
    {
        /* Post a command to the queue. This will unblock the receiver task
         * which will run as soon as the command is posted to the queue (i.e.
         * before the call to xQueueSend returns. */
        if(pdPASS != xQueueSend( xQueue_Command,
                                 (void*)&command,
                                 (TickType_t)(10 / portTICK_PERIOD_MS)))
        {
            /* Error handling goes here. */
        }
    }
}

I need this function call to flash LED.
Ok got it. I will see if something else can be used here to create a delay.

You could use simply vTaskSetTimeOutState/xTaskCheckForTimeOut to implement the LED flashing period.
Set the LED ON, use vTaskSetTimeOutState to init the timeout and xQueueReceive with a reasonable timeout (less or equal the flashing period) on reception of the corresponding command and depending on the current blinking frequency.
Then e.g. when checking state use xTaskCheckForTimeOut to switch OFF the LED on expiration. Then re-init the timeout for the LED OFF period and so on…
Alternatively you could use a FreeRTOS timer sending a ‘timeout’ command to the queue in it’s callback you can handle appropriately.
I wouldn’t use a timed xQueueReceive if not necessary. It’s just overhead polling a queue instead of waiting (forever) until a command or message comes in.

1 Like

So you would use portMAX_DELAY to wait forever for the queue message. If doing so, the task would enter block state and vTaskDelayUntil couldn’t be used. So you would use vTaskSetTimeOutState/vTaskCheckForTimeOut.
Is this the complete consideration for this application?

How is it relevant to my initial question as quoted below?