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