esp_ringbuf: add documents for SendAcquire and SendComplete

This commit is contained in:
michael 2019-09-19 18:35:24 +08:00
parent 420ee45279
commit 37fdcc1eb5
2 changed files with 175 additions and 38 deletions

View file

@ -0,0 +1,63 @@
#Diagram demonstrating reading and returning an item in a No-Split/Allow-Split ring buffer
#Buffer of 128 bytes, with 4 items of 16, 20, 8 and 24 bytes. First 3 items are read and returned
packetdiag ring_buffer_send_acquire_complete {
node_width = 6
node_height = 24
default_fontsize = 12
colwidth = 128
#Initial
0-7: 8 [color = lightblue];
8-23: 16 Available [color = lightyellow];
24-127: Free
#Acquire item 1, 2, 3
128-135: 8 [color = lightblue];
136-151: 16 Available [color = lightyellow];
152-179: 20 Acquired [color = lightgrey];
180-195: 8 Acquired [color = lightgrey];
196-227: 24 Acquired [color = lightgrey];
228-255: 28 Free
#Complete item 2
256-263: 8 [color = lightblue];
264-279: 16 Available [color = lightyellow];
280-307: 20 Acquired [color = lightgrey];
308-315: 8 [color = pink];
316-323: 8 Completed [color = pink];
324-355: 24 Acquired [color = lightgrey];
356-383: 28 Free
#Complete item 3
384-391: 8 [color = lightblue];
392-407: 16 Available [color = lightyellow];
408-435: 20 Acquired [color = lightgrey];
436-443: 8 [color = pink];
444-451: 8 Completed [color = pink];
452-459: 8 [color = pink];
460-483: 24 Completed [color = pink];
484-511: 28 Free
#Complete item 1
512-519: 8 [color = lightblue];
520-535: 16 Available [color = lightyellow];
536-543: 8 [color = pink];
544-563: 20 Completed [color = pink];
564-571: 8 [color = pink];
572-579: 8 Completed [color = pink];
580-587: 8 [color = pink];
588-611: 24 Completed [color = pink];
612-639: 28 Free
#Return item 3
640-647: 8 [color = lightblue];
648-663: 16 Available [color = lightyellow];
664-671: 8 [color = lightblue];
672-691: 20 Available [color = lightyellow];
692-699: 8 [color = lightblue];
700-707: 8 Available [color = lightyellow];
708-715: 8 [color = lightblue];
716-739: 24 Available [color = lightyellow];
740-767: 28 Free
}

View file

