Problem in starter project with PIC32MK using xQueueReceive()

Hello everybody,

we are currently starting a new project and use a Microchip PIC32MK with Harmony v3 and FreeRTOS. We started using a very basic feature. We would like to use a task with a queue and semaphore to control the sending of UART logs.

But the feature is not working as expected. xQueueReceive() is called. But the task sometimes waits forever while entries are present. We already checked for stack problems and found no problem. Assert is also configured. In other forum threads, it was mentioned that one of the most common issues are the interrupt priorities. But I couldnt find any obvious mistake.

Could someone with more FreeRTOS knowledge/experience have a look and tell me if we do something stupid?

//This structure contains the variables used by the task
typedef struct
{
    /* The application's current state */
    SYSTEM_LOG_APP_STATES state;
    
    QueueHandle_t txQueueHandle;
    TaskHandle_t taskHandle;
    SemaphoreHandle_t txSemaphoreHandle;
    QueueSetHandle_t txQueueSetHandle;
    uint8_t txBuffer[UART6_TRANSMIT_BUFFER_SIZE];
} SYSTEM_LOG_APP_DATA;

//This function is called once before scheduler is started
void SYSTEM_LOG_APP_Initialize ( void )
{
    /* Place the App state machine in its initial state. */
    system_log_appData.state = SYSTEM_LOG_APP_STATE_INIT;

    //Init variables
    system_log_appData.txQueueHandle = NULL;
    system_log_appData.taskHandle = NULL;
    system_log_appData.txSemaphoreHandle = NULL;
    system_log_appData.txQueueSetHandle = NULL;
    memset((void*)&system_log_appData.txBuffer[0], 0, UART6_TRANSMIT_BUFFER_SIZE);
}

