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

Async reads from UART do not return partial data

SDK version 15.2.0 (latest at the moment of writing).

I am having trouble reading from UART in > 1 byte chunks where exact length is not known upfront.

The problem is, UART driver will not return partial result even after explicit abort (which i invoke from a timer).

This is because despite what the documentation states:

317 /**
318 * @brief Function for aborting any ongoing reception.
319 * @note @ref NRFX_UARTE_EVT_RX_DONE event will be generated in non-blocking mode.
320 * It will contain number of bytes received until abort was called. The event
321 * handler will be called from UARTE interrupt context.
322 *
323 * @param[in] p_instance Pointer to the driver instance structure.
324 */
325 void nrfx_uarte_rx_abort(nrfx_uarte_t const * p_instance);

The RX_DONE event is not raised unless the amount of data is not exactly equal to the amount specified in the rx call:

526 nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_ENDRX);
527 size_t amount = nrf_uarte_rx_amount_get(p_uarte);
528 // If the transfer was stopped before completion, amount of transfered bytes
529 // will not be equal to the buffer length. Interrupted transfer is ignored.
530 if (amount == p_cb->rx_buffer_length)
531 {

"Interrupted transfer is ignored." vs "It will contain number of bytes received until abort was called." - this looks like a bug to me.

  • Hi,

    I'm not sure if I agree. If you look at Figure 4. UARTE reception with forced stop via STOPRX you can see that you should get an RXTO event after you trigger the STOPRX task (which is what happens when you call nrfx_uarte_rx_abort()). If you look in the nrfx_uarte drivers you can see that this event calls the RX DONE event:

    // nrfx_uart.c line 549:
    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);
        }
    }

    As far as I understand, this event should provide you with the bytes received up until abort was called.

  • what you say makes sense, but i also wasn't just browsing around the driver code to find this.

    i definitely was not getting partial RX_DONE events until i identified and disabled that check.

  • Ok, i experimented some more and it seem that RXTO is not raised at all if RXD is double-buffered, i.e. if transfer is aborted while there is second buffer available and the ENDRX->STARTRX short is enabled (which driver does).

    here's what i did. at the top of uarte_irq_handler, i added this:

    if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_RXTO)) {
      bsp_board_led_on(1);
    }
    if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_ENDRX)) {
      bsp_board_led_on(3);
    }

    when i only configure single buffer and do a short transfer, i get both leds to light up. when i configure second buffer, only LED4 light ups and RXTO is never triggered.

    the manual doesn't mention anything about RXTO and double buffering interaction, so i suppose it should be the same. this smells like a silicon bug, actually

    also, here, at the end of nrfx_uarte_rx, when interrupts are enabled for the async case:

    438 {
    439 nrf_uarte_int_enable(p_instance->p_reg, NRF_UARTE_INT_ERROR_MASK |
    440 NRF_UARTE_INT_ENDRX_MASK);
    441 }

    isn't NRF_UARTE_INT_RXTO_MASK supposed to be there as well?

  • Hi,

    Sorry for the late response. I have done some further digging and consulted SDK driver team, and regarding your first point; it turns out that you are not the first to report this. I also found some internal bug reports, but the guy responsible for them doesn't work for Nordic anymore and it seems like the report was forgotten about. I'll have to look further into this next week.

    Regarding your last point the SDK team says that RXTO is enabled in the init and disabled in the uninit functions. So that means that RXTO interrupt should be enabled until the developer explicitly calls the uninit function.

Related