How to check if a serial port is currently sending something

Hi all,

I have a project where I will be sending/receiving messages via the serial ports on a Due. Receiving is automatically handled in the sense that I just have to check .available() for each port, however, I’d like to know how to check if the serial port is sending a message. I want to know how to do this because I don’t want to have to use .flush(), which I assume is blocking. Essentially, I’ll be switching off between several tasks, including sending those messages, and I don’t want to have to wait to send (want to work on other tasks while sending). But, I have to know when it is done sending because I have to change a digital pin state to let the RS485 transceiver (3.3V TTL to RS485 IC) know that it’s time to receive the message.

Thanks in advance!

I want to know how to do this because I don't want to have to use .flush(), which I assume is blocking.

It is, for the length of time that it takes to send the buffered data. You could look at how flush() is implemented, to see how it determines that it can return.

Okay, snooping around a bit, it looks like I need to #include "sam.h" and then I can test if the transmission is done by "if (UART->UART_SR & UART_SR_TXRDY)", however I think this is for the UART connected to pins 0 and 1. I can't make much out of the sam3x8e.h on GitHub as to the define names for the remaining 3 serial ports. I see UART, PDC_UART, PDC_USART0, PDC_USART1, PDC_USART2, and PDC_USART3, which of these corresponds to the 3 ports on pins 14 thru 19?

Edit: looked on the SAM3X datasheet and matched the USARTs with the TX/RX lines.

Okay, snooping around a bit, it looks like I need to #include "sam.h"

Be sure to do that in #ifdef guards.

The function Serial.availableForWrite() is part of the Arduino core, even though it doesn't appear in the documentation. That will tell you if there are any bytes waiting in the ringbuffer. Then once that's empty, wait one more byte time (depending on baud rate) and you can be sure that all the serial data has been sent.

The Due's UART_SR_TXRDY will flash on between every byte, to let the Arduino core code know it's time to send another byte from the ringbuffer. I would not rely on it to tell you that the ringbuffer is empty.

Following what's in flush(), and being made aware of availableForWrite() (and looking at UARTClass.cpp), I think this should do it:

if ((Serial1.availableForWrite() == (SERIAL_BUFFER_SIZE-1)) && ((USART0->US_CSR & US_CSR_TXRDY) == US_CSR_TXRDY))

I think this should do it:

Without seeing the body of the is statement, I can't agree with you.

What happens when that statement is evaluated, and the outgoing buffer is empty?

The buffer size if usually 64, do you are testing that there are 63 empty places in the buffer - that is, that there is exactly one character not yet sent.

What happens if there are none? What happens if there are 2 or more?

Look at the code for availableForWrite(), the function returns SERIAL_BUFFER_SIZE-1 if the buffer is empty (head == tail)

the function returns SERIAL_BUFFER_SIZE-1 if the buffer is empty (head == tail)

Oops. Some days I can’t count for beans. Of course, the upper index that is empty will be 63 if the array size is 64.

Still doesn’t answer my questions. What happens after the if statement evaluates to false? What happens if it evaluates to true?

Not sure what you're getting at -- if you're asking where the rest of my if statement is, I was only showing the conditional. My reasoning for the conditional shown is based on the code for flush() -- need to make sure head == tail on the buffer, and make sure that the USART is ready to transmit:

int UARTClass::availableForWrite(void)
{
  int head = _tx_buffer->_iHead;
  int tail = _tx_buffer->_iTail;
  if (head >= tail) return SERIAL_BUFFER_SIZE - 1 - head + tail;
  return tail - head - 1;
}

void UARTClass::flush( void )
{
  while (_tx_buffer->_iHead != _tx_buffer->_iTail); //wait for transmit data to be sent
  // Wait for transmission to complete
  while ((_pUart->UART_SR & UART_SR_TXRDY) != UART_SR_TXRDY)
   ;
}

Like I said, based on the code from availableForWrite(), when head == tail, the returned value will be SERIAL_BUFFER_SIZE-1. As far as being ready to transmit, simply copying the 2nd conditional from flush() and replacing with the appropriate defines for USART0 instead of the UART.

Let me rephrase my question. Are you planning to add code to the HardwareSerial class? Or, are you planning to add code to your sketch/class?

If you are planning to add code to the HardwareSerial class, what code do you plan on adding?
If you are planning to add code to your sketch/class, what code do you plan on adding?

Perhaps you mistook me for PaulS ??

Whoops, yes.