xSemaphoreTake and peripheral IRQs

jon-gordon wrote on Monday, October 17, 2016:

I have a driver that awaits a certain number of bytes to be received from the UART.
This driver “waits” by either a) taking a binary semaphore or b) sitting in a while loop. In either case, a timeout is also present.

Each RX decrements the count awaited until all are received. When all are received, it lets the task know by either a) giving a binary semaphore or b) clearing the flag that’s keeping the while loop spinning.

Scenario b) works perfectly fine. From point of “wait” in the read driver, I see an IRQ every 1.2ms (i.e. one character @ 9600) all the way until all bytes are received and the task is notified. Overall time for 12 characters: ~18ms.

Scenario a) which should work in the exact same manner except for allowing other system tasks to run, does not work. From the point of the “wait” in the driver, I see nothing at all on the ISR until 90ms later when one corrupted character has been received. The semaphore take eventually times out.

This is very odd behaviour and I am struggling to understand it.
How does the taking of a semaphore stop the IRQ from firing?
Why is there no overrun detected (this is an STM32F2, by the way)? That would suggest the peripheral is off?
If I use DMA instead of IRQs, I get the same problem, only one character received, suggesting the problem is not related to ISR/IRQ behaviour either.
Any call into the FreeRTOS API (vTaskDelay, YIELD, etc) causes the peripheral to not acknowledge any data recived except for the one corrupt byte. By spinning hard in the task, it always executes perfectly.

We are using FreeRTOS version 8.1.2.
I am thinking of moving to at least 8.2.0 and using the new Direct to Task Notifications - do you think this would help?
Any idea what could be going wrong with this very simple use of a binary semaphore?


rtel wrote on Monday, October 17, 2016:

You are doing something that is very common - so it should work with no problem. I’m afraid without seeing the code I could not really say why it is not working.

I would recommend updateding to version 9.0.0 - it won’t resolve your issue, as I think there is something fundementally wrong, but the additional configASSERT() statements in the newer code versions might enable you to identify what that issue is.

Once you are using a newer version ensure configASSERT() is defined, and stack overflow prtection is turned on and set to 2.

My best guess at this point would be that the interrupt priority is set incorrectly.

jon-gordon wrote on Tuesday, October 18, 2016:

Yes, I agree it should work without problem!
I’ve read through on the link to interrupt priorities and I know that not to be the cause. Most especially because, as I mentioned originally, the DMA does not work either and that does not depend on interrupts.
Either a hard while loop or timer-based delay works perfectly fine in all cases - obtaining a semaphore does not.

I will upgrade to v9.0.0 and see if any improvement is found.

jon-gordon wrote on Tuesday, October 18, 2016:

V9.0.0 didn’t make any difference, unfortunately. However, we did root out the problem.
The use of a semaphore allowed the system to go into Idle. With use of the idle task hook, we call a sleep routine if nothing else is to be done. The sleep routine was powering off the peripheral, hence the lack of any data.

Thank you for your help anyway and at least I’ve learned a bit more about FreeRTOS!

rtel wrote on Tuesday, October 18, 2016:

Great you were able to get you system working - and thanks for reporting
back so other readers of this thread can see the conclusion.