Skip to content

Commit 59c6467

Browse files
Improve HardwareSerial::flush()
The flush() method blocks until all characters in the serial buffer have been written to the uart _and_ transmitted. This is checked by waiting until the "TXC" (TX Complete) bit is set by the UART, signalling completion. This bit is cleared by write() when adding a new byte to the buffer and set by the hardware after tranmission ends, so it is always guaranteed to be zero from the moment the first byte in a sequence is queued until the moment the last byte is transmitted, and it is one from the moment the last byte in the buffer is transmitted until the first byte in the next sequence is queued. However, the TXC bit is also zero from initialization to the moment the first byte ever is queued (and then continues to be zero until the first sequence of bytes completes transmission). Unfortunately we cannot manually set the TXC bit during initialization, we can only clear it. To make sure that flush() would not (indefinitely) block when it is called _before_ anything was written to the serial device, the "transmitting" variable was introduced. This variable suggests that it is only true when something is transmitting, which isn't currently the case (it remains true after transmission is complete until flush() is called, for example). Furthermore, there is no need to keep the status of transmission, the only thing needed is to remember if anything has ever been written, so the corner case described above can be detected. This commit improves the code by: - Renaming the "transmitting" variable to _written (making it more clear and following the leading underscore naming convention). - Not resetting the value of _written at the end of flush(), there is no point to this. - Only checking the "_written" value once in flush(), since it can never be toggled off anyway. - Initializing the value of _written in both versions of _begin (though it probably gets initialized to 0 by default anyway, better to be explicit).
1 parent da984c9 commit 59c6467

File tree

2 files changed

+17
-6
lines changed

2 files changed

+17
-6
lines changed

hardware/arduino/avr/cores/arduino/HardwareSerial.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ void HardwareSerial::begin(unsigned long baud, byte config)
281281
*_ubrrh = baud_setting >> 8;
282282
*_ubrrl = baud_setting;
283283

284+
_written = false;
285+
284286
//set the data bits, parity, and stop bits
285287
#if defined(__AVR_ATmega8__)
286288
config |= 0x80; // select UCSRC register (shared with UBRRH)
@@ -336,9 +338,15 @@ int HardwareSerial::read(void)
336338

337339
void HardwareSerial::flush()
338340
{
339-
// UDR is kept full while the buffer is not empty, so TXC triggers when EMPTY && SENT
340-
while (transmitting && bit_is_clear(*_ucsra, TXC0));
341-
transmitting = false;
341+
// If we have never written a byte, no need to flush. This special
342+
// case is needed since there is no way to force the TXC (transmit
343+
// complete) bit to 1 during initialization
344+
if (!_written)
345+
return;
346+
347+
// UDR is kept full while the buffer is not empty, so TXC triggers
348+
// when EMPTY && SENT
349+
while (bit_is_clear(*_ucsra, TXC0));
342350
}
343351

344352
size_t HardwareSerial::write(uint8_t c)
@@ -355,8 +363,10 @@ size_t HardwareSerial::write(uint8_t c)
355363
_tx_buffer_head = i;
356364

357365
sbi(*_ucsrb, UDRIE0);
358-
// clear the TXC bit -- "can be cleared by writing a one to its bit location"
359-
transmitting = true;
366+
_written = true;
367+
// clear the TXC bit -- "can be cleared by writing a one to its bit
368+
// location". This makes sure flush() won't return until the bytes
369+
// actually got written
360370
sbi(*_ucsra, TXC0);
361371

362372
return 1;

hardware/arduino/avr/cores/arduino/HardwareSerial.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ class HardwareSerial : public Stream
4646
volatile uint8_t *_ucsrb;
4747
volatile uint8_t *_ucsrc;
4848
volatile uint8_t *_udr;
49-
bool transmitting;
49+
// Has any byte been written to the UART since begin()
50+
bool _written;
5051

5152
volatile uint8_t _rx_buffer_head;
5253
volatile uint8_t _rx_buffer_tail;

0 commit comments

Comments
 (0)