Merge branch 'doc/esp_ringbuf_acquire_complete_v4.0' into 'release/v4.0'
esp_ringbuf: add documents for SendAcquire and SendComplete (backport v4.0) See merge request espressif/esp-idf!7104
This commit is contained in:
commit
e5d25fb51e
2 changed files with 175 additions and 38 deletions
63
docs/_static/diagrams/ring-buffer/ring_buffer_send_acquire_complete.diag
vendored
Normal file
63
docs/_static/diagrams/ring-buffer/ring_buffer_send_acquire_complete.diag
vendored
Normal 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
|
||||
}
|
|
@ -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
|
||||
^^^^^^^^^^^
|
||||
|
||||
|
|
Loading…
Reference in a new issue