This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

UARTE data loss on nRF52832 and nRF52840 when using EasyDMA

I'm trying to read data over UART as fast as possible using the double-buffering feature and EasyDMA, but even this simple example I've posted is losing data.

I've set up three buffers:

  • Active - the one EasyDMA is writing into.
  • Next - next buffer EasyDMA should write to.
  • Ready - buffer with data for the application to consume.

And this is the flow:

  • The Active buffer is loaded into EasyDMA in the initialization function.
  • The ENDRX_STARTRX short is set for continuous reception.
  • On the event RXSTARTED I set the Next buffer in EasyDMA, which should now hold two buffers.
  • On the event ENDRX the Next buffer becomes the Active buffer because of the double buffering. I re-arm the EasyDMA using the old Ready buffer (which then becomes Next) and the old Active buffer (with data) becomes the Ready buffer.

When I send 1 byte at a time I can see through the debugger that everything works as expected, data is stored in the buffers and the UARTE module swaps out the buffers as told. However, if I dump a couple of hundred of bytes at a time I can see from the "counter" variable that I'm losing data and even when dumping the same amount of data repeatedly I can see from the "counter" that the data loss is inconsistent.

I've tested this on both the nRF52832 and nRF52840 development kits using SDK 14.2.

What am I doing wrong here?

#include <stdbool.h>
#include <stdint.h>
#include "nrf_delay.h"
#include "boards.h"

#include "nrf_uarte.h"
#include "nrf_drv_common.h"
#include "app_util_platform.h"

#define BUFFER_SIZE         32
#define NUMBER_OF_BANKS     3
#define ACTIVE_BANK_OFFSET  0
#define NEXT_BANK_OFFSET    1
#define READY_BANK_OFFSET   2
#define TX_PIN              TX_PIN_NUMBER
#define RX_PIN              RX_PIN_NUMBER

static uint8_t buffer[NUMBER_OF_BANKS][BUFFER_SIZE];
static uint32_t counter = 0;
static uint32_t active_bank = 0;

void UARTE0_UART0_IRQHandler(void)
{
    if (nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_RXSTARTED))
    {
        nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_RXSTARTED);

        uint8_t next_bank = (active_bank + NEXT_BANK_OFFSET) % NUMBER_OF_BANKS;

        nrf_uarte_rx_buffer_set(NRF_UARTE0, buffer[next_bank], BUFFER_SIZE);
    }

    if (nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_ENDRX))
    {
        nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_ENDRX);

        active_bank++;

        if (active_bank >= NUMBER_OF_BANKS) 
        {
            active_bank = 0;
        }

        counter++;
    }

    if (nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_ERROR))
    {
        nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_ERROR);

        uint32_t code = nrf_uarte_errorsrc_get_and_clear(NRF_UARTE0);
    }
}

void init(void)
{
    nrf_gpio_pin_set(TX_PIN);
    nrf_gpio_cfg_output(TX_PIN);
    nrf_gpio_cfg_input(RX_PIN, NRF_GPIO_PIN_NOPULL);

    nrf_uarte_txrx_pins_set(NRF_UARTE0, TX_PIN, RX_PIN);

    nrf_uarte_configure(NRF_UARTE0, NRF_UARTE_PARITY_EXCLUDED, NRF_UARTE_HWFC_DISABLED);

    nrf_uarte_baudrate_set(NRF_UARTE0, NRF_UARTE_BAUDRATE_115200);

    nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_RXSTARTED);
    nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_ERROR);
    nrf_uarte_event_clear(NRF_UARTE0, NRF_UARTE_EVENT_ENDRX);

    nrf_uarte_int_enable(NRF_UARTE0,
                         NRF_UARTE_INT_RXSTARTED_MASK |
                         NRF_UARTE_INT_ERROR_MASK     |
                         NRF_UARTE_INT_ENDRX_MASK);

    nrf_uarte_shorts_enable(NRF_UARTE0, NRF_UARTE_SHORT_ENDRX_STARTRX);

    nrf_drv_common_irq_enable(UART0_IRQn, APP_IRQ_PRIORITY_HIGHEST);

    nrf_uarte_enable(NRF_UARTE0);

    nrf_uarte_rx_buffer_set(NRF_UARTE0, buffer[0], BUFFER_SIZE);

    nrf_uarte_task_trigger(NRF_UARTE0, NRF_UARTE_TASK_STARTRX);
}


int main(void)
{
    init();

    for (;;)
    {
        __WFI();
    }
}

Edit: changed header include in example code and changed pin names.

Parents
  • Hello,

    I have tried to send 31 * 32 bytes via my uart terminal (maximum allowed transmission by the terminal), and I can't seem to replicate your problem.

    I tried to add to your code:

     

            ...
            counter++;
            if(counter >=31)
            {
                counter = 0;
            }

    And it always stops on the breakpoint I placed there after I send the packet. I can also see in the buffers that the data is aligned with the end of the data that I send, so it indicates that I don't loose any data. I have tested it quite a few times. Do you get data loss often? I tried to send 31*32 (=992) bytes about 20 times in a row, and the breakpoint always fired. 

    Have you configured the sdk_config.h file, or in some other way possibly changed to use the RC Oscillator instead of the crystal? Have you tried to check the RX pin with e.g. a logic analyzer to see if all the data is sent correctly? What device are you sending the UART data from?

     

    Best regards,

    Edvin

  • I went through everything in your post and it turns out my uart terminal is not capable of sending the big chunk of data I was copy-pasting into it.

    When I reduce the size to something that still exercises the buffers it works!

    Thank you for pointing me in the right direction!

Reply Children
No Data
Related