How does Serial.flush() work?

Does Serial.flush() block until the last byte leaves the UART or only until the last byte is loaded into the UART?

I've built an RS485 comms between 2 Arduinos with DS75176N chips. These chips have an input to select TX or RX. I started with the following transmitter code:

  digitalWrite(DS75176txPin, HIGH);  // set to TX mode
  Serial.print("123456789012");
  Serial.flush();
  digitalWrite(DS75176txPin, LOW);  // set to RX mode
  delay(t);

This wasn't reliable. It appears that the "set to RX mode" line executes before the last byte or two are compltetely sent. The following code, however, works perfectly:

  digitalWrite(DS75176txPin, HIGH);  // set to TX mode
  Serial.print("123456789012");
  Serial.flush();
  delay(2);
  digitalWrite(DS75176txPin, LOW);  // set to RX mode
  delay(t);

Is there a function that would take the place of "Serial.flush()", block until the last bit has left the UART, and eliminate the "delay(2)"?
Thanks.

until the last byte is loaded into the UART

And the actual serial hardware has two registers, a holding register and the actual register shifting out the serial data, so there can be an almost two character delay until the compete message is sent out even when the Serial.flush() command has completed, so having a small delay (delay time based on baud rate being used) is the only way you can safely control the RS485 enable output pin signal without danger of chopping off the last couple of characters being sent out.

Lefty

Thanks Lefty.

I was afraid of that.

If anyone has a clever idea on how to read when the UART is truly finished sending, please let me know.

How many "baud ticks" should I use as a delay? Maybe two bytes worth plus overhead, maybe 20?

Paul

If anyone has a clever idea on how to read when the UART is truly finished sending, please let me know.

Nick Gammon does. Search for his serial link on his web site. He talks about how to get all the serial data out before sleeping the Arduino.

Again the delay should be based on the baud rate you set up in the Serial.begin(xxxx); statement. Character rate in characters per seconds is approximately the baud rate / 10, or around 1k per second at 9600 baud (or about 1 millisecond per character) , so a delay(3) would be more then enough. Scale to whatever baud rate you actually use.

Lefty

But remember that the receiving end has to have a matching delay as well so that it is not sending when your end is still in its delay.
This is a tricky problem and has baffled more than one engineer that has worked for me.

Grumpy_Mike:
But remember that the receiving end has to have a matching delay as well so that it is not sending when your end is still in its delay.
This is a tricky problem and has baffled more than one engineer that has worked for me.

Not sure of the receiving end actually needing to add a matching delay time after it receives the last character of a valid message. The transmitters delay should have timed out by the time the receiver actually reads the last character sent and then decides it must form and send something in response. The main thing is to not delay on the transmitter end too long, just long enough to insure the last two characters to be sent aren’t stepped on by the switching of the RS-485 transceiver chip to soon. The delay must be scaled to the baud rate being used.

Lefty

Not sure of the receiving end actually needing to add a matching delay time after it receives the last character of a valid message.

It doesn't have to match exactly but it should not transmit when the other end is still in its delay period. That is why you have to set that delay properly.

Grumpy_Mike:

Not sure of the receiving end actually needing to add a matching delay time after it receives the last character of a valid message.

It doesn't have to match exactly but it should not transmit when the other end is still in its delay period. That is why you have to set that delay properly.

We agree on that. I just didn't understand what you meant by 'matching delay'. :wink:

My page on RS485 talks about that, because I had a similar (identical?) issue:

http://www.gammon.com.au/forum/?id=11428

After doing the Serial.flush you should do this:

 while (!(UCSR0A & (1 << UDRE0)))  // Wait for empty transmit buffer
     UCSR0A |= 1 << TXC0;  // mark transmission not complete
 while (!(UCSR0A & (1 << TXC0)));   // Wait for the transmission to complete

I don’t know about the matching delay at the receiving end, because presumably it won’t switch from Rx to Tx until the transmission ends? So what you are really doing is making the transmitting end wait until it has finished sending to switch from Tx to Rx.

I’ve been playing with sleeping the MCU and having an RTC wake it with an interrupt every so many minutes. I put some debugging prints in and had some difficulty, but adding Serial.flush() and Serial.end() seems to have been sufficient. Am I just lucky? Baud rate is 57600.

void gotoSleep(void)
{
    uint8_t adcsra, mcucr1, mcucr2;

    Serial << "DDRC=" << _HEX(DDRC) << " PORTC=" << _HEX(PORTC) << " PINC=" << _HEX(PINC) << endl;
    Serial.flush();
    Serial.end();
    digitalWrite(RTC_POWER, LOW);  //remove RTC power
    pinMode(RTC_POWER, INPUT);
    digitalWrite(LED, LOW);        //ensure LED is off
    pinMode(SCL, INPUT);           //tri-state the i2c bus   
    pinMode(SDA, INPUT);
    sleep_enable();
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    adcsra = ADCSRA;               //save the ADC Control and Status Register A
    ADCSRA = 0;                    //disable ADC
    cli();
    mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE);  //turn off the brown-out detector
    mcucr2 = mcucr1 & ~_BV(BODSE);
    MCUCR = mcucr1;
    MCUCR = mcucr2;
    sei();                         //ensure interrupts enabled so we can wake up again
    sleep_cpu();                   //go to sleep
    sleep_disable();               //wake up here
    ADCSRA = adcsra;               //restore ADCSRA    
    Serial.begin(BAUD_RATE);
    pinMode(RTC_POWER, OUTPUT);
}

Well this is interesting. They seemed to have changed how it works. In version 1.0 of the IDE:

void HardwareSerial::flush()
{
  while (_tx_buffer->head != _tx_buffer->tail)
    ;
}

However in version 1.0.3:

void HardwareSerial::flush()
{
  // UDR is kept full while the buffer is not empty, so TXC triggers when EMPTY && SENT
  while (transmitting && ! (*_ucsra & _BV(TXC0)));
  transmitting = false;
}

So it would appear that 1.0.3 onwards will handle flush correctly.

Looking at IDE release notes, it appears to have been corrected in release 1.0.2

Lefty

That might explain my luck, I was using 1.0.3. Thanks, Nick!

Is this brokein again in 1.0.5?

I am also using a 75176 for RS485 and Serial.flush() does not delay until the Transmitt buffer is empty.

I just installed 1.0.5 on a new machine and transfered my Sketches and recompiled

This is my code for changing from RS232 to RS485, I am using a UNO with it’s single Serial on D0,D1 and have a I2C Serial Expander using HC125 Tri-State to manage the D0 Rx.

void rs485_set_receive(uint8_t channel){
 Serial.flush(); // wait for Serial traffic to complete
 switch(channel){
   case 1 :
      I2C.write_byte(0x22,9,5);
	  break;
   case 2 :
      I2C.write_byte(0x22,9,3);
	  break;
   default :
      I2C.write_byte(0x22,9,0x46); // back to RS232
   }
  }

Comm RS232_RS485.pdf (16.6 KB)

The code in 1.0.5 is:

void HardwareSerial::flush()
{
  // UDR is kept full while the buffer is not empty, so TXC triggers when EMPTY && SENT
  while (transmitting && ! (*_ucsra & _BV(TXC0)));
  transmitting = false;
}

You could try my code, it isn’t exactly the same:

while (!(UCSR0A & (1 << UDRE0)))  // Wait for empty transmit buffer
     UCSR0A |= 1 << TXC0;  // mark transmission not complete
 while (!(UCSR0A & (1 << TXC0)));   // Wait for the transmission to complete

… and have a I2C Serial Expander using HC125 Tri-State to manage the D0 Rx.

I don’t really understand that.