2017-08-09 08:42 AM
Hello everyone,
I am having some trouble understanding the behaviour of the HAL_UART_Transmit_IT and HAL_UART_Receive_IT routines. I am using two NUCLEO-F767ZI boards that communicate via UART1 in a request/reply fashion - the 'client' sends a one-byte command and the 'server' immediately replies with the associated message. Both boards use a state machine which is programmed to ensure that at all times only one Receive_IT or Transmit_IT can be running. All the communication is carried out in interrupt mode. I have working IRQ handlers and Tx/Rx Completed Callbacks on both.
As I am running through a series of requests and replies, repeated every 10 ms by the client, the client board always starts to hang after a couple of cycles. But what is weird is that it seems to work fine only if I omit receiving the last reply of the server in a cycle, and skip directly to the next request without calling a HAL_UART_Receive_IT on the client. But from what I can see, the TxCpltCallback on the server side is still executed, although the client never called a Receive!
So I guess my question is: What is the behaviour of HAL_UART_Transmit_IT if nobody is answering on the other side?
Is there any other way a TxCpltCallback can be triggered? Do I have to clear any flags manually if I want to do what I described?
#nucleo-f767zi #uart2017-08-09 09:58 AM
>>What is the behaviour of HAL_UART_Transmit_IT if nobody is answering on the other side?
It shouldn't care, it is stuffing data into a dumb pipe as fast as the USART flags the output buffer is clear for new data (ie signalling TXE, one byte at a time)
One should be wary of using HAL_Delay(), or waiting for multiple characters in a callback, it is called in interrupt context, do minimal work and leave. The HAL and example code have a lot of code that blocks when that is highly undesirable.
The use of HAL_UART_Transmit_IT() and it's interactivity with the other side, is all on your side of the fence. Is your protocol stuck on a rigid number of bytes, or patterns? Is it capable of resync/recovery when the planets don't align perfectly?
2017-08-09 12:29 PM
Hello Clive, thanks for answering.
Indeed, I am not using any HAL_Delay() and the callbacks are only used to advance the state machine, and copy a few bytes at the maximum.
When you say the USART is 'signalling TXE, one byte at a time', what is happening to those bytes if they are not read at the receiver's end? Does it just keep stuffing data from the TDR to the shift register? If so, what's the point of using an interrupt-driven function if it starts transmitting even though there is no receiver?
In the meantime I noticed I do get Overrun errors on the receiver's end, I just cannot pinpoint yet where exactly they happen...
2017-08-09 01:19 PM
>>what is happening to those bytes if they are not read at the receiver's end?
Nothing on the the transmission side,the USART is just wiggling a pin up and down, if nothing is connected or listening it doesn't care. It is a blind interface. If you implement RTS/CTS flow control you can stop the Tx side.
On the Rx side if you don't pull the data you received the register will overrun once the next byte is received, and that will be flagged, and you must read the data register to clear that state.
2017-08-09 02:06 PM
Ok, that sounds like it could be what's happening.
What I assumed so far is that once HAL_UART_Transmit_IT() is called, it waits until a receiver calls HAL_UART_Receive() or HAL_UART_Receive_IT() before it pushes out any data. Obviously that assumption was wrong.
On the other hand, HAL_UART_Receive_IT() seems to wait until data is available in the receive register. So does that generally mean that, if I want to do interrupt-mode only communication, I have to ensure that HAL_UART_Receive_IT() is called before HAL_UART_Transmit_IT() to avoid any overruns?
2017-08-09 02:33 PM
HAL_UART_Transmit_IT() should return immediately, and call you back once all characters have clocked out, or it times out. For HAL_U(S)ART_Transmit functions with timeout this should be sufficient to account for all characters at the baud rate chosen. Ran into someone on u-Blox forum today where data transmit was truncated.
HAL_UART_Transmit() blocks until characters sent, or timeout.
HAL_UART_Receive function are dependent on inbound data arriving in the size and time frame specified.
The Receive/Transmit on the U(S)ART are independent, you have to manage the flow, expectations, and protocol. The receive end must be ready to accept all data sent it's way.
On SPI they share a common clock tying the Receive/Transmit together.
2017-08-10 05:56 AM
Ok, I have rewritten my code considering the points above, and it runs much better. Basically, I now call the Receive_IT() before the Transmit_IT() that requests the message, instead of the other way around.
Thanks for the comments, that was really helpful!