Task hangs on xQueueReceive

nixz wrote on Tuesday, November 14, 2017:

Hi All,

I’m using STM32F767 with CubeMX and open STM32 compiler. I have latest CubeMX is using FreeRTOS 9.0.0. I have 3 tasks (TaskA, TaskB, TaskC) every of these 3 task have same structure:

void StartTaskA(void const * argument)
{
	uint32_t msg = 0;

	for (;;)
	{
		while( xQueueReceive(TaskAudioInputQueueHandle, &msg, portMAX_DELAY) != pdTRUE )
		//while( xQueueReceive(TaskAudioInputQueueHandle, &msg, 100) != pdTRUE )
			;

		switch(msg)
        {
            // message stuff
        }
}

TaskA has Normal priority, TaskB has High priority and TaskC has Realtime priority.
TaskA is sending to the queue of TaskB, TaskB is waiting on xQueueReceive().

I’m sure that I send from TaskA:

xQueueSendToBack(TaskHandle, &msg, 0);

It seems that in TaskA “xQueueSendToBack(TaskHandle, &msg, 0);” return pdTRUE for the first N times (however it isn’t handled from the other task) and faild with subsequent calls (when queue is full besause TaskB is not returns from xQueueReceive).

Maybe I shall call some manual task reschedule/notify/etc procedure?

TaskA sending message to TaskB not from ISR.

Any Idea what can be wrong? It seems that situation is better when all task has Normal priority.

Lower priority task can’t Resume Higher priority task by adding elements to it’s queue?

Thx in advance for any comments and ideas to check!

best regards
Mik

rtel wrote on Tuesday, November 14, 2017:

Do you have configASSERT() defined?

nixz wrote on Tuesday, November 14, 2017:

Yes, I have configASSERT() by default from CubeMX.

I’ve debugged xQueueSendToBack and it pass all asserts, hovewer queues is full because higher priority task does not wake to read queue filled by lower priority task…

nixz wrote on Tuesday, November 14, 2017:

Do you suspect that xQueueReceive() is frozen on some configASSERT()?

rtel wrote on Tuesday, November 14, 2017:

I was asking as adding configASSERT() may have found a problem, but if
it is already defined then it could well be on an assert already. How
have you defined the configASSERT() macro?

nixz wrote on Tuesday, November 14, 2017:

Yes, I have configASSERT() by default from CubeMX.
I’ve debugged xQueueSendToBack and it pass all asserts, hovewer queues is full because higher priority task does not wake to read queue filled by lower priority task…

nixz wrote on Tuesday, November 14, 2017:

/* USER CODE BEGIN 1 */   
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );} 
/* USER CODE END 1 */

But it doesn’t help if I change it to:

#define configASSERT( x ) {}

Lower priority task can’t wake higher priority task…

nixz wrote on Tuesday, November 14, 2017:

Another hint…

I’ve changed code to receive messages from:

		while( xQueueReceive(TaskAudioInputQueueHandle, &msg, portMAX_DELAY) != pdTRUE )
            ;

to:

		while( xQueueReceive(TaskAudioInputQueueHandle, &msg, 0) != pdTRUE )
			vTaskDelay(10);

after this change it seems that it doesn’t hang even with highter priority destination thread, however it causes 10ms unwanted delay :frowning:

My configuration:

#define configUSE_PREEMPTION                     1
#define configSUPPORT_STATIC_ALLOCATION          1
#define configSUPPORT_DYNAMIC_ALLOCATION         0
#define configUSE_IDLE_HOOK                      0
#define configUSE_TICK_HOOK                      0
#define configCPU_CLOCK_HZ                       ( SystemCoreClock )
#define configTICK_RATE_HZ                       ((TickType_t)1000)
#define configMAX_PRIORITIES                     ( 7 )
#define configMINIMAL_STACK_SIZE                 ((uint16_t)128)
#define configMAX_TASK_NAME_LEN                  ( 16 )
#define configUSE_16_BIT_TICKS                   0
#define configUSE_MUTEXES                        1
#define configQUEUE_REGISTRY_SIZE                8
#define configUSE_PORT_OPTIMISED_TASK_SELECTION  1
#define configUSE_CO_ROUTINES                    0
#define configMAX_CO_ROUTINE_PRIORITIES          ( 2 )
#define INCLUDE_vTaskPrioritySet            1
#define INCLUDE_uxTaskPriorityGet           1
#define INCLUDE_vTaskDelete                 1
#define INCLUDE_vTaskCleanUpResources       0
#define INCLUDE_vTaskSuspend                1
#define INCLUDE_vTaskDelayUntil             0
#define INCLUDE_vTaskDelay                  1
#define INCLUDE_xTaskGetSchedulerState      1
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) 

All ISR routines has priority od 5 (and are allowed to call “FromISR” API).

