diff options
Diffstat (limited to 'cores')
| -rw-r--r-- | cores/arduino/HardwareSerial.cpp | 14 | 
1 files changed, 12 insertions, 2 deletions
diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index e6ccdef..ecd7918 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -226,8 +226,18 @@ size_t HardwareSerial::write(uint8_t c)    // significantly improve the effective datarate at high (>    // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.    if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) { -    *_udr = c; -    *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0); +    // If TXC is cleared before writing UDR and the previous byte +    // completes before writing to UDR, TXC will be set but a byte +    // is still being transmitted causing flush() to return too soon. +    // So writing UDR must happen first. +    // Writing UDR and clearing TC must be done atomically, otherwise +    // interrupts might delay the TXC clear so the byte written to UDR +    // is transmitted (setting TXC) before clearing TXC. Then TXC will +    // be cleared when no bytes are left, causing flush() to hang +    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { +      *_udr = c; +      *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0); +    }      return 1;    }    tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE;  | 
