We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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