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 a8196bfb482..b7463431aab 100644 --- a/components/ulp/lp_core/lp_core/lp_core_uart.c +++ b/components/ulp/lp_core/lp_core/lp_core_uart.c @@ -185,45 +185,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; } diff --git a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core_uart.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core_uart.c index a8e7edab385..db859abee9d 100644 --- a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core_uart.c +++ b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core_uart.c @@ -5,6 +5,7 @@ */ #include +#include #include #include "hal/uart_types.h" #include "lp_core_test_app_uart.h" @@ -30,6 +31,18 @@ extern const uint8_t lp_core_main_uart_bin_end[] asm("_binary_lp_core_test_app static const char *TAG = "lp_core_uart_test"; +/* + * The LP-core binary exports shared symbols via a generated header that types + * blobs as uint32_t placeholders. The HP test must still walk the real layout + * (lp_uart_read_bounds_guard_t). Indexing through a struct pointer to + * &ulp_read_bounds_guard_region triggers GCC -Warray-bounds= (object size 4). + * Read bytes by absolute address so the compiler does not attach the wrong size. + */ +static __attribute__((noinline)) uint8_t lp_uart_test_read_shared_u8(uintptr_t addr) +{ + return *(const volatile uint8_t *)addr; +} + static void lp_core_uart_clear_buf(void) { uart_dev_t *dev = (uart_dev_t *)UART_LL_GET_HW(LP_UART_NUM_0); @@ -1057,13 +1070,16 @@ static void test_lp_uart_read_bytes_buffer_bounds(void) TEST_ASSERT_LESS_OR_EQUAL(LP_UART_READ_BOUNDS_USER_BUF_LEN, ret_val); TEST_ASSERT_GREATER_THAN(0, ret_val); - lp_uart_read_bounds_guard_t *region = (lp_uart_read_bounds_guard_t *)&ulp_read_bounds_guard_region; + const uintptr_t guard_base = (uintptr_t)(void *)&ulp_read_bounds_guard_region; + const size_t post_off = offsetof(lp_uart_read_bounds_guard_t, post_guard); for (int i = 0; i < LP_UART_READ_BOUNDS_GUARD_LEN; i++) { - TEST_ASSERT_EQUAL_HEX8_MESSAGE(LP_UART_READ_BOUNDS_GUARD_PATTERN, region->pre_guard[i], + TEST_ASSERT_EQUAL_HEX8_MESSAGE(LP_UART_READ_BOUNDS_GUARD_PATTERN, + lp_uart_test_read_shared_u8(guard_base + (uintptr_t)i), "pre-guard memory corrupted"); } for (int i = 0; i < LP_UART_READ_BOUNDS_GUARD_LEN; i++) { - TEST_ASSERT_EQUAL_HEX8_MESSAGE(LP_UART_READ_BOUNDS_GUARD_PATTERN, region->post_guard[i], + TEST_ASSERT_EQUAL_HEX8_MESSAGE(LP_UART_READ_BOUNDS_GUARD_PATTERN, + lp_uart_test_read_shared_u8(guard_base + post_off + (uintptr_t)i), "post-guard memory corrupted"); }