From 9aa902ef9d272e12306eb9ff7ffae4cdf47c6227 Mon Sep 17 00:00:00 2001 From: Nico Date: Fri, 25 Sep 2015 16:17:24 +0200 Subject: [PATCH 1/3] Fix Hardwareserial sending a byte twice https://github.com/arduino/Arduino/issues/3745 --- hardware/arduino/avr/cores/arduino/HardwareSerial.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp b/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp index 5cd89e5e664..0ea71e63434 100644 --- a/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp +++ b/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp @@ -218,8 +218,11 @@ 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)) { + uint8_t oldSREG = SREG; + cli(); *_udr = c; sbi(*_ucsra, TXC0); + SREG = oldSREG; return 1; } tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE; @@ -240,9 +243,12 @@ size_t HardwareSerial::write(uint8_t c) } _tx_buffer[_tx_buffer_head] = c; + uint8_t oldSREG = SREG; + cli(); _tx_buffer_head = i; sbi(*_ucsrb, UDRIE0); + SREG = oldSREG; return 1; } From 30762518f23c5310dac505f9d79ad62556adba9b Mon Sep 17 00:00:00 2001 From: Nico Date: Sat, 26 Sep 2015 12:24:59 +0200 Subject: [PATCH 2/3] Changed Hardwareserial cli() to Atomic Blocks --- .../avr/cores/arduino/HardwareSerial.cpp | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp b/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp index 0ea71e63434..483059d7581 100644 --- a/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp +++ b/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "Arduino.h" #include "HardwareSerial.h" @@ -178,13 +179,12 @@ int HardwareSerial::read(void) int HardwareSerial::availableForWrite(void) { #if (SERIAL_TX_BUFFER_SIZE>256) - uint8_t oldSREG = SREG; - cli(); + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { #endif tx_buffer_index_t head = _tx_buffer_head; tx_buffer_index_t tail = _tx_buffer_tail; #if (SERIAL_TX_BUFFER_SIZE>256) - SREG = oldSREG; + } #endif if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail; return tail - head - 1; @@ -218,11 +218,10 @@ 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)) { - uint8_t oldSREG = SREG; - cli(); - *_udr = c; - sbi(*_ucsra, TXC0); - SREG = oldSREG; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + *_udr = c; + sbi(*_ucsra, TXC0); + } return 1; } tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE; @@ -243,12 +242,11 @@ size_t HardwareSerial::write(uint8_t c) } _tx_buffer[_tx_buffer_head] = c; - uint8_t oldSREG = SREG; - cli(); - _tx_buffer_head = i; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + _tx_buffer_head = i; - sbi(*_ucsrb, UDRIE0); - SREG = oldSREG; + sbi(*_ucsrb, UDRIE0); + } return 1; } From 7b87a52971815bd479de4613139ed4bdaf01080d Mon Sep 17 00:00:00 2001 From: Nico Date: Sat, 26 Sep 2015 16:47:32 +0200 Subject: [PATCH 3/3] Made Serial.write() buffer comparison atomic --- hardware/arduino/avr/cores/arduino/HardwareSerial.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp b/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp index 483059d7581..6f0c0beb535 100644 --- a/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp +++ b/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp @@ -217,7 +217,14 @@ size_t HardwareSerial::write(uint8_t c) // to the data register and be done. This shortcut helps // 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)) { +#if (SERIAL_TX_BUFFER_SIZE>256) + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { +#endif + bool emptyBuffer = _tx_buffer_head == _tx_buffer_tail; +#if (SERIAL_TX_BUFFER_SIZE>256) + } +#endif + if (emptyBuffer && bit_is_set(*_ucsra, UDRE0)) { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *_udr = c; sbi(*_ucsra, TXC0);