Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem TCP & FAT




Loading

Char buffer corruption within FreeRTOS queue messages

Posted by rksheth on July 28, 2015

Some info first: HW: STM32F407 Discovery board Compiler: gcc-arm-none-eabi-4_8-2014q2 Yes, demo code (and a fair bit of my code) runs fine on this device.

I'm implementing a USART trace logging feature to be used in a multi-task environment. The idea is that multiple tasks can send a message to the "debugQueue" and the "debugTask" will sequentially service them and write them out over USART. In order to implement this, I created a queue of the following type:

typedef struct{ uint16t size; tracelevelt level; char buffer[UARTBUFSIZE]; } debugqueuemsgt;

I have tested the basic UART code and know that it works correctly.

What I am finding is that the strings that I place in the message buffer come out garbled when they are received by the debugTask.

Here's an example:

I have inspected the message in GDB immediately before sending: xQueueSend(debugQueue, &msg, 0);

and immediately after receiving it in the debugTask: xQueueReceive(debugQueue, &msg, portMAX_DELAY );

Former: (gdb) p msg $2 = {size = 33, level = TRACE_MED, buffer = "SPEED HARD SET TO 0.75 DUTY CYCLE", '245' }

Latter: (gdb) p msg $3 = {size = 33, level = TRACE_MED, buffer = "S", '245' , "375377377377000000000000", '245' , "275024"}

As you can see, the first character is still present but the rest of the string has been overwritten.

Not sure if I'm missing something obvious or if there's something I don't understand about using queues with FreeRTOS.

I should also point out that I'm aware that placing a 100 byte buffer within the queue message is not ideal - but I'm not sure whether there's a fundamental issue with that or if it's just bad practice because introduces some extra writes.

Any advice is appreciated!


Char buffer corruption within FreeRTOS queue messages

Posted by richard_damon on July 28, 2015

Could your receiving task be overruning its stack? That is a somewhat large object if the receiving task is using the stack to hold it.

I am also a bit concerned that the incoming message isn't null terminated. This means you need to be very careful to not use any routines (like strcpy) to move the string around.


Char buffer corruption within FreeRTOS queue messages

Posted by rtel on July 28, 2015

The queue should work whatever the size of the item being queued, provided you have created the queue correctly so each item is actually that size. As you say yourself, queuing something that big is not ideal, normally for something so large you would just queue a pointer to it - but then you have to ensure the string still exists in the buffer being pointed to at the time it is printed out.

To add to Richard Damon's comment on stack overflow, do you have configCHECKFORSTACK_OVERFLOW set to 2? Also, do you have configASSERT() defined?

Regards.


Char buffer corruption within FreeRTOS queue messages

Posted by rksheth on August 5, 2015

Appreciate the input.

@ Richard - I do in fact explicitly insert a null character as the last char in the buffer, and I memcpy the entire buffer, as opposed to doing a strcpy. It's inefficient, but should be safe. I also use strnlen for sizes elsewhere - moral of the story, I think I'm covered from null character related issues.

@ RTE - Config assert is defined and the check for stack oveflow variable is set to 2. I was also concerned about stack overflow, so I changed the stack size of the task from min stack size (260 in the config file I have) to 1024, but saw the same behavior. I should note that I didn't see my code enter the stack overflow handler.

I did consider passing a pointer, but in order to guarantee that the buffer with my string would not be overwritten, I realized I'd need to create one of the following: 1) A secondary shared circular buffer with a mutex on it, which can cause tasks to block 2) A secondary shared circular buffer with a new task servicing it with a queue, effectively recreating my debug task 3) Provide a circular buffer to each task that uses the debug interface, which seems messy and not very scalable. Plus, then I have to think about my buffer size with respect to my message volume in addition to my queue size.

In conclusion, limiting my message size and keeping the buffer in the queue message seems the most elegant solution, even if it does consume some more cycles.

If you have any recommendations on other experiments I can try to narrow down why that buffer is getting corrupted, I would welcome them.

Thanks!


Char buffer corruption within FreeRTOS queue messages

Posted by heinbali01 on August 6, 2015

