Hi all,
I am using the CMSIS Driver USART driver in Keil uVision with the STM32F746 discovery board and have a weird bug in the usart callback.
I'm kind of following the example from - https://www.keil.com/pack/doc/CMSIS/Driver/html/group__usart__interface__gr.html (but updated for cmsis_os2.h)
When I do usart_driver->Receive(&cmd, 1); and hit enter in my terminal window, it then just skips through the remaining osEventFlagsWait() commands, repeatedly printing "Hello World!" to my terminal window. However if I add a loop of spinning CPU cycles to introduce a short delay before sending the osEventFlag it behaves as expected (that is it waits on the osEventFlagsWait(usart_flag, 0x01, osFlagsWaitAny, osWaitForever); line until I hit enter again). It also works as expected if I run the code line by line in the debugger (probably because stepping through the code introduces it's own delay).
The issue is (at least I think!) with the osEventFlagsWait(usart_flag, 0x01, osFlagsWaitAny, osWaitForever);. I was expecting the event flag to clear immediately after osEventFlagsWait returns, but there seems to be a delay in clearing the flag.
This means if you do:
usart_driver->Send("some message\n", 14); osEventFlagsWait(usart_flag, 0x01, osFlagsWaitAny, osWaitForever); usart_driver->Send("some other message\n", 20); osEventFlagsWait(usart_flag, 0x01, osFlagsWaitAny, osWaitForever);
where the uart callback sets the event flag when it is triggered with ARM_USART_EVENT_SEND_COMPLETE or ARM_USART_EVENT_TX_COMPLETE - e.g.
// if our usart send / transmit was a success uint32_t send_mask = ARM_USART_EVENT_SEND_COMPLETE | ARM_USART_EVENT_TX_COMPLETE ; if(event & send_mask) { osEventFlagsSet(usart_flag, 0x01); }
it just skips through the second osEventFlagsWait (as - as far as i can see - it still thinks the flag is set).
If I stick an osDelay(25); between the two calls to usart_driver->Send() it then works.
My question now is - is this the desired behaviour? Is there a bug in osEventFlagsWait() or should I just not rely on the flags being cleared immediately after osEventFlagsWait() returns? Or am I using the event flags wrong?
Regards,
Alex
p.s. This is also cross posted to https://github.com/ARM-software/CMSIS_5/issues/1027 and I have a minimal working example at https://gist.github.com/al3xsh/3de259f2bf6802d5112fd1111a6d8ec1
Hi Alex,
I believe that the problem might actually be in the handling of events in my_usart_callback. Flag osEventFlagsSet(usart_flag, 0x01) is set when ever one of following events is triggered: ARM_USART_EVENT_RECEIVE_COMPLETE or ARM_USART_EVENT_TRANSFER_COMPLETE or ARM_USART_EVENT_SEND_COMPLETE or ARM_USART_EVENT_TX_COMPLETE. Note that USART->Send can trigger two events: ARM_USART_EVENT_SEND_COMPLETE and also ARM_USART_EVENT_TX_COMPLETE (when the data is actually shifted out on the lines).
This might be happening:
// print a status message usart_driver->Send("we are alive ...\r\n", 19);
ARM_USART_EVENT_SEND_COMPLETE happened and Flag osEventFlagsSet(usart_flag, 0x01) is set.
// wait for the usart_flag event flag (i.e. we have been successful) osEventFlagsWait(usart_flag, 0x01, osFlagsWaitAny, osWaitForever);
Somewhere in between...
while(1) { // weirdly, if you don't reset the cmd character to zero the usart_driver // doesn't overwrite it - it just seems to breeze through the // "usart_driver->Receive()" operation and the osEventFlagsWait char cmd; // = 0; usart_driver->Receive(&cmd, 1);
ARM_USART_EVENT_TX_COMPLETE happened, which was caused by previous send.
osEventFlagsWait(usart_flag, 0x01, osFlagsWaitAny, osWaitForever);
osEventFlagsWait(usart_flag, 0x01, osFlagsWaitAny, osWaitForever) returns immediately because usart_flag is already set by ARM_USART_EVENT_TX_COMPLETE and the actual receive is not completed.Mentioned problem could be solved, by not OR-ing the ARM_USART_EVENT_TX_COMPLETE into the success_mask variable.I hope this helps,David
Hi David,
Many thanks for your reply! That did indeed solve it!
Am I correct in thinking that the difference between ARM_USART_EVENT_TX_COMPLETE and ARM_USART_EVENT_SEND_COMPLETE is that ARM_USART_EVENT_SEND_COMPLETE returns even when there might be data in the USART buffer still to send, whereas ARM_USART_EVENT_TX_COMPLETE is when the transmission is completely done (i.e. no data in the transmit buffers)?
Thanks for your help!
Hi Alex,ARM_USART_EVENT_SEND_COMPLETE event indicates that all the tx data has been processed by the driver and the user can reuse tx buffer and call USART_Send() again. This not necessary mean that all the data is already physically transferred, It might be just queued or copied in drivers local buffer.ARM_USART_EVENT_TX_COMPLETE event is optional and it can be implemented when the usart peripheral support this functionality. It indicates that all tx data was physically transferred (gone out on pin/wire). This event is useful, for example, when disabling the USART peripheral or changing the alternate function of USART_TX pin, where waiting for ARM_USART_EVENT_TX_COMPLETE event prevents unwanted interruption of the transfer.
Please take a look here for details:https://www.keil.com/pack/doc/CMSIS/Driver/html/group__usart__interface__gr.html#gad796cd023f8f6300a6caadcc39d43cbfRegards,David