Skip to content

Commit 08c3bfd

Browse files
Disable the RX PCINT inside SoftwareSerial::recv
Before, the interrupt would remain enabled during reception, which would re-set the PCINT flag because of the level changes inside the received byte. Because interrupts are globally disabled, this would not immediately trigger an interrupt, but the flag would be remembered to trigger another PCINT interrupt immediately after the first one is processed. Typically this was not a problem, because the second interrupt would see the stop bit, or an idle line, and decide that the interrupt triggered for someone else. However, at high baud rates, this could cause the next interrupt for the real start bit to be delayed so much that the byte got corrupted. By clearing the interrupt mask bit for just the RX pin (as opposed to the PCINT mask bit for the entire port), any PCINT events on other bits can still set the PCINT flag and be processed as normal. In this case, it's likely that there will be corruption, but that's inevitable when (other) interrupts happen during SoftwareSerial reception.
1 parent 5f2f0ef commit 08c3bfd

File tree

2 files changed

+8
-1
lines changed

2 files changed

+8
-1
lines changed

libraries/SoftwareSerial/SoftwareSerial.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,11 @@ void SoftwareSerial::recv()
237237
// so interrupt is probably not for us
238238
if (_inverse_logic ? rx_pin_read() : !rx_pin_read())
239239
{
240+
// Disable further interrupts during reception, this prevents
241+
// triggering another interrupt directly after we return, which can
242+
// cause problems at higher baudrates.
243+
setRxIntMsk(false);
244+
240245
// Wait approximately 1/2 of a bit width to "center" the sample
241246
tunedDelay(_rx_delay_centering);
242247
DebugPulse(_DEBUG_PIN2, 1);
@@ -255,6 +260,8 @@ void SoftwareSerial::recv()
255260
tunedDelay(_rx_delay_stopbit);
256261
DebugPulse(_DEBUG_PIN2, 1);
257262

263+
// Re-enable interrupts when we're sure to be inside the stop bit
264+
setRxIntMsk(true);
258265
if (_inverse_logic)
259266
d = ~d;
260267

libraries/SoftwareSerial/SoftwareSerial.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class SoftwareSerial : public Stream
7676
void tx_pin_write(uint8_t pin_state) __attribute__((__always_inline__));
7777
void setTX(uint8_t transmitPin);
7878
void setRX(uint8_t receivePin);
79-
void setRxIntMsk(bool enable);
79+
void setRxIntMsk(bool enable) __attribute__((__always_inline__));
8080

8181
// private static method for timing
8282
static inline void tunedDelay(uint16_t delay);

0 commit comments

Comments
 (0)