This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

FreeRTOS Queues seem broken.

Hi,

The xQueueReceive function in FreeRTOS seems to be broken, when a non-zero timeout is specified.

Example, I'm trying to create and ordered output mechanism for the UART using a task and a FIFO queue:

static void uart_output_task(void * arg)
{
    for (;;)
    {
        struct SerialPortOutput spo;

        printf("uart_output_task: Waiting for data to send, come on.\n");
        
        // Block waiting on data in the queue.
        if (xQueueReceive(m_uart_output_queue, &spo, 100))
        {
            printf("Sending data to UART.\n");
            
            // Send data to UART.
            nrf_drv_uart_tx(spo.output, spo.length);
        }
        else
        {
            printf("uart_output_task: xQueueReceive had nothing to send.\n");
        }
        
        // char test[8] = "test\r\n";
        // nrf_drv_uart_tx(test, 6);
    }
}

If I specify a timeout to the xQueueReceive method (in this case 100 ticks), the task prints the first printf() and stops forever while waiting. I should be seeing that printf() every 100 ticks. If I set the queue receive timeout to 0, it loops appropriately, but this is of course not the behavior I want. This also happens if I set it to portDELAY_MAX.

Thanks, Max

  • The first thing is - what is the system doing when its apparently stuck in xQueueReceive(). Are other tasks running. If you pause the debugger, what is executing? Are you sure its not in a fault handler?

    Are you sure the tick interrupt is executing? If you put a break point in xTaskIncrementTick() in FreeRTOS/Source/tasks.c, does it ever get hit? If the tick count is not increment the timeout will never occur.

    How is your printf() implemented. That can often cause in small microcontroller systems, especially when it is used in more than one task, or uses semihosting (which will conflict with the kernel interrupts).

    Have you checked for stack overflow? Do you have configASSERT() defined? Etc.

  • Unbelievable. The problem was that the default configTOTAL_HEAP_SIZE

    #define configTOTAL_HEAP_SIZE                                                     ( 4096 )
    

    Breaks after only 2 user tasks have been implemented. Trying to start a third task causes vTaskStartScheduler to fail.

    Reconfiguring this, for now, to:

    #define configTOTAL_HEAP_SIZE                                                     ( 8192 )
    

    Fixes the problem.

    So it's not a problem in the Queue. Thanks for the help guys.

    Here's the sample code with gdb trace:

    /**@brief Function for application main entry.
     */
    int main(void)
    {
        // Do not start any interrupt that uses system functions before system initialisation.
        // The best solution is to start the OS before any other initalisation.
    
        // Init a semaphore for the BLE thread.
        m_ble_event_ready = xSemaphoreCreateBinary();
    
        if(NULL == m_ble_event_ready)
        {
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
        
        m_uart_output_queue = xQueueCreate(5, sizeof (struct SerialPortOutput));
        
        if (m_uart_output_queue)
        {
            printf("UART output queue created successfully!\n");
        }
        else
        {
            printf("UART output queue could not be created!\n");    
        }
    
        // Start execution.
        if(pdPASS != xTaskCreate(ble_stack_thread, "BLE", 256, NULL, 1, &m_ble_stack_thread))
        {
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
    
        nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;
    
        if (NRF_SUCCESS == nrf_drv_uart_init(&uart_config, uart_event_handler))
        {
            printf("UART initialized properly.\n");
        }
        else
        {
            printf("UART failed to initialize properly.\n");
        }
        
        if (pdPASS != xTaskCreate(uart_output_task, "UART Output Task", 256, NULL, 1, &m_uart_output_thread))
        {
            printf("Out of memory.");
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
    
        if (pdPASS != xTaskCreate(uart_test_task, "Test UART Task", 256, NULL, 1, &m_uart_test_task))
        {
            printf("Out of memory.");
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
        
        /* Activate deep sleep mode */
        // SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    
        // Start FreeRTOS scheduler.
        vTaskStartScheduler();
    
        while (true)
        {
            printf("Oops.\n");
            APP_ERROR_HANDLER(NRF_ERROR_FORBIDDEN);
        }
    }
    

    gdb output is:

    Breakpoint 1, main () at /home/max/nRF5_SDK_11.0.0_89a8197/examples/ble_peripheral/ble_app_hrs_freertos/main.c:1205
    1205	{
    
    (gdb) break vTaskStartScheduler
    Breakpoint 2 at 0x1e2c0: file /home/max/nRF5_SDK_11.0.0_89a8197/external/freertos/source/tasks.c, line 1544.
    (gdb) continue
    Continuing.
    
    Breakpoint 2, vTaskStartScheduler () at /home/max/nRF5_SDK_11.0.0_89a8197/external/freertos/source/tasks.c:1544
    1544	{
    (gdb) n
    1552			xReturn = xTaskCreate( prvIdleTask, "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
    (gdb) n
    1565				xReturn = xTimerCreateTimerTask();
    (gdb) n
    1574		if( xReturn == pdPASS )
    (gdb) n
    main () at /home/max/nRF5_SDK_11.0.0_89a8197/examples/ble_peripheral/ble_app_hrs_freertos/main.c:1304
    1304	        printf("Oops.\n");
    (gdb) 
    
Related