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 & USARTSR_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.