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?