Skip to content

Commit 3a2a7f8

Browse files
Fix hang on Serial overflow, PIOSerial stop bit handling (#401)
When the Serial software FIFOs overeflowed, the IRQ handler would not read any more data from the hardware FIFOs. This would cause the IRQ handler to be continually called as soon as it exited since the HW FIFOS were not empty. Now always read every available HW FIFO entry and throw out any that don't fit in the SW FIFO. Also fix a too long by half stop bit timing in the PIOSerial receiver.
1 parent 52a22e5 commit 3a2a7f8

File tree

2 files changed

+21
-9
lines changed

2 files changed

+21
-9
lines changed

cores/rp2040/SerialPIO.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
9191
if (_rx == NOPIN) {
9292
return;
9393
}
94-
while ((!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) && ((_writer + 1) % sizeof(_queue) != _reader)) {
94+
while (!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) {
9595
uint32_t decode = _rxPIO->rxf[_rxSM];
9696
decode >>= 32 - _rxBits;
9797
uint32_t val = 0;
@@ -114,9 +114,13 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
114114
}
115115
}
116116

117-
_queue[_writer] = val & ((1 << _bits) - 1);
118-
asm volatile("" ::: "memory"); // Ensure the queue is written before the written count advances
119-
_writer = (_writer + 1) % sizeof(_queue);
117+
if ((_writer + 1) % sizeof(_queue) != _reader) {
118+
_queue[_writer] = val & ((1 << _bits) - 1);
119+
asm volatile("" ::: "memory"); // Ensure the queue is written before the written count advances
120+
_writer = (_writer + 1) % sizeof(_queue);
121+
} else {
122+
// TODO: Overflow
123+
}
120124
}
121125
}
122126

@@ -195,7 +199,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
195199
_writer = 0;
196200
_reader = 0;
197201

198-
_rxBits = 2 * (_bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1);
202+
_rxBits = 2 * (_bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1) - 1;
199203
_rxPgm = _getRxProgram(_rxBits);
200204
int off;
201205
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off)) {
@@ -213,6 +217,9 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
213217
pio_sm_put_blocking(_rxPIO, _rxSM, clock_get_hz(clk_sys) / (_baud * 2) - 2);
214218
pio_sm_exec(_rxPIO, _rxSM, pio_encode_pull(false, false));
215219

220+
// Join the TX FIFO to the RX one now that we don't need it
221+
_rxPIO->sm[_rxSM].shiftctrl |= 0x80000000;
222+
216223
// Enable interrupts on rxfifo
217224
switch (_rxSM) {
218225
case 0: pio_set_irq0_source_enabled(_rxPIO, pis_sm0_rx_fifo_not_empty, true); break;

cores/rp2040/SerialUART.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,15 @@ void arduino::serialEvent2Run(void) {
248248
// IRQ handler, called when FIFO > 1/4 full or when it had held unread data for >32 bit times
249249
void __not_in_flash_func(SerialUART::_handleIRQ)() {
250250
uart_get_hw(_uart)->icr |= UART_UARTICR_RTIC_BITS | UART_UARTICR_RXIC_BITS;
251-
while ((uart_is_readable(_uart)) && ((_writer + 1) % sizeof(_queue) != _reader)) {
252-
_queue[_writer] = uart_getc(_uart);
253-
asm volatile("" ::: "memory"); // Ensure the queue is written before the written count advances
254-
_writer = (_writer + 1) % sizeof(_queue);
251+
while (uart_is_readable(_uart)) {
252+
auto val = uart_getc(_uart);
253+
if ((_writer + 1) % sizeof(_queue) != _reader) {
254+
_queue[_writer] = val;
255+
asm volatile("" ::: "memory"); // Ensure the queue is written before the written count advances
256+
_writer = (_writer + 1) % sizeof(_queue);
257+
} else {
258+
// TODO: Overflow
259+
}
255260
}
256261
}
257262

0 commit comments

Comments
 (0)