Hi,

You can either pass the messages by value, and create a big message queue like this:

~~~~~ /* Just some examples of sizes */

define UARTBUFSIZE 64
define DEBUGMSGCOUNT 100

typedef struct{ uint16t size; tracelevelt level; char buffer[UARTBUFSIZE]; } debugqueuemsgt;

/* The size of this queue is big: 100 time the size of 'debugqueuemsg_t', approximately 6800 bytes: */

xQueueCreate( DEBUGMSGCOUNT, sizeof( debugqueuemsg_t ) );

~~~~~

Or you can pass the message by reference (memory pointer), and create it like this:

~~~~~

define DEBUGMSGCOUNT 100

/* This queue will only store and forward objects of the size of a pointer. This size of this queue is only 100 * 4 = 400 bytes: */ xQueueCreate( DEBUGMSGCOUNT, sizeof( debugqueuemsg_t * ) )

~~~~~

It looks like you mixed things up: your queue has an element size of 4 bytes and you expect it will hold complete message of type 'debugqueuemsg_t', is that true?

Regards.


Char buffer corruption within FreeRTOS queue messages

Posted by heinbali01 on August 6, 2015

Some addition to my previous post:

FreeRTOS Queues are used for several purposes, for example:

  • Semaphores: nothing is being stored and the element size is zero
  • Token queues: the element size equals 1 and characters are being sent
  • Messages queues: the element size equals to the size of a memory pointer

I would not recommend using queues to store large objects as in my previous post.

If you pass pointers you must make sure who is the owner of the pointers at any time. A safe and easy way is to use 2 queues:

~~~~~ void vLoggingInit( void ) { BaseType xIndex; static debugqueuemsgt messages[ DEBUGMSG_COUNT ];

    /* The queue that will be consumed by the UART task. */
    xLoggingQueue = xQueueCreate( DEBUG_MSG_COUNT, sizeof( debug_queue_msg_t * ) );

    /* The queue that holds free messages. */
    xFreeQueue = xQueueCreate( DEBUG_MSG_COUNT, sizeof( debug_queue_msg_t * ) );
    for( xIndex = 0; xIndex < DEBUG_MSG_COUNT; xIndex++ )
    {
        debug_queue_msg_t *pxPointer = messages + xIndex;
        xQueueSendToBack( xFreeQueue, ( void *)&pxPointer, 0 );
    }
}
void vSendLogging( trace_level_t xLevel, const char *pcFormat, ... )
{
    debug_queue_msg_t *pxPointer;
    if( xQueueReceive( xFreeQueue, ( void *)&pxPointer, 0ul ) != pdFALSE )
    {
    va_list vArgs;

        /* pxPointer is ours now, fill the fields. */
        pxPointer->level = xLevel;
        va_start (vArgs, pcFormat);
        pxPointer->size = vsnprintf( pxPointer->buffer, sizeof pxPointer->buffer, pcFormat, vArgs );
        va_end (vArgs);
        /* The parameter 'xTicksToWait' can safely be set at the maximum because
        xLoggingQueue is created big enough to to hold ALL messages: */
        xQueueSendToBack( xLoggingQueue, ( void *)&pxPointer, portMAX_DELAY );
    }
    else
    {
        /* The UART task is a bit slow, all messages are occupied. */
    }
}
void vReceiveLogging( ... )
{
    debug_queue_msg_t *pxPointer;
    if( xQueueReceive( xLoggingQueue, ( void *)&pxPointer, 0ul ) != pdFALSE )
    {
        /* Send the message: */
        uart_send( pxPointer );
        /* Pass the pointer to the poll of free pointers: */
        xQueueSendToBack( xFreeQueue, ( void *)&pxPointer, portMAX_DELAY );
    }
}

~~~~~

The above function vSendLogging() can be rewritten as an ISR version but I would not recommend to do so: it will influence the process too much.

Note: I didn't take the time to test the above code, excuse me if it contains typos or some mistake :-)

Regards.


[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]




Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

FreeRTOS kernel V10 is available for immediate download. Now MIT licensed.


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

OpenRTOS and SafeRTOS