Error when queue handle is created run-time

Hi all,

I made a simple program with 2 tasks and 2 queues and I’ve been able to make it work.
Both tasks modify the variable passed through the queus.
programArchitecture
I have just a question regarding the creation of the queue handler.
If I create them at compile-time there are no issues, but if I do it run-time the program crashes.

Both queues handle are contained in a structure.
If I create the handle’s structure before the main() as:

UBaseType_t uxQueueLength = 1;
UBaseType_t uxItemSize = sizeof(uint32_t);
    ...
    ...
typedef struct{
    QueueHandle_t hQueueTx;
    QueueHandle_t hQueueRx;
}queues_t;
// queues structure created as COMPILE-TIME
queues_t queues;

Everything works as expected.

But if I move the structure creation in the main function the program doesn’t work anymore.

    int main(void) {
        ...
        ...
        // queues structure created as RUN-TIME
        queues_t queues;

        // queues creation
        queues.hQueueTx = xQueueCreate(uxQueueLength, uxItemSize);
        queues.hQueueRx = xQueueCreate(uxQueueLength, uxItemSize);
        ...
        ...
    /* TASK A CREATION */
        if(pdPASS == xTaskCreate(
                vTaskA, "Task_A", usStackDepth, (void*)&queues, uxPriority, &hTask_A)){
            // task successfully created
        }

    /* TASK B CREATION */
        if(pdPASS == xTaskCreate(
                vTaskB, "Task_B", usStackDepth, (void*)&queues, uxPriority, &hTask_B)){
            // task successfully created
        }
        ...
        ...

Precisely, when the task executes the xQueueSendToBack() the PC jumps to the HardFault_Handler.

void vTaskA(void *pvStruct){
    uint32_t variable = 0;
    queues_t *queues = (queues_t*)pvStruct;

    for(;;){
        // send the variable value to the Task_B through the Tx queue
        if(xQueueSendToBack(
                queues->hQueueTx,
                (void*)&variable,
                portMAX_DELAY) == pdFAIL){
            // buffer not available
        }
    ...
    ...

In fact in this last case I can see that the handles don’t contain the correct values set at the queues creation (see images below).
Why? That’s suprise me… I spent few debug hours about this…

Here the queues structure inside the running task when is created run-time:

queueStructureRunTime

While here the same queues structure created compile-time (when the program works):

queueStructureCompileTime

In the Reference Manual (V10.0.0) page 201 the example code creates the queue handle in run-time and uses the code as I did it:

    int main( void )
    {
    QueueHandle_t xQueue;
    /* Create the queue, storing the returned handle in the xQueue variable. */
    xQueue = xQueueCreate( QUEUE_LENGTH, QUEUE_ITEM_SIZE );
    if( xQueue == NULL )
    {
    /* The queue could not be created – do something. */
    }
    /* Create a task, passing in the queue handle as the task parameter. */
    xTaskCreate( vAnotherTask,
    “Task”,
    STACK_SIZE,
    ( void * ) xQueue, /* xQueue is used as the task parameter. */
    TASK_PRIORITY,
    NULL );
    /* Start the task executing. */
    vTaskStartScheduler();

Can someone help me to understand this?

Many thanks!
AGA

It depends on the FreeRTOS port you are using, but some re-purpose the stack used by main() as the stack used by interrupts. Therefore the variables you placed on the stack of main() will get corrupted the first time an interrupt executes.

In main

queues_t queues;

are stored on main stack. Don’t do this.
The main stack should be considered being (kind of) outside the scope of FreeRTOS. For some ports it’s re-used as ISR stack for instance.
Better use persistent storage (static/global variables or heap) for OS handles and/or other shared data.

Hi Richard, hi Hartmut,

many thanks for the explanations.
This makes sense, I’ll always think using this scheme.
I like also the idea of use the static beside the global declaration.
:+1:

What about the example in the documentation? Do I need then to consider it wrong?
I mean the example should work exhaustively with all the supported MCU isn’t it?

Kind regards,
AGA

Yes agree the example is misleading. It will work with some FreeRTOS ports, but not the most recent. Should update.