Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

UARTE RX abort non-functional when using double-buffered receive

I'm using the UARTE peripheral via the UART driver code in SDK v14.2. Due to transfer size and SoftDevice timing I have to use the double-buffered receive method (by calling nrf_drv_uart_rx() twice). My receive transfers have the possibility of timing out, in which case I abort the transfer via nrf_drv_uart_rx_abort(). I have found that if the first buffer is still active, and the second buffer hasn't been used, then when I call nrf_drv_uart_rx_abort() I never get the NRF_DRV_UART_EVT_RX_DONE callback in my event handler. When I subsequently try to initiate my next RX, the driver throws NRF_ERROR_BUSY.

Tracing it back, it looks like the UARTE never generates an RXTO event as long as the ENDRX->STARTRX shortcut is enabled. I made two small changes to the driver code which solved my problem, but I would like to know if there is a better/cleaner solution. If not, then these changes should probably become part of the UART driver.

In nrf_drv_uart_rx_abort(), change the CODE_FOR_UARTE block to look like this:

    CODE_FOR_UARTE
    (
        // When using double-buffered RX, we must disable the short before aborting. Otherwise,
        // we will never receive the RXTO event
        if (p_cb->rx_secondary_buffer_length)
nrf_uarte_shorts_disable(p_instance->reg.p_uarte, NRF_UARTE_SHORT_ENDRX_STARTRX); nrf_uarte_task_trigger(p_instance->reg.p_uarte, NRF_UARTE_TASK_STOPRX); )

and in uarte_irq_handler(), change the RXTO handler section to look like this:

    if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_RXTO))
    {
        nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_RXTO);
        if (p_cb->rx_buffer_length)
        {
            p_cb->rx_buffer_length = 0;
            rx_done_event(p_cb, nrf_uarte_rx_amount_get(p_uarte), p_cb->p_rx_buffer);
        }

        // When using double-buffered RX, we must clear both receive counts. Otherwise, the next
        // time we try to do a double-buffered receive the driver will throw an error
        if (p_cb->rx_secondary_buffer_length != 0) {
          p_cb->rx_secondary_buffer_length = 0;
        }
    }
Related