Issue with QueueSet

temazzz wrote on Monday, April 14, 2014:

Hello!

I have issue with Queue Set.
I use FreeRTOS 8.0.0, IAR 6.40, STM32F103RD

I have a task which is blocked by semaphore take.
This semaphore is given in ISRs. After semaphore is given
my task will run. It works ok.
But I also want to synchronize my task with queue to receive messages from another task.
To do it I create Queue Set which includes semaphore described above and queue.
But sometimes my task is blocked forever…
I tried to remove queue for messages from my QueueSet but I have the same behavior.
When my task is blocked forever uxMessagesWaiting in my semaphore is equal to 1 and uxMessagesWaiting for my QueueSet
is equal to 1 too. But task doesn’t transit in active state…

My code is similar with the following:

Status_t task_init(void)
{
mSignals = 0;

    xQueueSet = xQueueCreateSet( SET_LENGTH );
    if(xQueueSet == NULL)
    {
      return STAT_ERROR;
    }
    
    mSignalsSemaphore = xSemaphoreCreateBinary();

    if(mSignalsSemaphore == NULL)
      return STAT_ERROR;
    

    if(xQueueAddToSet(mSignalsSemaphore, xQueueSet) != pdPASS)
      return STAT_ERROR;

    
    xSemaphoreGive(mSignalsSemaphore);
    
if(xTaskCreate(Task, "Task", configTASK_STACK_SIZE, NULL,                     
                   configTASK_PRIORITY, NULL)!= pdPASS)
    {
      return STAT_ERROR;
    }

    return STAT_OK;	

}

void bttask_setSignalFromISR(bt_uint signal, signed portBASE_TYPE* higherPriorityTaskWoken)
{
unsigned portBASE_TYPE savedInterruptStatus;

savedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
mSignals |= signal;
portCLEAR_INTERRUPT_MASK_FROM_ISR(savedInterruptStatus);

xSemaphoreGiveFromISR(mSignalsSemaphore, higherPriorityTaskWoken);

}

static void Task(void* params)
{
bt_uint signals;
QueueSetMemberHandle_t xActivatedMember;

for (;;)
{

            xActivatedMember = xQueueSelectFromSet( xQueueSet, portMAX_DELAY );
            if(xActivatedMember == mSignalsSemaphore)
            {
		xSemaphoreTake(mSignalsSemaphore, 0);

		taskENTER_CRITICAL();
		signals = mSignals;
		mSignals = 0;
		taskEXIT_CRITICAL();
	

		if (signals & BTTASK_SIG_RX)
		{
			bttask_pal_handleRxSignal();
		}
	
		if (signals & BTTASK_SIG_TX)
		{
			bttask_pal_handleTxSignal();
		}

		if (signals & BTTASK_SIG_TIMER)
		{
			bttask_pal_handleTimerSignal();
		}
	
           	}
           	else
            {
            }
}

}

Best regards,
Artem Z

davedoors wrote on Monday, April 14, 2014:

Have you got configASSERT defined? In v8 that will catch many interrupt priority setting problems on STM32s. Does it help?

temazzz wrote on Monday, April 14, 2014:

Thank you for your response.

I turn on configASSERT and find 1 error in task priority. But after fix it the behavior of my system is the same, it did not help me…

rtel wrote on Monday, April 14, 2014:

I cannot see anything obviously wrong with your code, assuming the interrupt priorities are set correctly, and somewhere you are calling NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); (because you are using an STM32, no other Cortex-M parts need that).

Does the problem occur after it has operated correctly for a while, or does the problem occur immediately? Or to put it another way, are you able to receive on the queue set a few times before you get into this situation, or does it happen the first time you try to receive on the queue set?

In your code you create the semaphore, add the semaphore to the set, give the semaphore, then start the task - that means the semaphore is already available and the queue set should have an item in it before you try and use it - I’m wonder if that could be a problem, but to be honest I don’t think it would be.

What is SET_LENGTH set to?

Regards.

temazzz wrote on Tuesday, April 15, 2014:

Hi,

I am calling NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ) in my main() procedure.

I call xSemaphoreGive(), because originally code didn’t have QueueSet.
It had the only semaphore created by vSemaphoreCreateBinary(mSignalsSemaphore).
Now I use QueueSet so I must create semaphore using xSemaphoreCreateBinary.
Not calling xSemaphoreGive() has no any effect.

This problem does not occur immediately. Task is blocked forever after
several dozen successfully executions. When I calling something like
xQueueSelectFromSet( xQueueSet, 100 ) instead of xQueueSelectFromSet( xQueueSet, portMAX_DELAY )
it works ok. If I use single semaphore instead of QueueSet including the only semaphore
it works ok too. But I if I use QueueSet consists of 1 semaphore, starting from some
moment my task can not be unblocked, despite of semaphore is given and QueueSet has the message…

In case of my QueueSet includes only 1 semaphore, SET_LENGTH is set to 1.

Try to tell more about my code.

My task is a part of Bluetooth stack. And don’t have access to all sources.
This task handles different events. Stack sends these events by semaphore giving.
3 events are send from interrupt handlers: the first from uart_tx_dma handler,
the second from from uart_rx_dma_handler, the third from tick hook.
And last event is send from function called by task.

configKERNEL_INTERRUPT_PRIORITY = 255
configMAX_SYSCALL_INTERRUPT_PRIORITY = 0x5F

