Merge branch 'doc/esp_ringbuf_acquire_complete' into 'master'
esp_ringbuf: add documents for SendAcquire and SendComplete See merge request espressif/esp-idf!6165
This commit is contained in:
commit
e2897f4d4a
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.
|
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
|
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
|
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
|
it can store, but rather by the amount of memory used for storing items. You may apply for a
|
||||||
ring buffers by copy, however for efficiency reasons **items are retrieved by reference**. As a
|
piece of memory on the ring buffer to send an item, or just use the API to copy your data and send
|
||||||
result, all retrieved items **must also be returned** in order for them to be removed from
|
(according to the send API you call). For efficiency reasons,
|
||||||
the ring buffer completely. The ring buffers are split into the three following types:
|
**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
|
**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
|
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
|
**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
|
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::
|
.. note::
|
||||||
No-split/allow-split buffers will always store items at 32-bit aligned addresses. Therefore when
|
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::
|
.. note::
|
||||||
Each item stored in no-split/allow-split buffers will **require an additional 8 bytes for a header**.
|
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");
|
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**
|
The following example demonstrates retrieving and returning an item from a **no-split ring buffer**
|
||||||
using :cpp:func:`xRingbufferReceive` and :cpp:func:`vRingbufferReturnItem`
|
using :cpp:func:`xRingbufferReceive` and :cpp:func:`vRingbufferReturnItem`
|
||||||
|
@ -83,7 +127,7 @@ using :cpp:func:`xRingbufferReceive` and :cpp:func:`vRingbufferReturnItem`
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
//Receive an item from no-split ring buffer
|
//Receive an item from no-split ring buffer
|
||||||
size_t item_size;
|
size_t item_size;
|
||||||
char *item = (char *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(1000));
|
char *item = (char *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(1000));
|
||||||
|
@ -162,23 +206,23 @@ using :cpp:func:`xRingbufferReceiveUpTo` and :cpp:func:`vRingbufferReturnItem`
|
||||||
|
|
||||||
|
|
||||||
For ISR safe versions of the functions used above, call :cpp:func:`xRingbufferSendFromISR`, :cpp:func:`xRingbufferReceiveFromISR`,
|
For ISR safe versions of the functions used above, call :cpp:func:`xRingbufferSendFromISR`, :cpp:func:`xRingbufferReceiveFromISR`,
|
||||||
:cpp:func:`xRingbufferReceiveSplitFromISR`, :cpp:func:`xRingbufferReceiveUpToFromISR`, and :cpp:func:`vRingbufferReturnItemFromISR`
|
:cpp:func:`xRingbufferReceiveSplitFromISR`, :cpp:func:`xRingbufferReceiveUpToFromISR`, and :cpp:func:`vRingbufferReturnItemFromISR`
|
||||||
|
|
||||||
|
|
||||||
Sending to Ring Buffer
|
Sending to Ring Buffer
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
The following diagrams illustrate the differences between no-split/allow-split buffers
|
The following diagrams illustrate the differences between no-split/allow-split buffers
|
||||||
and byte buffers with regards to sending items/data. The diagrams assume that three
|
and byte buffers with regards to sending items/data. The diagrams assume that three
|
||||||
items of sizes **18, 3, and 27 bytes** are sent respectively to a **buffer of 128 bytes**.
|
items of sizes **18, 3, and 27 bytes** are sent respectively to a **buffer of 128 bytes**.
|
||||||
|
|
||||||
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_send_non_byte_buf.diag
|
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_send_non_byte_buf.diag
|
||||||
:caption: Sending items to no-split/allow-split ring buffers
|
:caption: Sending items to no-split/allow-split ring buffers
|
||||||
:align: center
|
:align: center
|
||||||
|
|
||||||
For no-split/allow-split buffers, a header of 8 bytes precedes every data item. Furthermore, the space
|
For no-split/allow-split buffers, a header of 8 bytes precedes every data item. Furthermore, the space
|
||||||
occupied by each item is **rounded up to the nearest 32-bit aligned size** in order to maintain overall
|
occupied by each item is **rounded up to the nearest 32-bit aligned size** in order to maintain overall
|
||||||
32-bit alignment. However the true size of the item is recorded inside the header which will be
|
32-bit alignment. However the true size of the item is recorded inside the header which will be
|
||||||
returned when the item is retrieved.
|
returned when the item is retrieved.
|
||||||
|
|
||||||
Referring to the diagram above, the 18, 3, and 27 byte items are **rounded up to 20, 4, and 28 bytes**
|
Referring to the diagram above, the 18, 3, and 27 byte items are **rounded up to 20, 4, and 28 bytes**
|
||||||
|
@ -188,12 +232,42 @@ respectively. An 8 byte header is then added in front of each item.
|
||||||
:caption: Sending items to byte buffers
|
:caption: Sending items to byte buffers
|
||||||
:align: center
|
:align: center
|
||||||
|
|
||||||
Byte buffers treat data as a sequence of bytes and does not incur any overhead
|
Byte buffers treat data as a sequence of bytes and does not incur any overhead
|
||||||
(no headers). As a result, all data sent to a byte buffer is merged into a single item.
|
(no headers). As a result, all data sent to a byte buffer is merged into a single item.
|
||||||
|
|
||||||
Referring to the diagram above, the 18, 3, and 27 byte items are sequentially written to the
|
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**.
|
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
|
Wrap around
|
||||||
^^^^^^^^^^^
|
^^^^^^^^^^^
|
||||||
|
|
||||||
|
@ -207,15 +281,15 @@ with **56 bytes of free space that wraps around** and a sent item of **28 bytes*
|
||||||
|
|
||||||
No-split buffers will **only store an item in continuous free space and will not split
|
No-split buffers will **only store an item in continuous free space and will not split
|
||||||
an item under any circumstances**. When the free space at the tail of the buffer is insufficient
|
an item under any circumstances**. When the free space at the tail of the buffer is insufficient
|
||||||
to completely store the item and its header, the free space at the tail will be **marked as dummy data**.
|
to completely store the item and its header, the free space at the tail will be **marked as dummy data**.
|
||||||
The buffer will then wrap around and store the item in the free space at the head of the buffer.
|
The buffer will then wrap around and store the item in the free space at the head of the buffer.
|
||||||
|
|
||||||
Referring to the diagram above, the 16 bytes of free space at the tail of the buffer is
|
Referring to the diagram above, the 16 bytes of free space at the tail of the buffer is
|
||||||
insufficient to store the 28 byte item. Therefore the 16 bytes is marked as dummy data and
|
insufficient to store the 28 byte item. Therefore the 16 bytes is marked as dummy data and
|
||||||
the item is written to the free space at the head of the buffer instead.
|
the item is written to the free space at the head of the buffer instead.
|
||||||
|
|
||||||
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_wrap_allow_split.diag
|
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_wrap_allow_split.diag
|
||||||
:caption: Wrap around in allow-split buffers
|
:caption: Wrap around in allow-split buffers
|
||||||
:align: center
|
:align: center
|
||||||
|
|
||||||
Allow-split buffers will attempt to **split the item into two parts** when the free space at the tail
|
Allow-split buffers will attempt to **split the item into two parts** when the free space at the tail
|
||||||
|
@ -232,17 +306,17 @@ as two parts to the buffer.
|
||||||
parts of a split item in a thread safe manner.
|
parts of a split item in a thread safe manner.
|
||||||
|
|
||||||
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_wrap_byte_buf.diag
|
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_wrap_byte_buf.diag
|
||||||
:caption: Wrap around in byte buffers
|
:caption: Wrap around in byte buffers
|
||||||
:align: center
|
:align: center
|
||||||
|
|
||||||
Byte buffers will **store as much data as possible into the free space at the tail of buffer**. The remaining
|
Byte buffers will **store as much data as possible into the free space at the tail of buffer**. The remaining
|
||||||
data will then be stored in the free space at the head of the buffer. No overhead is incurred when wrapping
|
data will then be stored in the free space at the head of the buffer. No overhead is incurred when wrapping
|
||||||
around in byte buffers.
|
around in byte buffers.
|
||||||
|
|
||||||
Referring to the diagram above, the 16 bytes of free space at the tail of the buffer is insufficient to
|
Referring to the diagram above, the 16 bytes of free space at the tail of the buffer is insufficient to
|
||||||
completely store the 28 bytes of data. Therefore the 16 bytes of free space is filled with data, and the
|
completely store the 28 bytes of data. Therefore the 16 bytes of free space is filled with data, and the
|
||||||
remaining 12 bytes are written to the free space at the head of the buffer. The buffer now contains
|
remaining 12 bytes are written to the free space at the head of the buffer. The buffer now contains
|
||||||
data in two separate continuous parts, and each part continuous will be treated as a separate item by the
|
data in two separate continuous parts, and each part continuous will be treated as a separate item by the
|
||||||
byte buffer.
|
byte buffer.
|
||||||
|
|
||||||
Retrieving/Returning
|
Retrieving/Returning
|
||||||
|
@ -255,10 +329,10 @@ byte buffers in retrieving and returning data.
|
||||||
:caption: Retrieving/Returning items in no-split/allow-split ring buffers
|
:caption: Retrieving/Returning items in no-split/allow-split ring buffers
|
||||||
:align: center
|
:align: center
|
||||||
|
|
||||||
Items in no-split/allow-split buffers are **retrieved in strict FIFO order** and **must be returned**
|
Items in no-split/allow-split buffers are **retrieved in strict FIFO order** and **must be returned**
|
||||||
for the occupied space to be freed. Multiple items can be retrieved before returning, and the items
|
for the occupied space to be freed. Multiple items can be retrieved before returning, and the items
|
||||||
do not necessarily need to be returned in the order they were retrieved. However the freeing of space
|
do not necessarily need to be returned in the order they were retrieved. However the freeing of space
|
||||||
must occur in FIFO order, therefore not returning the earliest retrieved item will prevent the space
|
must occur in FIFO order, therefore not returning the earliest retrieved item will prevent the space
|
||||||
of subsequent items from being freed.
|
of subsequent items from being freed.
|
||||||
|
|
||||||
Referring to the diagram above, the **16, 20, and 8 byte items are retrieved in FIFO order**. However the items
|
Referring to the diagram above, the **16, 20, and 8 byte items are retrieved in FIFO order**. However the items
|
||||||
|
@ -270,13 +344,13 @@ are not returned in they were retrieved (20, 8, 16). As such, the space is not f
|
||||||
:align: center
|
:align: center
|
||||||
|
|
||||||
Byte buffers **do not allow multiple retrievals before returning** (every retrieval must be followed by a return
|
Byte buffers **do not allow multiple retrievals before returning** (every retrieval must be followed by a return
|
||||||
before another retrieval is permitted). When using :cpp:func:`xRingbufferReceive` or
|
before another retrieval is permitted). When using :cpp:func:`xRingbufferReceive` or
|
||||||
:cpp:func:`xRingbufferReceiveFromISR`, all continuous stored data will be retrieved. :cpp:func:`xRingbufferReceiveUpTo`
|
:cpp:func:`xRingbufferReceiveFromISR`, all continuous stored data will be retrieved. :cpp:func:`xRingbufferReceiveUpTo`
|
||||||
or :cpp:func:`xRingbufferReceiveUpToFromISR` can be used to restrict the maximum number of bytes retrieved. Since
|
or :cpp:func:`xRingbufferReceiveUpToFromISR` can be used to restrict the maximum number of bytes retrieved. Since
|
||||||
every retrieval must be followed by a return, the space will be freed as soon as the data is returned.
|
every retrieval must be followed by a return, the space will be freed as soon as the data is returned.
|
||||||
|
|
||||||
Referring to the diagram above, the 38 bytes of continuous stored data at the tail of the buffer is retrieved,
|
Referring to the diagram above, the 38 bytes of continuous stored data at the tail of the buffer is retrieved,
|
||||||
returned, and freed. The next call to :cpp:func:`xRingbufferReceive` or :cpp:func:`xRingbufferReceiveFromISR`
|
returned, and freed. The next call to :cpp:func:`xRingbufferReceive` or :cpp:func:`xRingbufferReceiveFromISR`
|
||||||
then wraps around and does the same to the 30 bytes of continuous stored data at the head of the buffer.
|
then wraps around and does the same to the 30 bytes of continuous stored data at the head of the buffer.
|
||||||
|
|
||||||
Ring Buffers with Queue Sets
|
Ring Buffers with Queue Sets
|
||||||
|
@ -331,7 +405,7 @@ The :cpp:func:`xRingbufferCreateStatic` can be used to create ring buffers with
|
||||||
- The ring buffer's data structure of type :cpp:type:`StaticRingbuffer_t`
|
- The ring buffer's data structure of type :cpp:type:`StaticRingbuffer_t`
|
||||||
- The ring buffer's storage area of size ``xBufferSize``. Note that ``xBufferSize`` must be 32-bit aligned for no-split/allow-split buffers.
|
- The ring buffer's storage area of size ``xBufferSize``. Note that ``xBufferSize`` must be 32-bit aligned for no-split/allow-split buffers.
|
||||||
|
|
||||||
The manner in which these blocks are allocated will depend on the users requirements (e.g. all blocks being statically declared, or dynamically allocated with specific capabilities such as external RAM).
|
The manner in which these blocks are allocated will depend on the users requirements (e.g. all blocks being statically declared, or dynamically allocated with specific capabilities such as external RAM).
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
The :ref:`CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION` option must be enabled in `menuconfig` for statically allocated ring buffers to be available.
|
The :ref:`CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION` option must be enabled in `menuconfig` for statically allocated ring buffers to be available.
|
||||||
|
@ -375,20 +449,20 @@ Ring Buffer API Reference
|
||||||
.. note::
|
.. note::
|
||||||
Ideally, ring buffers can be used with multiple tasks in an SMP fashion where the **highest
|
Ideally, ring buffers can be used with multiple tasks in an SMP fashion where the **highest
|
||||||
priority task will always be serviced first.** However due to the usage of binary semaphores
|
priority task will always be serviced first.** However due to the usage of binary semaphores
|
||||||
in the ring buffer's underlying implementation, priority inversion may occur under very
|
in the ring buffer's underlying implementation, priority inversion may occur under very
|
||||||
specific circumstances.
|
specific circumstances.
|
||||||
|
|
||||||
The ring buffer governs sending by a binary semaphore which is given whenever space is
|
The ring buffer governs sending by a binary semaphore which is given whenever space is
|
||||||
freed on the ring buffer. The highest priority task waiting to send will repeatedly take
|
freed on the ring buffer. The highest priority task waiting to send will repeatedly take
|
||||||
the semaphore until sufficient free space becomes available or until it times out. Ideally
|
the semaphore until sufficient free space becomes available or until it times out. Ideally
|
||||||
this should prevent any lower priority tasks from being serviced as the semaphore should
|
this should prevent any lower priority tasks from being serviced as the semaphore should
|
||||||
always be given to the highest priority task.
|
always be given to the highest priority task.
|
||||||
|
|
||||||
However in between iterations of acquiring the semaphore, there is a **gap in the critical
|
However in between iterations of acquiring the semaphore, there is a **gap in the critical
|
||||||
section** which may permit another task (on the other core or with an even higher priority) to
|
section** which may permit another task (on the other core or with an even higher priority) to
|
||||||
free some space on the ring buffer and as a result give the semaphore. Therefore the semaphore
|
free some space on the ring buffer and as a result give the semaphore. Therefore the semaphore
|
||||||
will be given before the highest priority task can re-acquire the semaphore. This will result
|
will be given before the highest priority task can re-acquire the semaphore. This will result
|
||||||
in the **semaphore being acquired by the second highest priority task** waiting to send, hence
|
in the **semaphore being acquired by the second highest priority task** waiting to send, hence
|
||||||
causing priority inversion.
|
causing priority inversion.
|
||||||
|
|
||||||
This side effect will not affect ring buffer performance drastically given if the number
|
This side effect will not affect ring buffer performance drastically given if the number
|
||||||
|
@ -403,9 +477,9 @@ Ring Buffer API Reference
|
||||||
Hooks
|
Hooks
|
||||||
-----
|
-----
|
||||||
|
|
||||||
FreeRTOS consists of Idle Hooks and Tick Hooks which allow for application
|
FreeRTOS consists of Idle Hooks and Tick Hooks which allow for application
|
||||||
specific functionality to be added to the Idle Task and Tick Interrupt.
|
specific functionality to be added to the Idle Task and Tick Interrupt.
|
||||||
ESP-IDF provides its own Idle and Tick Hook API in addition to the hooks
|
ESP-IDF provides its own Idle and Tick Hook API in addition to the hooks
|
||||||
provided by Vanilla FreeRTOS. ESP-IDF hooks have the added benefit of
|
provided by Vanilla FreeRTOS. ESP-IDF hooks have the added benefit of
|
||||||
being run time configurable and asymmetrical.
|
being run time configurable and asymmetrical.
|
||||||
|
|
||||||
|
@ -416,9 +490,9 @@ Idle and Tick Hooks in vanilla FreeRTOS are implemented by the user
|
||||||
defining the functions ``vApplicationIdleHook()`` and ``vApplicationTickHook()``
|
defining the functions ``vApplicationIdleHook()`` and ``vApplicationTickHook()``
|
||||||
respectively somewhere in the application. Vanilla FreeRTOS will run the user
|
respectively somewhere in the application. Vanilla FreeRTOS will run the user
|
||||||
defined Idle Hook and Tick Hook on every iteration of the Idle Task and Tick
|
defined Idle Hook and Tick Hook on every iteration of the Idle Task and Tick
|
||||||
Interrupt respectively.
|
Interrupt respectively.
|
||||||
|
|
||||||
Vanilla FreeRTOS hooks are referred to as **Legacy Hooks** in ESP-IDF FreeRTOS.
|
Vanilla FreeRTOS hooks are referred to as **Legacy Hooks** in ESP-IDF FreeRTOS.
|
||||||
To enable legacy hooks, :ref:`CONFIG_FREERTOS_LEGACY_HOOKS` should be enabled
|
To enable legacy hooks, :ref:`CONFIG_FREERTOS_LEGACY_HOOKS` should be enabled
|
||||||
in :doc:`project configuration menu </api-reference/kconfig>`.
|
in :doc:`project configuration menu </api-reference/kconfig>`.
|
||||||
|
|
||||||
|
@ -433,9 +507,9 @@ Due to the the dual core nature of the ESP32, it may be necessary for some
|
||||||
applications to have separate hooks for each core. Furthermore, it may
|
applications to have separate hooks for each core. Furthermore, it may
|
||||||
be necessary for the Idle Tasks or Tick Interrupts to execute multiple hooks
|
be necessary for the Idle Tasks or Tick Interrupts to execute multiple hooks
|
||||||
that are configurable at run time. Therefore the ESP-IDF provides it's own hooks
|
that are configurable at run time. Therefore the ESP-IDF provides it's own hooks
|
||||||
API in addition to the legacy hooks provided by Vanilla FreeRTOS.
|
API in addition to the legacy hooks provided by Vanilla FreeRTOS.
|
||||||
|
|
||||||
The ESP-IDF tick/idle hooks are registered at run time, and each tick/idle hook
|
The ESP-IDF tick/idle hooks are registered at run time, and each tick/idle hook
|
||||||
must be registered to a specific CPU. When the idle task runs/tick Interrupt
|
must be registered to a specific CPU. When the idle task runs/tick Interrupt
|
||||||
occurs on a particular CPU, the CPU will run each of its registered idle/tick hooks
|
occurs on a particular CPU, the CPU will run each of its registered idle/tick hooks
|
||||||
in turn.
|
in turn.
|
||||||
|
|
Loading…
Reference in a new issue