Fix flush hanging issue
Make write to UDR and clearing of TXC bit in flush() atomic to avoid race condition. Fixes #3745 (second different issue introduced later but discussed in the same issue)
This commit is contained in:
parent
99c294c5a2
commit
58006613a7
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue