8000 Add a poor-man's software FIFO for serial UART reads (#379) · nerkulec/arduino-pico@a58f490 · GitHub
[go: up one dir, main page]

Skip to content

Commit a58f490

Browse files
Add a poor-man's software FIFO for serial UART reads (earlephilhower#379)
Because the hardware FIFO is quite small and doesn't report the actual number of bytes available, implement a software FIFO that will pull all available bytes out of the HW FIFO on any Serial call. It's not as efficient or as bulletproof as an IRQ based method, but it is simpler to implement and can help with issues like earlephilhower#378
1 parent 7120a15 commit a58f490

File tree

2 files changed

+36
-14
lines changed

2 files changed

+36
-14
lines changed

cores/rp2040/SerialUART.cpp

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ void SerialUART::begin(unsigned long baud, uint16_t config) {
9696
gpio_set_function(_tx, GPIO_FUNC_UART);
9797
gpio_set_function(_rx, GPIO_FUNC_UART);
9898
_running = true;
99-
_peek = -1;
99+
while (!_swFIFO.empty()) {
100+
(void)_swFIFO.pop(); // Just throw out anything in our old FIFO
101+
}
100102
}
101103

102104
void SerialUART::end() {
@@ -107,52 +109,66 @@ void SerialUART::end() {
107109
_running = false;
108110
}
109111

112+
// Transfers any data in the HW FIFO into our SW one, up to 32 bytes
113+
void SerialUART::_pumpFIFO() {
114+
while ((_swFIFO.size() < 32) && (uart_is_readable(_uart))) {
115+
_swFIFO.push(uart_getc(_uart));
116+
}
117+
}
118+
110119
int SerialUART::peek() {
111120
CoreMutex m(&_mutex);
112121
if (!_running || !m) {
113122
return -1;
114123
}
115-
if (_peek >= 0) {
116-
return _peek;
124+
_pumpFIFO();
125+
// If there's something in the FIFO now, just peek at it
126+
if (_swFIFO.size()) {
127+
return _swFIFO.front();
117128
}
129+
// The SW FIFO is empty, read the HW one until the timeout
118130
if (uart_is_readable_within_us(_uart, _timeout * 1000)) {
119-
_peek = uart_getc(_uart);
120-
} else {
121-
_peek = -1; // Timeout
131+
// We got one char, put it in the FIFO (which will now have exactly 1 byte) and return it
132+
_swFIFO.push(uart_getc(_uart));
133+
return _swFIFO.front();
122134
}
123-
return _peek;
135+
return -1; // Nothing available before timeout
124136
}
125137

126138
int SerialUART::read() {
127139
CoreMutex m(&_mutex);
128140
if (!_running || !m) {
129141
return -1;
130142
}
131-
if (_peek >= 0) {
132-
int ret = _peek;
133-
_peek = -1;
143+
_pumpFIFO();
144+
if (_swFIFO.size()) {
145+
auto ret = _swFIFO.front();
146+
_swFIFO.pop();
134147
return ret;
135148
}
149+
// The SW FIFO is empty, read the HW one until the timeout
136150
if (uart_is_readable_within_us(_uart, _timeout * 1000)) {
151+
// We got one char, return it (FIFO will still be empty
137152
return uart_getc(_uart);
138-
} else {
139-
return -1; // Timeout
140153
}
154+
return -1; // Timeout
141155
}
142156

143157
int SerialUART::available() {
144158
CoreMutex m(&_mutex);
145159
if (!_running || !m) {
146160
return 0;
147161
}
148-
return (uart_is_readable(_uart)) ? 1 : 0;
162+
_pumpFIFO();
163+
return _swFIFO.size();
149164
}
150165

151166
int SerialUART::availableForWrite() {
152167
CoreMutex m(&_mutex);
153168
if (!_running || !m) {
154169
return 0;
155170
}
171+
_pumpFIFO();
156172
return (uart_is_writable(_uart)) ? 1 : 0;
157173
}
158174

@@ -161,6 +177,7 @@ void SerialUART::flush() {
161177
if (!_running || !m) {
162178
return;
163179
}
180+
_pumpFIFO();
164181
uart_tx_wait_blocking(_uart);
165182
}
166183

@@ -169,6 +186,7 @@ size_t SerialUART::write(uint8_t c) {
169186
if (!_running || !m) {
170187
return 0;
171188
}
189+
_pumpFIFO();
172190
uart_putc_raw(_uart, c);
173191
return 1;
174192
}
@@ -178,6 +196,7 @@ size_t SerialUART::write(const uint8_t *p, size_t len) {
178196
if (!_running || !m) {
179197
return 0;
180198
}
199+
_pumpFIFO();
181200
size_t cnt = len;
182201
while (cnt) {
183202
uart_putc_raw(_uart, *p);

cores/rp2040/SerialUART.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <Arduino.h>
2424
#include "api/HardwareSerial.h"
2525
#include <stdarg.h>
26+
#include <queue>
2627
#include "CoreMutex.h"
2728

2829
extern "C" typedef struct uart_inst uart_inst_t;
@@ -61,8 +62,10 @@ class SerialUART : public HardwareSerial {
6162
uart_inst_t *_uart;
6263
pin_size_t _tx, _rx;
6364
int _baud;
64-
int _peek;
6565
mutex_t _mutex;
66+
67+
void _pumpFIFO();
68+
std::queue<uint8_t> _swFIFO;
6669
};
6770

6871
extern SerialUART Serial1; // HW UART 0

0 commit comments

Comments
 (0)
0