diff --git a/drivers/serial/uart_nrfx_uarte2.c b/drivers/serial/uart_nrfx_uarte2.c index 750c211efb0..cf109c32d8e 100644 --- a/drivers/serial/uart_nrfx_uarte2.c +++ b/drivers/serial/uart_nrfx_uarte2.c @@ -115,6 +115,9 @@ struct uarte_async_data { uart_callback_t user_callback; void *user_data; + uint8_t *en_rx_buf; + size_t en_rx_len; + struct k_timer tx_timer; struct k_timer rx_timer; @@ -288,6 +291,22 @@ static void on_rx_buf_req(const struct device *dev) struct uarte_async_data *adata = data->async; const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + /* If buffer is not null it indicates that event comes from RX enabling + * function context. We need to pass provided buffer to the driver. + */ + if (adata->en_rx_buf) { + uint8_t *buf = adata->en_rx_buf; + size_t len = adata->en_rx_len; + nrfx_err_t err; + + adata->en_rx_buf = NULL; + adata->en_rx_len = 0; + + err = nrfx_uarte_rx_buffer_set(nrfx_dev, buf, len); + __ASSERT_NO_MSG(err == NRFX_SUCCESS); + return; + } + struct uart_event evt = { .type = UART_RX_BUF_REQUEST }; @@ -296,8 +315,6 @@ static void on_rx_buf_req(const struct device *dev) * reception of one buffer was terminated to restart another transfer. */ if (!K_TIMEOUT_EQ(adata->rx_timeout, K_NO_WAIT)) { - /* Read and clear any pending new data information. */ - nrfx_uarte_rx_new_data_check(nrfx_dev); nrfx_uarte_rxdrdy_enable(nrfx_dev); } data->async->user_callback(dev, &evt, data->async->user_data); @@ -469,22 +486,28 @@ static int api_rx_enable(const struct device *dev, uint8_t *buf, size_t len, int if (timeout != SYS_FOREVER_US) { adata->idle_cnt = RX_TIMEOUT_DIV + 1; adata->rx_timeout = K_USEC(timeout / RX_TIMEOUT_DIV); + nrfx_uarte_rxdrdy_enable(nrfx_dev); } else { adata->rx_timeout = K_NO_WAIT; } - err = nrfx_uarte_rx_buffer_set(nrfx_dev, buf, len); - if (err != NRFX_SUCCESS) { - return -EIO; - } + /* Store the buffer. It will be passed to the driver in the event handler. + * We do that instead of calling nrfx_uarte_rx_buffer_set here to ensure + * that nrfx_uarte_rx_buffer_set is called when RX enable configuration + * flags are already known to the driver (e.g. if flushed data shall be + * kept or not). + */ + adata->en_rx_buf = buf; + adata->en_rx_len = len; + + atomic_or(&data->flags, UARTE_DATA_FLAG_RX_ENABLED); err = nrfx_uarte_rx_enable(nrfx_dev, flags); if (err != NRFX_SUCCESS) { + atomic_and(&data->flags, ~UARTE_DATA_FLAG_RX_ENABLED); return (err == NRFX_ERROR_BUSY) ? -EBUSY : -EIO; } - atomic_or(&data->flags, UARTE_DATA_FLAG_RX_ENABLED); - return 0; } @@ -932,7 +955,8 @@ static int uarte_nrfx_pm_action(const struct device *dev, UARTE_MEMORY_SECTION(idx) __aligned(4); \ static nrfx_uarte_rx_cache_t uarte##idx##_rx_cache_scratch; \ IF_ENABLED(CONFIG_UART_##idx##_INTERRUPT_DRIVEN, \ - (static uint8_t a2i_rx_buf##idx[CONFIG_UART_##idx##_A2I_RX_SIZE];)) \ + (static uint8_t a2i_rx_buf##idx[CONFIG_UART_##idx##_A2I_RX_SIZE] \ + UARTE_MEMORY_SECTION(idx) __aligned(4);)) \ PINCTRL_DT_DEFINE(UARTE(idx)); \ static const struct uart_async_to_irq_config uarte_a2i_config_##idx = \ UART_ASYNC_TO_IRQ_API_CONFIG_INITIALIZER(&a2i_api, \