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.

Parents
  • 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.

  • 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?

  • Can you please try the nrfx_uarte drivers found here? They are part of nrfx and they made some changes related to double buffering and RXTO in v1.2.0.

  • I'm in a similar situation trying to use UARTE on nrf52840.
    I updated NRFX to the latest v1.3.1 tag but still don't get an RX_DONE event after nrfx_uarte_rx_abort(). In fact, stepping through the driver it's not even getting NRF_UARTE_EVENT_ENDRX.

    This could be another bug or the result of nrfx_uarte not having good documentation, including an example.

  • Hi,

    Thanks for reporting. I have found what seems to be a dormant internal bug report related to the issue. I'll try to revive it.

  • I've just run into the same problem. I want to use double-buffering to avoid dropping received characters when receiving at a high bit rate (921600 bps) without hardware flow control, and I'm calling nrfx_uarte_rx_abort() periodically to get any characters at the trailing end of a receive that don't fill the buffer, and I don't get the documented NRFX_UARTE_EVT_RX_DONE event.

    Has anyone come up with a patch to the nrfx_uarte driver to get this working?

  • Yes, it's working.

    We just ended up replacing the NRFX module with the latest release from github.

Reply Children
Related