@ -23,14 +23,17 @@ Ring Buffers
The ESP-IDF FreeRTOS ring buffer is a strictly FIFO buffer that supports arbitrarily sized items.
Ring buffers are a more memory efficient alternative to FreeRTOS queues in situations where the
size of items is variable. The capacity of a ring buffer is not measured by the number of items
it can store, but rather by the amount of memory used for storing items. Items are sent to
ring buffers by copy, however for efficiency reasons **items are retrieved by reference**. As a
result, all retrieved items **must also be returned** in order for them to be removed from
the ring buffer completely. The ring buffers are split into the three following types:
it can store, but rather by the amount of memory used for storing items. You may apply for a
piece of memory on the ring buffer to send an item, or just use the API to copy your data and send
(according to the send API you call). For efficiency reasons,
**items are always retrieved from the ring buffer by reference**. As a result, all retrieved
items *must also be returned* in order for them to be removed from the ring buffer completely.
The ring buffers are split into the three following types:
**No-Split** buffers will guarantee that an item is stored in contiguous memory and will not
attempt to split an item under any circumstances. Use no-split buffers when items must occupy
contiguous memory.
contiguous memory. *Only this buffer type allows you getting the data item address and writting
to the item by yourself.*
**Allow-Split** buffers will allow an item to be split when wrapping around if doing so will allow
the item to be stored. Allow-split buffers are more memory efficient than no-split buffers but
@ -42,7 +45,8 @@ do not need to be maintained (e.g. a byte stream).
.. note::
No-split/allow-split buffers will always store items at 32-bit aligned addresses. Therefore when
retrieving an item, the item pointer is guaranteed to be 32-bit aligned.
retrieving an item, the item pointer is guaranteed to be 32-bit aligned. This is useful
especially when you need to send some data to the DMA.
.. note::
Each item stored in no-split/allow-split buffers will **require an additional 8 bytes for a header**.
@ -76,6 +80,46 @@ and :cpp:func:`xRingbufferSend` to create a ring buffer then send an item to it.
printf("Failed to send item\n");
}
The following example demonstrates the usage of :cpp:func:`xRingbufferSendAcquire` and
:cpp:func:`xRingbufferSendComplete` instead of :cpp:func:`xRingbufferSend` to apply for the
memory on the ring buffer (of type `RINGBUF_TYPE_NOSPLIT`) and then send an item to it. This way
adds one more step, but allows getting the address of the memory to write to, and writing to the
memory yourself.
.. code-block:: c
#include "freertos/ringbuf.h"
#include "soc/lldesc.h"
typedef struct {
lldesc_t dma_desc;
uint8_t buf[1];
} dma_item_t;
#define DMA_ITEM_SIZE(N) (sizeof(lldesc_t)+(((N)+3)&(~3)))
...
//Retrieve space for DMA descriptor and corresponding data buffer
//This has to be done with SendAcquire, or the address may be different when copy
dma_item_t item;
UBaseType_t res = xRingbufferSendAcquire(buf_handle,
&item, DMA_ITEM_SIZE(buffer_size), pdMS_TO_TICKS(1000));
if (res != pdTRUE) {
printf("Failed to acquire memory for item\n");
}
item->dma_desc = (lldesc_t) {
.size = buffer_size,
.length = buffer_size,
.eof = 0,
.owner = 1,
.buf = &item->buf,
};
//Actually send to the ring buffer for consumer to use
res = xRingbufferSendComplete(buf_handle, &item);
if (res != pdTRUE) {
printf("Failed to send item\n");
}
The following example demonstrates retrieving and returning an item from a **no-split ring buffer**
using :cpp:func:`xRingbufferReceive` and :cpp:func:`vRingbufferReturnItem`
@ -194,6 +238,36 @@ Byte buffers treat data as a sequence of bytes and does not incur any overhead
Referring to the diagram above, the 18, 3, and 27 byte items are sequentially written to the
byte buffer and **merged into a single item of 48 bytes**.
Using SendAcquire and SendComplete
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Items in no-split buffers are acquired (by SendAcquire) in strict FIFO order and must be sent to
the buffer by SendComplete for the data to be accessible by the consumer. Multiple items can be
sent or acquired without calling SendComplete, and the items do not necessarily need to be
completed in the order they were acquired. However the receiving of data items must occur in FIFO
order, therefore not calling SendComplete the earliest acquired item will prevent the subsequent
items from being received.
The following diagrams illustrate what will happen when SendAcquire/SendComplete don't happen in
the same order. At the beginning, there is already an data item of 16 bytes sent to the ring
buffer. Then SendAcquire is called to acquire space of 20, 8, 24 bytes on the ring buffer.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_send_acquire_complete.diag
:caption: SendAcquire/SendComplete items in no-split ring buffers
:align: center
After that, we fill (use) the buffers, and send them to the ring buffer by SendComplete in the
order of 8, 24, 20. When 8 bytes and 24 bytes data are sent, the consumer still can only get the
16 bytes data item. Due to the usage if 20 bytes item is not complete, it's not available, nor
the following data items.
When the 20 bytes item is finally completed, all the 3 data items can be received now, in the
order of 20, 8, 24 bytes, right after the 16 bytes item existing in the buffer at the beginning.
Allow-split/byte buffers do not allow using SendAcquire/SendComplete since acquired buffers are
required to be complete (not wrapped).
Wrap around
^^^^^^^^^^^