DMA interrupt priorities are set to 5 (eq to configMAX_SYSCALL_INTERRUPT_PRIORITY)

Status_t task_init(void)
{      
    mSignals = 0;

    xQueueSet = xQueueCreateSet( SET_LENGTH );
    if(xQueueSet == NULL)
    {
        return STAT_ERROR;
    }
    
    mSignalsSemaphore = xSemaphoreCreateBinary();

    if(mSignalsSemaphore == NULL)
        return STAT_ERROR;
    
    if(xQueueAddToSet(mSignalsSemaphore, xQueueSet) != pdPASS)
        return STAT_ERROR;

    if(xTaskCreate(Task, "Task", configTASK_STACK_SIZE, NULL,                     
                   configTASK_PRIORITY, NULL)!= pdPASS)
    {
        return STAT_ERROR;
    }

    return STAT_OK;	
}


void bt_oem_schedule_signals(void)
{
    bttask_setSignal(BTTASK_SIG_BTSIGNAL);
}


void bttask_setSignal(bt_uint signal)
{
    taskENTER_CRITICAL();
    mSignals |= signal;
    taskEXIT_CRITICAL();

    xSemaphoreGive(mSignalsSemaphore);
}


void bttask_setSignalFromISR(bt_uint signal, signed portBASE_TYPE*    
                                higherPriorityTaskWoken)
{
    unsigned portBASE_TYPE savedInterruptStatus;

    savedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
    mSignals |= signal;
    portCLEAR_INTERRUPT_MASK_FROM_ISR(savedInterruptStatus);

    xSemaphoreGiveFromISR(mSignalsSemaphore, higherPriorityTaskWoken);
}


void bttask_setSignalFromTickHook(bt_uint signal)
{
	signed portBASE_TYPE higherPriorityTaskWoken;

    unsigned portBASE_TYPE savedInterruptStatus;

	savedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
	mSignals |= signal;
	portCLEAR_INTERRUPT_MASK_FROM_ISR(savedInterruptStatus);

	xSemaphoreGiveFromISR(mSignalsSemaphore, &higherPriorityTaskWoken);
}




void BT_UART_DMA_RX_Channel_IRQHandler(void)
{
	signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE;

	/*
    .........
    */

	bttask_setSignalFromISR(BTTASK_SIG_RX, &higherPriorityTaskWoken);

	portEND_SWITCHING_ISR(higherPriorityTaskWoken);
}

void BT_UART_DMA_TX_Channel_IRQHandler(void)
{
	signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE;

	/*
    .........
    */

	bttask_setSignalFromISR(BTTASK_SIG_TX, &higherPriorityTaskWoken);

	portEND_SWITCHING_ISR(higherPriorityTaskWoken);
}




static void Task(void* params)
{
    bt_uint                signals;
    QueueSetMemberHandle_t xActivatedMember;
    
    for (;;)
	{

            xActivatedMember = xQueueSelectFromSet( xQueueSet, portMAX_DELAY );
            if(xActivatedMember == mSignalsSemaphore)
            {
                    xSemaphoreTake(mSignalsSemaphore, 0);

                    taskENTER_CRITICAL();
                    signals = mSignals;
                    mSignals = 0;
                    taskEXIT_CRITICAL();

                    if (signals & BTTASK_SIG_BTSIGNAL)
                    {
                        bt_signal_process_pending();
                    }		

                    if (signals & BTTASK_SIG_RX)
                    {
                        bttask_pal_handleRxSignal();
                    }
	
                    if (signals & BTTASK_SIG_TX)
                    {
                        bttask_pal_handleTxSignal();
                    }

                    if (signals & BTTASK_SIG_TIMER)
                    {
                        bttask_pal_handleTimerSignal();
                    }
	
            }
            else
            {
            }
	}
}

rtel wrote on Tuesday, April 15, 2014:

First, I’m not 100% sure you need a queue set as you could send all messages down a single queue (any task or interrupt can write to the same queue), and then you can just encode the message origin and value in the message.

To answer more directly, I cannot see a problem, but would like to suggest you increase the value of SET_LENGTH. Try a value of 10 to be extremely over the top just for test purposes. It should only make a difference if the semaphore is given more often than you are able to receive it in your task.

Regards.

temazzz wrote on Tuesday, April 15, 2014:

Thank you for your response,

I decided to use QueueSet because I want my task be blocked not only by semaphore, but also by input and output queues to communicate with other task.
Task must be blocked on xQueueReceive from input queue and on xQueueSend to output queue.

I can use bt task mSignal to send event indicating that message is in queue and task can read it. But I want mSignal would be used only by bluetooth task and not to set this signal from other task…
QueueSet seems convenient for my purposes.

I will try to mail stack developer.

Best regards,
Artem Z

temazzz wrote on Tuesday, April 15, 2014:

I tried SET_LENGTH = 10, it does not matter

jmsmith86 wrote on Saturday, April 25, 2015:

I am having this same issue. What I am doing is very similar too. I am using version 8.1.2. I see that the latest version of FreeRTOS (8.2.1) contains a fix for “a potential issue related to the use of queue sets from an ISR”. I wonder if this is related?

jmsmith86 wrote on Sunday, April 26, 2015:

I upgraded FreeRTOS in my project to version 8.2.1 and then ran my 3-hour unit test that would previously cause the queue set to hang (usually within the first hour). It passed this time! It seems like this issue has been fixed.