Is there a possibility to dump call stac on configASSERT()? I have printf() on UART defined.

heinbali01 wrote on Tuesday, November 14, 2017:

while( xQueueReceive(TaskAudioInputQueueHandle, &msg, portMAX_DELAY) != pdTRUE ) ;

The above is a bit illogical: when you call xQueueReceive() with portMAX_DELAY as a time-out, the function will block for ever, or until an item has been received.
and so it will always return pdTRUE.

while( xQueueReceive(TaskAudioInputQueueHandle, &msg, 0) != pdTRUE ) vTaskDelay(10);

The above loop makes more sense: a time-out of 0 ( ticks ) means: polling. The call to xQueueReceive() will poll if there is a packet, and return immediately, either success, or fail As long as there is no packet, every loop will sleep unconditionally for 10 clock-ticks.

Please also realise that when it calls vTaskDelay(10), other ( lower-priority ) tasks get a chance to become active. It will also be possible for other tasks to read from TaskAudioInputQueueHandle.

But it doesn’t help if I change it to:

> #define configASSERT( x ) {}

The introduction of configASSERT() will not directly prevent problems, at most it may reveal some bad behaviour.

nixz wrote on Tuesday, November 14, 2017:

I have added loop to the:

while( xQueueReceive(TaskAudioInputQueueHandle, &msg, portMAX_DELAY) != pdTRUE ) ;

because I was playing with various timeouts from 0 to portMAX_DELAY and only 0 works for me. In facet for portMAX_DELAY it shoud not return nothing other than PDTRUE/pdPASS.

I still have no idea why xQueueReceive(…, portMAX_DELAY) freezes and make queue overflow, especially this task has higher/realtime priority. It works only if all task has same Normal priority (which is unwanted for me).

nixz wrote on Tuesday, November 14, 2017:

I’ve changed configASSERT() to:

#define configASSERT( x ) if((x)==0) printf( "##########\nASSERT FAILED in %s, line %i\n\n", __FILE__, __LINE__ )

However it wasn’t executed and task waiting on queue have freezed and queue overflows…

heinbali01 wrote on Wednesday, November 15, 2017:

If you want, can you attach some more complete code that I can actually run?

I’d like to see :

● the three tasks functions
● the calls to Send and Receive
● the way in which you create all queues

and you can leave-out other details

int msg;
xQueueSendToBack(TaskHandle, &msg, 0);

Isn’t TaskHandle a strange name for a handle to a queue? Aren’t you mistaken here?

nixz wrote on Wednesday, November 15, 2017:

Sure, some code is created by STM32 CubeMX:

Tasks:

osThreadId TaskMainHandle;
uint32_t TaskMainBuffer[ 2048 ];
osStaticThreadDef_t TaskMainControlBlock;
osThreadId TaskAudioInputHandle;
uint32_t TaskAudioInputBuffer[ 1024 ];
osStaticThreadDef_t TaskAudioInputControlBlock;
osThreadId TaskAudioOutputHandle;
uint32_t TaskAudioOutputBuffer[ 1024 ];
osStaticThreadDef_t TaskAudioOutputControlBlock;
...
 osThreadStaticDef(TaskMain, StartTaskMain, osPriorityNormal, 0, 2048, TaskMainBuffer, &TaskMainControlBlock);
  TaskMainHandle = osThreadCreate(osThread(TaskMain), NULL);

osThreadStaticDef(TaskAudioInput, StartTaskAudioInput, osPriorityNormal, 0, 1024, TaskAudioInputBuffer, &TaskAudioInputControlBlock);
  TaskAudioInputHandle = osThreadCreate(osThread(TaskAudioInput), NULL);

osThreadStaticDef(TaskAudioOutput, StartTaskAudioOutput, osPriorityNormal, 0, 1024, TaskAudioOutputBuffer, &TaskAudioOutputControlBlock);
  TaskAudioOutputHandle = osThreadCreate(osThread(TaskAudioOutput), NULL);

Queues:

osMessageQId CmdTxRxQueueHandle;
uint8_t CmdTxRxQueueBuffer[32 * sizeof(struct msg_t)];
osStaticMessageQDef_t CmdTxRxQueueControlBlock;

osMessageQId TaskAudioInputQueueHandle;
uint8_t TaskAudioInputQueueBuffer[16 * sizeof(uint32_t)];
osStaticMessageQDef_t TaskAudioInputQueueControlBlock;

