nRF5 SDK v17.1.0
Ring buffer library

The library provides an implementation of a ring buffer. It allows for thread-safe operation on the data in the buffer. The library enables copying data in and out, and some more optimal direct operations of portions of the ring buffer to avoid memory copying.

Initialization

The NRF_RINGBUF_DEF macro creates an instance of the ring buffer. The size of the ring buffer must be a power of 2. It must be first initialized before it can be used.

NRF_RINGBUF_DEF(m_ringbuf, 256);
void foo(void)
{
nrf_ringbuf_init(&m_ringbuf);
}

Access through copying

Data can be copied into the ring buffer using nrf_ringbuf_cpy_put. If another 'put' operation on the instance was interrupted, the attempt returns NRF_ERROR_BUSY. The nrf_ringbuf_cpy_put function returns the amount of data written to the buffer. It can be smaller than requested if there is no space available to copy all data.

Data can be copied out from the ring buffer using nrf_ringbuf_cpy_get. If another 'get' operation on the instance was interrupted, the attempt returns NRF_ERROR_BUSY. The nrf_ringbuf_cpy_get function returns the amount of data read from the buffer. It can be smaller than requested if there is less data available to copy.

void foo(void)
{
ret_code_t err_code;
uint8_t data_in[] = {1,2,3,4};
uint8_t data_out[5];
size_t len_in = sizeof(data_in);
size_t len_out = sizeof(data_out);
err_code = nrf_ringbuf_cpy_put(&m_ringbuf, data_in, &len_in);
err_code = nrf_ringbuf_cpy_get(&m_ringbuf, data_out, &len_out);
ASSERT(len_out == len_in);
ASSERT(memcmp(data_in, data_out, sizeof(data_in)) == 0);
}

Direct access to the memory

The ring buffer library allows for working directly on the memory within the buffer. A portion of the buffer can be allocated for use. Once used, it can be put back (the put amount can be smaller than the allocated one). A similar approach can be used for getting data from the buffer. You can get it and then free it. The amount of freed data can be smaller than the one that was got.

Putting data to the ring buffer consists of the following steps.

  1. Request allocation of N bytes (nrf_ringbuf_alloc) - get M (where M <= N) bytes and the pointer to the buffer. M is smaller or equal to N.
  2. Write P bytes to the buffer where P is smaller or equal to M.
  3. Indicate to the ring buffer that P bytes are valid (nrf_ringbuf_put).
void foo(void)
{
uint8_t * p_buffer;
size_t len = 16;
// Allocate buffer for uart RX
err_code = nrf_ringbuf_alloc(&m_ringbuf, &p_buffer, &len, true);
// Start uart RX. Uart driver has inactivity timeout and returns on receiving requested amount of bytes or less.
size_t rx_len = uart_rx(p_buffer, len);
//Indicate number of valid bytes in the ring buffer
err_code = nrf_ringbuf_put(&m_ringbuf, rx_len);
}

Getting data from the ring buffer consists of the following steps:

  1. Attempt to get N bytes of data from the ring buffer (nrf_ringbuf_get) - get M (where M <= N) bytes and the pointer to the buffer.
  2. Process P bytes of data where P is smaller or equal to M.
  3. Indicate to the ring buffer that P bytes can be freed (nrf_ringbuf_free).
void foo(void)
{
uint8_t * p_buffer;
size_t len = 16;
// Get available data from the buffer
err_code = nrf_ringbuf_get(&m_ringbuf, &p_buffer, &len, true);
// Process data
size_t processed_len = packet_process(p_buffer, len);
//Indicate number of bytes that can be freed
err_code = nrf_ringbuf_free(&m_ringbuf, processed_len);
}

Access to the ring buffer can be exclusive. It means that an attempt to allocate another buffer between nrf_ringbuf_alloc and nrf_ringbuf_put or an attempt to get data from the ring buffer between nrf_ringbuf_get and nrf_ringbuf_free can be detected. However, it is also possible to allocate or get more data with disabled exclusion check.

ret_code_t foo2(void)
{
uint8_t * p_buffer;
size_t len = 16;
err_code = nrf_ringbuf_alloc(&m_ringbuf, &p_buffer, &len, exclusive);
if (err_code == NRF_SUCCESS)
{
//Write data
err_code = nrf_ringbuf_put(&m_ringbuf, len);
}
else
{
return err_code;
}
}
void foo(void)
{
uint8_t * p_buffer;
uint8_t * p_buffer2;
size_t len = 16;
size_t len2 = 16;
// Allocate buffer
bool exclusive = true;
err_code = nrf_ringbuf_alloc(&m_ringbuf, &p_buffer, &len, exclusive);
err_code = foo2(); //NRF_ERROR_BUSY is returned
// Allocate more data without access control
err_code = nrf_ringbuf_alloc(&m_ringbuf, &p_buffer2, &len2, false);
//Write data
err_code = nrf_ringbuf_put(&m_ringbuf, len + len2);
}

Documentation feedback | Developer Zone | Subscribe | Updated