call portEND_SWITCHING_ISR when previous portEND_SWITCHING_ISR is still running

keesdeboer wrote on Monday, August 20, 2018:

Hello,

I’ve been stuck on a problem and I am a little bit clueless.
I’m using a PIC32MX, FREERTOS version 9.0, MPlabX IDE v 5.00 and the XC32 compiler version 1.44.

I’ve got a system with two interrupts, all implemented the RTOS style. RTOS wrapper, and very short. At the end of each interrupt, I preform the function portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );

The two interrupt sources are one UART serial input and a pulse detect (I’m using a CCP input for that). Both interrupts gives a semaphore (of course with the FromISR after the function names). Two separate tasks takes the semaphore, read the byte from the UART or the pulse will be counted. The UART is continuously communicating with a speed of 9600bps and the pulses have a frequency of 4000 Hz. The Tickrate of the system is 1000 Hz. The UART interrupt has priority 3, the Pulse interrupt has priority 2. The configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 7.

But after a while something annoying happens. The DelayedTaskList becomes empty, resulting in one active running task: the Idle task. Every other task comes in the ready state but the tasks won’t become active. The PIC32 is still running because interrupts keep firing. But the application itself runs only on FREERTOS so the application itself isn’t running. When not applying the pulses OR the UART bytes, this problem won’t occur.
To see something more, I’m using Percepio to view what’s happening. This problem only occurs when both interrupts fired at nearly the same time. The UART is first, giving a semaphore. But before the semaphore could be taken by the corresponding task, the pulse interrupt fires, also giving a semaphore. Both interrupt functions are very short, emptying a buffer, giving a semaphore (FromISR) and both end with the function portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );.

If I not end the interrupt function with the portEND_SWITCHING_ISR( xHigherPriorityTaskWoken ), everything goes well and the system keeps running without problems.

Long story so far, but here is the real question: What happens if the portEND_SWITCHING_ISR( xHigherPriorityTaskWoken ) function is running, preforming a taskYield and at that moment, an another Interrupt fires and also performs a taskYield. I think this is the reason my FREERTOS stops running active tasks, resulting in an empty DelayedTaskList. But I’m not the FREERTOS designer, so I could be wrong. But if I’m right, what can I do about it. Just never let the scheduled Yield after a interrupt and let the Idle task preform the yield (configIDLE_SHOULD_YIELD = 1)?

Thanks in advance,
Kees

rtel wrote on Monday, August 20, 2018:

I’ve been stuck on a problem and I am a little bit clueless.

I wouldn’t say that - sounds like you have done some excellent debugging
here.

is 1000 Hz. The UART interrupt has priority 3, the Pulse interrupt has
priority 2. The configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 7.

Not really relevant to your question, but I’m curious, why have the UART
interrupt priority above the pulse interrupt priority as the pulse is
much faster than the UART.

Now to the question: The portEND_SWITCHING_ISR() macro pends a software
interrupt that will execute when all higher priority interrupts have
completed. It does that by performing a read-modify-write on the CAUSE
register - so the question in my mind (without the datasheet in front of
me) is…could anything else have got set in the CAUSE register between
the read and write portions of that operation. Also, can the bit in the
CAUSE register get set with a simple bit set operation (don’t think so,
as it is not a general purpose register). I will have to look up the
answers to these and report back.

rtel wrote on Tuesday, August 21, 2018:

Having looked at the cauase register I think the portYIELD() code is ok as most fields in the CAUSE register are read only, and the bits that start/stop the clock or change whether interrupts go through the vectoring thing, etc. are not going to change at run time.

keesdeboer wrote on Tuesday, September 11, 2018:

Hello,

Thanks for your reaction, Richard.

It took me a while, but I finally solved the problem :-).

The problem was resetting the interrupt flags. I did it like this:

IFS0bits.IC2IF = 0;

but it should be like this:

IFS0CLR = _IFS0_IC2IF_MASK;

With the first method, when a new interrupt comes in, and the hardware doesn’t realy reset this interrupt flag yet, the FreeRTOS hangs when applying a context swith.
With the second (correct) method, the interrupt is really resetted when applying a context switch. So there is no problem at all.

btw, the pulse interrupt has a lower priority because in the real world, the pulserate is much lower, but the problem occured once in a day. To have this problem every 1-3 minutes, I increased the pulserate.