diff --git a/components/ulp/lp_core/lp_core/lp_core_uart.c b/components/ulp/lp_core/lp_core/lp_core_uart.c index 0fa24ba6751..90c8fc7a3ca 100644 --- a/components/ulp/lp_core/lp_core/lp_core_uart.c +++ b/components/ulp/lp_core/lp_core/lp_core_uart.c @@ -167,45 +167,49 @@ int lp_core_uart_read_bytes(uart_port_t lp_uart_num, void *buf, size_t size, int uint32_t to = 0; while (remaining_bytes > 0) { - /* Read from the Rx FIFO - * We set rx_len to -1 to read all bytes in the Rx FIFO - */ - rx_len = -1; - uart_hal_read_rxfifo(&hal, (uint8_t *)(buf + bytes_rcvd), &rx_len); + /* Drain only as many bytes as fit in the remaining buffer space */ + int fifo_len = uart_ll_get_rxfifo_len(hal.dev); + rx_len = (fifo_len < remaining_bytes) ? fifo_len : remaining_bytes; - if (rx_len) { - /* We have some data to read from the Rx FIFO. Check Rx interrupt status */ - intr_status = uart_hal_get_intraw_mask(&hal); - if ((intr_status & UART_INTR_RXFIFO_FULL) || - (intr_status & UART_INTR_RXFIFO_TOUT)) { - /* This is expected. Clear interrupt status and break */ - uart_hal_clr_intsts_mask(&hal, intr_mask); + if (rx_len > 0) { + uart_hal_read_rxfifo(&hal, (uint8_t *)(buf + bytes_rcvd), &rx_len); + bytes_rcvd += rx_len; + remaining_bytes -= rx_len; + + /* RXFIFO_FULL / RXFIFO_TOUT raw bits are sticky; acknowledge them + * so they do not short-circuit the next iteration. */ + uart_hal_clr_intsts_mask(&hal, LP_UART_RX_INT_FLAG); + + if (remaining_bytes <= 0) { break; - } else if ((intr_status & UART_INTR_RXFIFO_OVF)) { - /* We reset the Rx FIFO if it overflows */ + } + + /* FIFO overflow and parity/framing errors are terminal */ + intr_status = uart_hal_get_intraw_mask(&hal); + if (intr_status & UART_INTR_RXFIFO_OVF) { uart_hal_clr_intsts_mask(&hal, intr_mask); uart_hal_rxfifo_rst(&hal); break; - } else if ((intr_status & LP_UART_ERR_INT_FLAG)) { - /* Transaction error. Abort */ + } else if (intr_status & LP_UART_ERR_INT_FLAG) { uart_hal_clr_intsts_mask(&hal, intr_mask); return -1; } - /* Update the byte counters */ - bytes_rcvd += rx_len; - remaining_bytes -= rx_len; + /* Progress was made; restart the timeout window so callers with + * a finite timeout can tolerate gaps between bursts. */ + to = 0; } else { - /* We have no data to read from the Rx FIFO. Check for transaction timeout */ + /* FIFO empty. Honour the caller's timeout. */ ret = lp_core_uart_check_timeout(intr_mask, timeout, &to); if (ret == ESP_ERR_TIMEOUT) { - /* Timeout. Clear interrupt status and break */ uart_hal_clr_intsts_mask(&hal, intr_mask); break; } } } - /* Return the number of bytes received */ - return bytes_rcvd; + if (bytes_rcvd > size) { + bytes_rcvd = size; + } + return (int)bytes_rcvd; }