Ready task doesn't get scheduled

tlw wrote on Friday, May 24, 2019:

Hi there,

I am using FreeRTOS 10.2.0 on an stm32f103c8 (ARM Cortex-M3). I have an USART1 interrupt set up and push all the received bytes into a circular buffer. From the main task I’m constantly polling the buffer’s size and read any bytes that are available. This works like a charm.

However, the polling approach was just for initial testing. The communication task should be suspended, when it tries to read a byte from the buffer, but the buffer is empty. The IRQ should notify the task to continue execution everytime it received a new byte. So basically a top/bottom half processing approach, where the IRQ just receives and notifies a processing task. This is the code I’ve implemented:

IRQ Handler:

extern "C" void USART1_IRQHandler(void)
{
	/* Check the reason for the interrupt. At the moment
	we don't care about other interrupt sources than the
	receive buffer full interrupt. */
	if((USART1->SR & USART_SR_RXNE) == 0)
		return;


	/* Read the received byte from the USART data register
	and push it into the circular buffer. The buffer will
	prevent data overwrite. */
	uint8_t rxData = USART1->DR & 0x00FF;
	ringbuffer_push(rxBuffer, rxData);


	/* Now notify the handling task, that a new byte was 
	put into the buffer and can be processed. */
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	vTaskNotifyGiveFromISR(driverTaskHandle, &xHigherPriorityTaskWoken);
	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

Communication task:

/* Check to see if there is data in the buffer. If so,
	we can immediately read from the buffer and do not have
	to wait for the interrupt to fire. In this case we also
	need to reset the notify flag from the IRQ. */
	if(!ringbuffer_isEmpty(rxBuffer))
	{
		/* Reset the notify flag. We do read the buffer's
		content and if the flag is not reset, we will be
		able to read the buffer, if there is nothing
		inside (because the flag is still set. We don't block
        but just poll the notify value to clear it in any case. */
		ulTaskNotifyTake(pdTRUE, 0);
		return ringbuffer_read(rxBuffer);
	}

	/* No data is in the buffer, so we have to wait for data
	to become available. Thus we will block until we get no-
	tified from the isr that new data is available. */
	ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

	/* Once we reach this point, we were notified by the isr
	about new data being available. We can now read the buffer
	and return the data. */
	return ringbuffer_read(rxBuffer);

The problem is, that after some random time (really anything between a few minutes up to 2 hours) the interrupt fires and the IRQ executes, but the communication task is not woken up. Further checking with the FreeRTOS task view (I’m using Attolic TrueStudio) revealed, that the communication task is in the ready state, so naturally vTaskNotifyGiveFromISR does not set xHigherPriorityTaskWoken to true. BUT, although the communication task has the highest priority of 3 (one idle task with prio 0 and one ui task with priority 2), I can see the idle task being executed instead of the high priority communication task.

Is there anything that I’m missing? I also tried semaphores instead of direct task notification, but the result is the same.

rtel wrote on Friday, May 24, 2019:

If I understand correctly the communications task is not woken up
because it is already in the ready state. If that is the case, then
what is the communications task doing? By which I mean, which code is
it executing?

You may consider using a Stream Buffer to do the same thing (which
internally uses a task notification)
https://www.freertos.org/RTOS-stream-buffer-example.html

tlw wrote on Friday, May 24, 2019:

It is in the ready state, but not in the running state. Can I somehow check the instruction at which the task was suspended? I’ve already tried a static stream buffer, but had no success.

rtel wrote on Friday, May 24, 2019:

Well it is possible by finding the task’s task control block (which is
basically its handle), form which you can find its stack, from which you
can find its program counter - but it is much easier if you use a thread
aware plug in such as the one shipped with IAR, Segger or Code Confidence.

tlw wrote on Saturday, May 25, 2019:

Alright, it seems the problem is gone. I’ve successfully run the system for about 10 hours now. Maybe I’ve run out of stack (the NXP plugin showed a about 80% stack usage) and with stack overflow detection I guess the task wasn’t scheduled? However, the stack overflow hook did not execute.