lately I came over the question how to detect if an UART is ready with its transmission.
This is not as easy as it seems as first sight. An UART has up to 3 areas where the data to be transmitted is stored:
1st The buffer (when defined in the module configuration)
2nd The FIFO, 4 bytes deep holding untransmitted data, fed with bytes from Buffer in the interrupt routine
3rd Often forgotten, the Tx-shift-register, holding the actually transmitted byte
An API to get information whether the buffer is already empty is UART_GetTxBufferSize() which does not return the
size as the name would suggest, but the number of used bytes in the buffer. Thus a returned value of 0 (zero) indicates an empty buffer.
To have a look at the FIFO state we have the API UART_ReadTxStatus() which not only indicates an empty FIFO with a bit-mask named
UART_TX_STS_FIFO_EMPTY but indicates a complete transmission of the tx-shift-register with a mask named UART_TX_STS_COMPLETE.
Unfortunately this bit is reset when read with the API.
When writing a function to return the busy state of an UART we have to consider following facts:
Buffer must be empty
FIFO must be empty
Transfer must be complete.
The problem is, when looking at "Transfer must be complete" the API sets the state to "Transfer NOT complete" which would at a next
questioning for a busy UART return "Busy" and this answer can lead into an infinite loop when waiting for a "Ready" UART.
So, a function to give a correct result is a bit complicated. I append one to this post.
When is the function needed?
All the management when transfering data is handled by the supplied UART-routines, so there is no need. But when you have to stop the UART for any
reason (mostly to enter sleep mode) you must be sure that all communication is made.
Here is the function:
static uint8 FirstTimeCalled = TRUE;
#define Busy 1 // Just for better readabiliy (I hope)
STS = UART_ReadTxStatus();
if (!((UART_GetTxBufferSize() == 0) && (STS & UART_TX_STS_FIFO_EMPTY))) // Are the UART buffers empty?
FirstTimeCalled = FALSE;
return Busy; // Buffers NOT empty, return "Busy"
else // UART buffers empty, but last byte may be transfered currently
if (STS & UART_TX_STS_COMPLETE) // Is Transfer completed? Bit was reset with call to UART_ReadTxStatus()
FirstTimeCalled = TRUE; // Yes, we are done
else // Transfer not completed or called the first time after a !Busy returned
if (FirstTimeCalled) return !Busy;
Interestingly it took three years since someone dug out that post!
Glad when I have helped someone and thanks for reviewing and improving!
I agree with Dana that this problem should be at least mentioned in the Sleep() API of the UART.