osMessageQId TaskAudioOutputQueueHandle;
uint8_t TaskAudioOutputQueueBuffer[16 * sizeof(uint32_t)];
osStaticMessageQDef_t TaskAudioOutputQueueControlBlock;

	osMessageQStaticDef(CmdTxRxQueue, 32, msg_t, CmdTxRxQueueBuffer, &CmdTxRxQueueControlBlock);
	CmdTxRxQueueHandle = osMessageCreate(osMessageQ(CmdTxRxQueue), NULL);

	osMessageQStaticDef(TaskAudioInputQueue, 16, uint32_t, TaskAudioInputQueueBuffer, &TaskAudioInputQueueControlBlock);
	TaskAudioInputQueueHandle = osMessageCreate(osMessageQ(TaskAudioInputQueue), NULL);

	osMessageQStaticDef(TaskAudioOutputQueue, 16, uint32_t, TaskAudioOutputQueueBuffer, &TaskAudioOutputQueueControlBlock);
	TaskAudioOutputQueueHandle = osMessageCreate(osMessageQ(TaskAudioOutputQueue), NULL);

Task structure (~same for all three tasks):

	for (;;)
	{
		while( xQueueReceive(CmdTxRxQueueHandle, &msg, portMAX_DELAY) != pdTRUE )
			;

		switch(msg.id)
		{
		case MNone:
		{
			break;
		}
	...
	}

Send functions (all three looks the same):

BaseType_t SendToMainTask(msg_t msg, bool from_isr)
{
	if (!from_isr)
		return xQueueSendToBack(CmdTxRxQueueHandle, &msg, 0);

	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	return xQueueSendToBackFromISR(CmdTxRxQueueHandle, &msg, &xHigherPriorityTaskWoken);
}

It works if all three tasks have Normal priority, if I change priority of TaskB AboveNormal it would freeze xQueueReceive(CmdTxRxQueueHandle, &msg, portMAX_DELAY) and makes queue overflow. Which is visible from TaskA which is still running and responding…

heinbali01 wrote on Wednesday, November 15, 2017:

BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    return xQueueSendToBackFromISR(CmdTxRxQueueHandle, &msg, &xHigherPriorityTaskWoken);

The above code is called if from_isr = 1, that is good.

But what I miss is a yield, By default the ISR will return without switching, i.e. to the task ( or interrupt ) that was active.

Could you this :

BaseType_t SendToMainTask(msg_t msg, bool from_isr)
{
BaseType_t xResult;
    if (!from_isr)
	{
        xResult = xQueueSendToBack(CmdTxRxQueueHandle, &msg, 0);
	}
	else
	{
		BaseType_t xHigherPriorityTaskWoken = pdFALSE;
		xResult = xQueueSendToBackFromISR(CmdTxRxQueueHandle, &msg, &xHigherPriorityTaskWoken);
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
	}
	return xResult;
}

heinbali01 wrote on Wednesday, November 15, 2017:

Task structure (~same for all three tasks):

    for (;;)
    {
        while( xQueueReceive(CmdTxRxQueueHandle, &msg, portMAX_DELAY) != pdTRUE )
            ;

Just another question: do the three tasks all wait for the same queue name CmdTxRxQueueHandle ?

nixz wrote on Wednesday, November 15, 2017:

No, all three tasks has three separate queues:

osMessageQId CmdTxRxQueueHandle;
osMessageQId TaskAudioInputQueueHandle;
osMessageQId TaskAudioOutputQueueHandle;

I’ve attached definitions before (see above).

heinbali01 wrote on Wednesday, November 15, 2017:

And what is the effect of calling portYIELD_FROM_ISR() in case SendToMainTask() is called from an interrupt?

nixz wrote on Wednesday, November 15, 2017:

Thank you for the idea to check. I will check it when I will get access to the code again. However task B and C are feeded also from main loop od task A not only from ISR. Those “non ISR” messages also do not wake taks B and C. Do yoy think I shall try adding portYIELD() to the non ISR portion of this function?

BaseType_t SendToMainTask(msg_t msg, bool from_isr)
{
BaseType_t xResult;
    if (!from_isr)
    {
        xResult = xQueueSendToBack(CmdTxRxQueueHandle, &msg, 0);
      **portYIELD();**
    }
    else
    {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        xResult = xQueueSendToBackFromISR(CmdTxRxQueueHandle, &msg, &xHigherPriorityTaskWoken);
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
    return xResult;
}

BTW: I have preemption enabled so I believe FreeRTOS shall switch task as soon as new item is send to the queue…

heinbali01 wrote on Wednesday, November 15, 2017:

BTW: I have preemption enabled so I believe FreeRTOS shall
switch task as soon as new item is send to the queue…

I think that is correct.

        xResult = xQueueSendToBack(CmdTxRxQueueHandle, &msg, 0);
      **portYIELD();**

and so there is no need to call portYIELD() explicitly.

In case of an interrupt, a yield must be scheduled explicitly.

nixz wrote on Wednesday, November 15, 2017:

But when I disable all messaged sent from ISRs and leave only those sent from TaskA (Normal) main loop, TaskB also hangs on reading item from queue so thats the idea behing adding “portYIELD()” from non ISR calls.