//Main task called by scheduler
void SYSTEM_LOG_APP_Tasks (void *pvParameters)
{
    //Handle parameter to allow later access (by task and ISR)
    SYSTEM_LOG_APP_TASK_PARAMETER* parameter = (SYSTEM_LOG_APP_TASK_PARAMETER*)pvParameters;
    
    system_log_appData.txQueueHandle = parameter->txQueueHandle;
    system_log_appData.taskHandle = parameter->taskHandle;
    system_log_appData.txSemaphoreHandle = parameter->txSemaphoreHandle;
    system_log_appData.txQueueSetHandle = parameter->txQueueSetHandle;
    
    /* Check the application's current state. */
    switch ( system_log_appData.state )
    {
        /* Application's initial state. */
        case SYSTEM_LOG_APP_STATE_INIT:
            //Init semaphore by give call.
            if(xSemaphoreGive(system_log_appData.txSemaphoreHandle) == pdPASS)
            {
                //OK. do nothing.
            }else{
                //This may/should never happen. Semaphore looked forever.
                configASSERT(0);
            }            
            
            //Show initial start log
            SYSTEM_LOG_APP_AddLog(system_log_appData.txQueueHandle,             (uint8_t*)"StartOfLog:\r\n", 13);
            
            //Init uart callback
            UART6_WriteCallbackRegister(&UartWriteEventHandler, (uintptr_t)NULL);
            system_log_appData.state = SYSTEM_LOG_APP_ACTIVE;
            break;
        case SYSTEM_LOG_APP_ACTIVE:
            {
                uint8_t tempBuffer[UART6_TRANSMIT_BUFFER_SIZE];
                memset((void*)&tempBuffer[0], 0, UART6_TRANSMIT_BUFFER_SIZE);
                
                if(xQueueReceive(system_log_appData.txQueueHandle, &tempBuffer[0], 0) == pdTRUE){
                    //Queue message received. Wait for semaphore.
                    if(xSemaphoreTake(system_log_appData.txSemaphoreHandle, portMAX_DELAY) == pdTRUE){
                        memcpy((void*)&system_log_appData.txBuffer[0], (void*)&tempBuffer[0], UART6_TRANSMIT_BUFFER_SIZE);
                        UART6_Write(&system_log_appData.txBuffer[0], GetLengthOfBuffer(&system_log_appData.txBuffer[0]));
                    }else{
                        configASSERT(0);
                    }                    
                }else if(xSemaphoreTake(system_log_appData.txSemaphoreHandle, 0) == pdTRUE){
                    //Semaphore ready. Wait for message from queue.
                    if(xQueueReceive(system_log_appData.txQueueHandle, &tempBuffer[0], portMAX_DELAY) == pdTRUE){
                        memcpy((void*)&system_log_appData.txBuffer[0], (void*)&tempBuffer[0], UART6_TRANSMIT_BUFFER_SIZE);
                        UART6_Write(&system_log_appData.txBuffer[0], 
                    }else{
                        configASSERT(0); 
                    }
                }else{
                    //Wait for queue or semaphore by queueset
                    xQueueSelectFromSet(system_log_appData.txQueueSetHandle, portMAX_DELAY);
                    //Do nothing here. Function is called again.
                }
            }
            break;
        default:
            //do nothing. UART not working.
            configASSERT(0);
            ;
    }
}

//This function is called by other tasks to store a log message in the queue.
void SYSTEM_LOG_APP_AddLog(QueueHandle_t queueHandle, uint8_t* logMessage, size_t logMessageLength)
{
    //Create temporary buffer with same length as queue element
    uint8_t tempBuffer[UART6_TRANSMIT_BUFFER_SIZE];
    memset((void*)&tempBuffer[0], (int)0, (size_t)UART6_TRANSMIT_BUFFER_SIZE);
    
    //Check size of message
    size_t evaluatedLength;
    if(logMessageLength > UART6_TRANSMIT_BUFFER_SIZE){
        configASSERT(0);
        evaluatedLength = UART6_TRANSMIT_BUFFER_SIZE;
    }else{
        evaluatedLength = logMessageLength;
    }
    
    //Copy log into temporary buffer
    memcpy((void*)&tempBuffer[0], (void*)logMessage, evaluatedLength);
    
    //Assure string is null terminated. Last item always set to zero
    tempBuffer[UART6_TRANSMIT_BUFFER_SIZE - 1] = 0;
    
    //Only send if queueHandle is valid
    if(queueHandle == 0){
        configASSERT(0);
    }else{
        //Assert if message was not stored for debug purposes.
        BaseType_t queueResult = xQueueSend(queueHandle, &tempBuffer[0], 0);
        if(pdTRUE == queueResult){
            //OK. Entry added.
            system_log_appData.queueMessagesWaiting =   uxQueueMessagesWaiting(queueHandle);
            system_log_appData.queueMessagesManual++;
        }else{
            configASSERT(0);
        }
    }
}


//This function is called by an interrupt after UART finished sending the previous log
static void UartWriteEventHandler(uintptr_t context )
{
    if(system_log_appData.txSemaphoreHandle == NULL)
    {
        //Do nothing. Semaphore not initialized yet.
    }   
    else
    {    
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        xSemaphoreGiveFromISR(system_log_appData.txSemaphoreHandle,
                                                     &xHigherPriorityTaskWoken);

        portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
    }
}

Thanky you.

Best regards
Marcel Darming

Hi there Marcel,

may I suggest that you first present useful, readable and minimalistic code before you expect us to analyze it?

Where is the initialization code, for example? I don’t find a call to xQueueCreate() or xTaskCreate() in the code you provide (if you leave your queue at 0 as your code implies, you shouldn’t be surprised that nothing happens, as I’m sure you know, so you should at least include the real initialization code), instead a lot of (excuse the frank assessment) poorly written code fragments that don’t give any useful clue to where your problem could be.

Also, your task function is very, uhm, unusual. There is no infinite loop, as a task normally has, and the copying of the decoded task parameter structure (if you don’t tell us how you create your task, we can’t possibly know whether the parameters make any sense) to a global structure in the task function head doesn’t make sense.

I would suggest that your start from scratch, work your way through the many code samples provided and go on from there.