Skip to content

Commit 7f0b9d1

Browse files
mribbledevyte
authored andcommitted
Rx fifo latency fix (esp8266#4328)
* Flush the rx fifo when checking available bytes in fifo. This gives a more correct result rather than waiting until either the fifo is full or until a serial rx timeout occurs. * When rx_avaiable is checked return rx_buffer plus rx_fifo. Then during rx_read and rx_peek functions copy over the data in the fifo as needed. * Clean up early out case. * Set the rx full fifo ISR to trigger a little sooner. This makes the uart rx isr more robust in cases where the ISR can't trigger very fast
1 parent 61cd8d8 commit 7f0b9d1

File tree

1 file changed

+37
-13
lines changed

1 file changed

+37
-13
lines changed

cores/esp8266/uart.c

+37-13
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,31 @@ size_t uart_resize_rx_buffer(uart_t* uart, size_t new_size)
9191
return uart->rx_buffer->size;
9292
}
9393

94+
inline size_t uart_rx_buffer_available(uart_t* uart) {
95+
if(uart->rx_buffer->wpos < uart->rx_buffer->rpos) {
96+
return (uart->rx_buffer->wpos + uart->rx_buffer->size) - uart->rx_buffer->rpos;
97+
}
98+
return uart->rx_buffer->wpos - uart->rx_buffer->rpos;
99+
}
100+
101+
inline size_t uart_rx_fifo_available(uart_t* uart) {
102+
return (USS(uart->uart_nr) >> USRXC) & 0x7F;
103+
}
104+
105+
// Copy all the rx fifo bytes that fit into the rx buffer
106+
inline void uart_rx_copy_fifo_to_buffer(uart_t* uart) {
107+
while(uart_rx_fifo_available(uart)){
108+
size_t nextPos = (uart->rx_buffer->wpos + 1) % uart->rx_buffer->size;
109+
if(nextPos == uart->rx_buffer->rpos) {
110+
// Stop copying if rx buffer is full
111+
break;
112+
}
113+
uint8_t data = USF(uart->uart_nr);
114+
uart->rx_buffer->buffer[uart->rx_buffer->wpos] = data;
115+
uart->rx_buffer->wpos = nextPos;
116+
}
117+
}
118+
94119
int uart_peek_char(uart_t* uart)
95120
{
96121
if(uart == NULL || !uart->rx_enabled) {
@@ -99,6 +124,11 @@ int uart_peek_char(uart_t* uart)
99124
if (!uart_rx_available(uart)) {
100125
return -1;
101126
}
127+
if (uart_rx_buffer_available(uart) == 0) {
128+
ETS_UART_INTR_DISABLE();
129+
uart_rx_copy_fifo_to_buffer(uart);
130+
ETS_UART_INTR_ENABLE();
131+
}
102132
return uart->rx_buffer->buffer[uart->rx_buffer->rpos];
103133
}
104134

@@ -119,10 +149,7 @@ size_t uart_rx_available(uart_t* uart)
119149
if(uart == NULL || !uart->rx_enabled) {
120150
return 0;
121151
}
122-
if(uart->rx_buffer->wpos < uart->rx_buffer->rpos) {
123-
return (uart->rx_buffer->wpos + uart->rx_buffer->size) - uart->rx_buffer->rpos;
124-
}
125-
return uart->rx_buffer->wpos - uart->rx_buffer->rpos;
152+
return uart_rx_buffer_available(uart) + uart_rx_fifo_available(uart);
126153
}
127154

128155

@@ -135,14 +162,7 @@ void ICACHE_RAM_ATTR uart_isr(void * arg)
135162
return;
136163
}
137164
if(USIS(uart->uart_nr) & ((1 << UIFF) | (1 << UITO))){
138-
while((USS(uart->uart_nr) >> USRXC) & 0x7F){
139-
uint8_t data = USF(uart->uart_nr);
140-
size_t nextPos = (uart->rx_buffer->wpos + 1) % uart->rx_buffer->size;
141-
if(nextPos != uart->rx_buffer->rpos) {
142-
uart->rx_buffer->buffer[uart->rx_buffer->wpos] = data;
143-
uart->rx_buffer->wpos = nextPos;
144-
}
145-
}
165+
uart_rx_copy_fifo_to_buffer(uart);
146166
}
147167
USIC(uart->uart_nr) = USIS(uart->uart_nr);
148168
}
@@ -152,7 +172,11 @@ void uart_start_isr(uart_t* uart)
152172
if(uart == NULL || !uart->rx_enabled) {
153173
return;
154174
}
155-
USC1(uart->uart_nr) = (127 << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE );
175+
// UCFFT value is when the RX fifo full interrupt triggers. A value of 1
176+
// triggers the IRS very often. A value of 127 would not leave much time
177+
// for ISR to clear fifo before the next byte is dropped. So pick a value
178+
// in the middle.
179+
USC1(uart->uart_nr) = (100 << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE );
156180
USIC(uart->uart_nr) = 0xffff;
157181
USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIFR) | (1 << UITO);
158182
ETS_UART_INTR_ATTACH(uart_isr, (void *)uart);

0 commit comments

Comments
 (0)