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.