This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

General info of the correct usage of libuarte? Error: libUARTE_async: (evt) Failed to allocate buffer for RX

Hello everybody,

I am working on a custom board and i´d like to implement libuarte (on a nRF52832) to communicate with another uC on said board.
I am using sdk 17.0.2.
The goal is to receive data from the other uC and transmit it via BLE to a connected device using notifications.

The basic implementation is copied from the example.

My humble understanding of the implementation and usage are:

Configure the libuarte peripheral in sdk_config.h

// <q> NRF_LIBUARTE_ASYNC_WITH_APP_TIMER  - nrf_libuarte_async - libUARTE_async library
 

#ifndef NRF_LIBUARTE_ASYNC_WITH_APP_TIMER
#define NRF_LIBUARTE_ASYNC_WITH_APP_TIMER 1
#endif

// </h> 
//==========================================================

// <h> nrf_libuarte_drv - libUARTE library

//==========================================================
// <q> NRF_LIBUARTE_DRV_HWFC_ENABLED  - Enable HWFC support in the driver
 

#ifndef NRF_LIBUARTE_DRV_HWFC_ENABLED
#define NRF_LIBUARTE_DRV_HWFC_ENABLED 0
#endif

// <q> NRF_LIBUARTE_DRV_UARTE0  - UARTE0 instance
 

#ifndef NRF_LIBUARTE_DRV_UARTE0
#define NRF_LIBUARTE_DRV_UARTE0 1
#endif

// <q> NRF_LIBUARTE_DRV_UARTE1  - UARTE1 instance
 

#ifndef NRF_LIBUARTE_DRV_UARTE1
#define NRF_LIBUARTE_DRV_UARTE1 0
#endif

Create a libuarte instance using

NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 2, 2, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 255, 3);

Note the differences from the example. As per use-libuarte-together-with-softdevice rtc2 and timer 2 can be consumed by the libuarte.
Therfore these must be activated in sdk_config.h.

#ifndef NRFX_RTC2_ENABLED
#define NRFX_RTC2_ENABLED 1
#endif

#ifndef NRFX_TIMER2_ENABLED
#define NRFX_TIMER2_ENABLED 1
#endif

This thread general-libuarte-questions meight not be up to date, since it was created over 3 years ago. But i took it as it is.

The description in this thread mentions the nee to disable NRF_PRS_BOX_4.

#ifndef NRFX_PRS_BOX_4_ENABLED
#define NRFX_PRS_BOX_4_ENABLED 0
#endif

The next step is impementing the uart_event_handler.

void uart_event_handler(void *context, nrf_libuarte_async_evt_t *p_evt) {
  nrf_libuarte_async_t *p_libuarte = (nrf_libuarte_async_t *)context;
  ret_code_t ret;

  switch (p_evt->type) {
    case NRF_LIBUARTE_ASYNC_EVT_ERROR: {
      NRF_LOG_ERROR("LIBUARTE ERROR");
      break;
    }
    case NRF_LIBUARTE_ASYNC_EVT_RX_DATA: {
     // Receive complete
      memcpy(buffer, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
      data_length = p_evt->data.rxtx.length;
      break;
    }
    case NRF_LIBUARTE_ASYNC_EVT_TX_DONE: {
      // Transmit complete

      break;
    }
  }
}

The implementation is quite simple. I send a command to the second controller, get the NRF_LIBUARTE_ASYNC_EVT_TX_DONE event but have nothing to do with this information.
The second controller then starts transmitting data for which i get the NRF_LIBUARTE_ASYNC_EVT_RX_DATA event.
Here i just copy the data to a buffer. This data is used to update the gatt value and notify a connected device via notifications.

void transmit_data(uint8_t *data, uint8_t size) {
  uint32_t error_code;
  ble_gatts_value_t gatts_value;

  memset(&gatts_value, 0, sizeof(gatts_value));

  gatts_value.len = size;
  gatts_value.offset = 0;
  gatts_value.p_value = data;

  error_code = sd_ble_gatts_value_set(_ble.current_connection_handle,
      _ble.characteristic_value_handles.value_handle, &gatts_value);

  //check if connected and notification enabled
  if (_ble.current_connection_handle != BLE_CONN_HANDLE_INVALID) {
    ble_gatts_hvx_params_t handle_value_operation_params;

    memset(&handle_value_operation_params, 0, sizeof(handle_value_operation_params));

    handle_value_operation_params.handle = _ble.characteristic_value_handles.value_handle;
    handle_value_operation_params.type = BLE_GATT_HVX_NOTIFICATION;
    handle_value_operation_params.offset = 0;
    handle_value_operation_params.p_len = &gatts_value.len;
    handle_value_operation_params.p_data = gatts_value.p_value;

    error_code = sd_ble_gatts_hvx(_ble.current_connection_handle, &handle_value_operation_params);
  } else {
    error_code = NRF_ERROR_INVALID_STATE;
  }
}

When this returns, i free the buffer with

nrf_libuarte_async_rx_free(&libuarte, buffer, data_length);
.
I am unsure if i use this correctly and would like to learn more about it.
The implementation is naive and result of intuitive interpretation of the example, where the buffer was freed after the received data was send back to the sender.
So i assume the buffer has to be freed after we used its data, but before we expect new data coming in?
After the free is send another command to the second controller to indicate i expect the next chunk of data.

After we established the basic implementation, we get to the part i have a hard time understanding.

The above described system works - until a certain point. For now i try to receive packets of 240 bytes (although initializing libuarte with 255) and then forwarding them to my phone
and observe the incoming data with nRF Connect app.

I am able to receive and transmit about 2-3 of the 240 byte packages. Then i run into <error> libUARTE_async: (evt) Failed to allocate buffer for RX.
The error itself is descriptive and i located its origin in nrf_libuarte_async.c line 230.

I do not understand why we can not allocate the buffer. I susspect i misunderstand the use of libuarte and the rx_free() function.
I never use the rx_free to free p_evt->data.rxtx.p_data as the example did on the NRF_LIBUARTE_ASYNC_EVT_TX_DONE event.
I tried doing this, but got Unexpected RX free input parameter after receiving and freeing more than the initialized 255 bytes.

I hope i could express myself somewhat clear. I appriciate any input if someone could explain to me, or point me to resources i could learn more about my problem.

Thanks and best regards!

Parents Reply Children
No Data
Related