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.