non-preemptive multi-tasking

gugl wrote on Monday, January 18, 2010:

Hello everybody

My program uses 6 tasks (all of them have idle priority) and an UART iterrupt service routine. FreeRTOS is configured non-preemptive.

1)
How does FreeRTOS implement non-preemptive multi-tasking?
It seems that FreeRTOS doesn’t always continue with the interrupted task after the ISR routine has finished. Seems that there is a task schedule and another ready task continues execution before. Is this how FreeRTOS does non-preemptive multi-tasking? This would imply that I have to lock shared resources even in non-preemptive mode?

2)
My ISR uses  “xSemaphoreGiveFromISR”. Interestingly this function always returns that a higher priority task was woken although all of my tasks are created with idle priority. I don’t request a context switch in order to continue with the actually interrupted task. Does this has any effect on the non-preemptive scheduling behaviour?

Thanks
Andreas

davedoors wrote on Monday, January 18, 2010:

The last parameter to xSemaphoreGiveFromISR() will return true if the woken task has priority *equal to* or higher than the executing task.

In co-operative mode the tick interrupt will not select a new task to run. Whether or not your UART interrupt does is up to you. If you call portEND_SWITCHING_ISR or taskYIELD or portYIELD_FROM_ISR or whatever the port you are using implements then a switch will occur. If you don’t want that to happen then simply don’t call the switch macro. In most cases if you don’t want the interrupt to cause a task switch you can write the interrupt in the normal way, as the compiler manual and examples tell you to, without any special assembly code or macros at all.

gugl wrote on Monday, January 18, 2010:

Thank you for the quick response.

My ISR doesn’t request a context switch.

Code:

extern void UART1IntHandler( void )
/*------------------------------------------------*/
{
    unsigned long ulStatus = UARTIntStatus( UART1_BASE, true );
    UARTIntClear( UART1_BASE, ulStatus );
    while ( UARTCharsAvail( UART1_BASE ) )
    {
        RingBufWriteOne( buf, UARTCharGetNonBlocking( UART1_BASE ) );
    }
    portBASE_TYPE xHigherPriorityTaskWoken;
    xSemaphoreGiveFromISR( _ctx_.dataAvailable, &xHigherPriorityTaskWoken );
}

Or does the xSemaphoreGiveFromISR() itself request a context switch?

rtel wrote on Monday, January 18, 2010:

Things would be so much easier if people would say which port they were using…

In any case, xHigherPriorityTaskWoken should be initialised to pdFALSE/0.

Regards.

gugl wrote on Monday, January 18, 2010:

Sorry.

I’m using FreeRTOS V5.0.3 for Luminary LM3S8962.

Regards
Andreas

rtel wrote on Monday, January 18, 2010:

1)
How does FreeRTOS implement non-preemptive multi-tasking?
It seems that FreeRTOS doesn’t always continue with the interrupted task after the ISR routine has finished. Seems that there is a task schedule and another ready task continues execution before. Is this how FreeRTOS does non-preemptive multi-tasking? This would imply that I have to lock shared resources even in non-preemptive mode?

You use of xSemaphoreGiveFromISR() will allow the UART to unblock tasks, but because you are not calling portEND_SWITCHING_ISR() a switch to the unblocked task will not be performed.  At least should not be performed, although it sounds like you are experiencing something different.  How are you determining that a different task is being returned to?

2)
My ISR uses “xSemaphoreGiveFromISR”. Interestingly this function always returns that a higher priority task was woken although all of my tasks are created with idle priority. I don’t request a context switch in order to continue with the actually interrupted task. Does this has any effect on the non-preemptive scheduling behaviour?

I suspect that is because the variable is not being initialised.  It should be initialised to pdFALSE before it is used.

Regards.

gugl wrote on Monday, January 18, 2010:

1)
I’ve implemented a central message module. Via a public API each task is able to create formatted messages and store them in a message container. Formatting messages is done via some kind of “sprintf” using a static character buffer. As I supposed that there will be no unintentional context switches this non-reentrant construction should work properly. The message module itself doesn’t use any FreeRTOS functionality. Via serial communication I can pick up these messages one by one.

I observe two different problems:
- Some of the messages are corrupted as if the format buffer would be used concurrently by two different tasks.
- Sometimes the message sequence is invalid. I used a message sequence counter to determine this problem.

These problems occur whenever I produce UART traffic. If the UART ISR isn’t called the message module works properly.
For testing purposes I’ve locked the message API using a FreeRTOS mutex to get rid of this problem.
But I would prefer to avoid this synchronisation or at least understand why my original implementation doesn’t work in FreeRTOS non-preemptive mode.

2)
Doesn’t make any difference whether or not I initialize the higherPriorityTaskWoken variable before use in “xSemaphoreGiveFromISR”. But that doesn’t matter a I really don’t want a context switch when leaving the ISR.

Regards
Andreas

edwards3 wrote on Monday, January 18, 2010:

Do you have stack checking switched on? sprintf() can use a whole lot of stack, depending on which implementation you are using. Stack usage will go up when the UART is generating interrupts too.

gugl wrote on Monday, January 18, 2010:

Definitely no stack problem.

tgarner wrote on Monday, January 18, 2010:

Where do you observe the corruption ? Uart output ?
If your UART Tx is interrupt driven, you could possibly be calling transmit before the
last one completes

gugl wrote on Tuesday, January 19, 2010:

I use “UARTCharPut” to send serial data byte by byte. That isn’t interrupt driven.
As I wrote before: If I use a mutex to lock access to the message API, everything works properly.