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

Dubble buffered UARTE reception

Hi NordicSemi

I have a project where we receive data via the UARTE. To avoid missing data caused by higher prioritized tasks we want to use the DMA facilities. 

nrf52832 with softdevice and SDK version 15.2

But as we do not know how many bytes we receive we want to use the double buffered facilities, allowing us to process one buffer while the other are used for reception.

But we are not always receiving data, and we still not know how many data are going to be received, therefore we want to periodically forcefully swap from one buffer to the other.

Is this possible.

I have tried with the following (only relevant code snippets shown):

static void FpiUartEventHandler(nrf_drv_uart_event_t * p_event, void * p_context)
{
  uint8_t *p = p_event->data.rxtx.p_data;
  uint32_t l = p_event->data.rxtx.bytes;
  switch(p_event->type)
  {
  case NRFX_UARTE_EVT_ERROR:
    while(l--)
      FifoPut(&fifoRxUart, *p++);

/* Restart reception */
    nrf_drv_uart_rx(&m_uart, bufferRx[0], FPI_UART_MAX_LENGTH);
    nrf_drv_uart_rx(&m_uart, bufferRx[1], FPI_UART_MAX_LENGTH);
    break;
  case NRF_DRV_UART_EVT_TX_DONE:
  {
    FpiUartTransmitNext();
    break;
  }
  case NRF_DRV_UART_EVT_RX_DONE:
  {
    while(l--)
      FifoPut(&fifoRxUart, *p++);

    ret = nrf_drv_uart_rx(&m_uart, p_event->data.rxtx.p_data, FPI_UART_MAX_LENGTH);

    break;
  }
  default:
    break;
  }
}

static void FpiPoll(void * p_context)
{
/* Used as timeout, to ensure that data is not left in receive buffer too long */
  nrf_drv_uart_rx_abort(&m_uart); /* end receiving on primary buffer, automatically switching to secondary buffer */
}

void FpiInit(void)
{
  nrf_drv_uart_config_t config = NRF_DRV_UART_DEFAULT_CONFIG;
  config.pseltxd = HAL_UART_TX_PIN;
  config.pselrxd = HAL_UART_RX_PIN;
  APP_ERROR_CHECK(nrf_drv_uart_init(&m_uart, &config, FpiUartEventHandler));
  APP_ERROR_CHECK(nrf_drv_uart_rx(&m_uart, bufferRx[0], FPI_UART_MAX_LENGTH));
  APP_ERROR_CHECK(nrf_drv_uart_rx(&m_uart, bufferRx[1], FPI_UART_MAX_LENGTH)); // Do not use double buffering at the time.

  APP_ERROR_CHECK(app_timer_create(&m_fpi_timer_id, APP_TIMER_MODE_REPEATED,  FpiPoll));
  APP_ERROR_CHECK(app_timer_start(m_fpi_timer_id, APP_TIMER_TICKS(FPI_TIMER_PERIOD), NULL));
}

The nrf_drv_uart_rx_abort does trigger the TO event on the UART receiver and the FpiUartEventHandler is called. But in the driver the secondary buffer is forcefully canceled.

Therefore it seems to be impossible to use the double buffered feature together with the nrf_drv_uart_rx_abort. 

Did I miss something?

BR and thanks in advance.

Parents
  • Hi,

    to configure double buffering, set ENDRX-STARTRX shortcut and update RXD.PTR to next free buffer on RXSTARTED interrupt (I'm not sure that it can be done with nrf libraries, rather with direct programming of UARTE registers). You should not stop UARTE to manually switch buffers, as you will lose data sometimes. The main problem that you don't know how many bytes actually received. This can be solved by connecting a timer in counter mode to RXDRDY event through PPI - a counter will increment at each received byte.

Reply
  • Hi,

    to configure double buffering, set ENDRX-STARTRX shortcut and update RXD.PTR to next free buffer on RXSTARTED interrupt (I'm not sure that it can be done with nrf libraries, rather with direct programming of UARTE registers). You should not stop UARTE to manually switch buffers, as you will lose data sometimes. The main problem that you don't know how many bytes actually received. This can be solved by connecting a timer in counter mode to RXDRDY event through PPI - a counter will increment at each received byte.

Children
Related