mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-03 22:08:28 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			537 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			537 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
FreeRTOS Additions
 | 
						|
==================
 | 
						|
 | 
						|
Overview
 | 
						|
--------
 | 
						|
 | 
						|
ESP-IDF FreeRTOS is based on the Xtensa port of FreeRTOS v10.2.0 with significant modifications
 | 
						|
for SMP compatibility (see :doc:`ESP-IDF FreeRTOS SMP Changes<../../api-guides/freertos-smp>`).
 | 
						|
However various features specific to ESP-IDF FreeRTOS have been added. The features are as follows:
 | 
						|
 | 
						|
:ref:`ring-buffers`: Ring buffers were added to provide a form of buffer that could accept
 | 
						|
entries of arbitrary lengths.
 | 
						|
 | 
						|
:ref:`hooks`: ESP-IDF FreeRTOS hooks provides support for registering extra Idle and
 | 
						|
Tick hooks at run time. Moreover, the hooks can be asymmetric amongst both CPUs.
 | 
						|
 | 
						|
:ref:`component-specific-properties`: Currently added only one component specific property `ORIG_INCLUDE_PATH`.
 | 
						|
 | 
						|
 | 
						|
.. _ring-buffers:
 | 
						|
 | 
						|
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. The ring buffer provides API 
 | 
						|
to send an item, or to allocate space for an item in the ring buffer to be filled manually by the user. 
 | 
						|
For efficiency reasons,
 | 
						|
**items are always retrieved from the ring buffer by reference**. As a result, all retrieved
 | 
						|
items *must also be returned* to the ring buffer by using :cpp:func:`vRingbufferReturnItem` or :cpp:func:`vRingbufferReturnItemFromISR`, 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. *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
 | 
						|
can return an item in two parts when retrieving.
 | 
						|
 | 
						|
**Byte buffers** do not store data as separate items. All data is stored as a sequence of bytes,
 | 
						|
and any number of bytes and be sent or retrieved each time. Use byte buffers when separate items
 | 
						|
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. 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**.
 | 
						|
    Item sizes will also be rounded up to a 32-bit aligned size (multiple of 4 bytes), however the true
 | 
						|
    item size is recorded within the header. The sizes of no-split/allow-split buffers will also
 | 
						|
    be rounded up when created.
 | 
						|
 | 
						|
Usage
 | 
						|
^^^^^
 | 
						|
 | 
						|
The following example demonstrates the usage of :cpp:func:`xRingbufferCreate`
 | 
						|
and :cpp:func:`xRingbufferSend` to create a ring buffer then send an item to it.
 | 
						|
 | 
						|
.. code-block:: c
 | 
						|
 | 
						|
    #include "freertos/ringbuf.h"
 | 
						|
    static char tx_item[] = "test_item";
 | 
						|
 | 
						|
    ...
 | 
						|
 | 
						|
        //Create ring buffer
 | 
						|
        RingbufHandle_t buf_handle;
 | 
						|
        buf_handle = xRingbufferCreate(1028, RINGBUF_TYPE_NOSPLIT);
 | 
						|
        if (buf_handle == NULL) {
 | 
						|
            printf("Failed to create ring buffer\n");
 | 
						|
        }
 | 
						|
 | 
						|
        //Send an item
 | 
						|
        UBaseType_t res =  xRingbufferSend(buf_handle, tx_item, sizeof(tx_item), pdMS_TO_TICKS(1000));
 | 
						|
        if (res != pdTRUE) {
 | 
						|
            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`
 | 
						|
 | 
						|
.. code-block:: c
 | 
						|
 | 
						|
    ...
 | 
						|
 | 
						|
        //Receive an item from no-split ring buffer
 | 
						|
        size_t item_size;
 | 
						|
        char *item = (char *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(1000));
 | 
						|
 | 
						|
        //Check received item
 | 
						|
        if (item != NULL) {
 | 
						|
            //Print item
 | 
						|
            for (int i = 0; i < item_size; i++) {
 | 
						|
                printf("%c", item[i]);
 | 
						|
            }
 | 
						|
            printf("\n");
 | 
						|
            //Return Item
 | 
						|
            vRingbufferReturnItem(buf_handle, (void *)item);
 | 
						|
        } else {
 | 
						|
            //Failed to receive item
 | 
						|
            printf("Failed to receive item\n");
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
The following example demonstrates retrieving and returning an item from an **allow-split ring buffer**
 | 
						|
using :cpp:func:`xRingbufferReceiveSplit` and :cpp:func:`vRingbufferReturnItem`
 | 
						|
 | 
						|
.. code-block:: c
 | 
						|
 | 
						|
    ...
 | 
						|
 | 
						|
        //Receive an item from allow-split ring buffer
 | 
						|
        size_t item_size1, item_size2;
 | 
						|
        char *item1, *item2;
 | 
						|
        BaseType_t ret = xRingbufferReceiveSplit(buf_handle, (void **)&item1, (void **)&item2, &item_size1, &item_size2, pdMS_TO_TICKS(1000));
 | 
						|
 | 
						|
        //Check received item
 | 
						|
        if (ret == pdTRUE && item1 != NULL) {
 | 
						|
            for (int i = 0; i < item_size1; i++) {
 | 
						|
                printf("%c", item1[i]);
 | 
						|
            }
 | 
						|
            vRingbufferReturnItem(buf_handle, (void *)item1);
 | 
						|
            //Check if item was split
 | 
						|
            if (item2 != NULL) {
 | 
						|
                for (int i = 0; i < item_size2; i++) {
 | 
						|
                    printf("%c", item2[i]);
 | 
						|
                }
 | 
						|
                vRingbufferReturnItem(buf_handle, (void *)item2);
 | 
						|
            }
 | 
						|
            printf("\n");
 | 
						|
        } else {
 | 
						|
            //Failed to receive item
 | 
						|
            printf("Failed to receive item\n");
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
The following example demonstrates retrieving and returning an item from a **byte buffer**
 | 
						|
using :cpp:func:`xRingbufferReceiveUpTo` and :cpp:func:`vRingbufferReturnItem`
 | 
						|
 | 
						|
.. code-block:: c
 | 
						|
 | 
						|
    ...
 | 
						|
 | 
						|
        //Receive data from byte buffer
 | 
						|
        size_t item_size;
 | 
						|
        char *item = (char *)xRingbufferReceiveUpTo(buf_handle, &item_size, pdMS_TO_TICKS(1000), sizeof(tx_item));
 | 
						|
 | 
						|
        //Check received data
 | 
						|
        if (item != NULL) {
 | 
						|
            //Print item
 | 
						|
            for (int i = 0; i < item_size; i++) {
 | 
						|
                printf("%c", item[i]);
 | 
						|
            }
 | 
						|
            printf("\n");
 | 
						|
            //Return Item
 | 
						|
            vRingbufferReturnItem(buf_handle, (void *)item);
 | 
						|
        } else {
 | 
						|
            //Failed to receive item
 | 
						|
            printf("Failed to receive item\n");
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
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`
 | 
						|
 | 
						|
.. note::
 | 
						|
 | 
						|
    Two calls to RingbufferReceive[UpTo][FromISR]() are required if the bytes wraps around the end of the ring buffer.
 | 
						|
 | 
						|
Sending to Ring Buffer
 | 
						|
^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
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
 | 
						|
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
 | 
						|
    :caption: Sending items to no-split/allow-split ring buffers
 | 
						|
    :align: center
 | 
						|
 | 
						|
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
 | 
						|
32-bit alignment. However the true size of the item is recorded inside the header which will be
 | 
						|
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**
 | 
						|
respectively. An 8 byte header is then added in front of each item.
 | 
						|
 | 
						|
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_send_byte_buf.diag
 | 
						|
    :caption: Sending items to byte buffers
 | 
						|
    :align: center
 | 
						|
 | 
						|
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.
 | 
						|
 | 
						|
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
 | 
						|
^^^^^^^^^^^
 | 
						|
 | 
						|
The following diagrams illustrate the differences between no-split, allow-split, and byte
 | 
						|
buffers when a sent item requires a wrap around. The diagrams assumes a buffer of **128 bytes**
 | 
						|
with **56 bytes of free space that wraps around** and a sent item of **28 bytes**.
 | 
						|
 | 
						|
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_wrap_no_split.diag
 | 
						|
    :caption: Wrap around in no-split buffers
 | 
						|
    :align: center
 | 
						|
 | 
						|
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
 | 
						|
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.
 | 
						|
 | 
						|
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
 | 
						|
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
 | 
						|
    :caption: Wrap around in allow-split buffers
 | 
						|
    :align: center
 | 
						|
 | 
						|
Allow-split buffers will attempt to **split the item into two parts** when the free space at the tail
 | 
						|
of the buffer is insufficient to store the item data and its header. Both parts of the
 | 
						|
split item will have their own headers (therefore incurring an extra 8 bytes of overhead).
 | 
						|
 | 
						|
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 item is split into two parts (8 and 20 bytes) and written
 | 
						|
as two parts to the buffer.
 | 
						|
 | 
						|
.. note::
 | 
						|
    Allow-split buffers treats the both parts of the split item as two separate items, therefore call
 | 
						|
    :cpp:func:`xRingbufferReceiveSplit` instead of :cpp:func:`xRingbufferReceive` to receive both
 | 
						|
    parts of a split item in a thread safe manner.
 | 
						|
 | 
						|
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_wrap_byte_buf.diag
 | 
						|
    :caption: Wrap around in byte buffers
 | 
						|
    :align: center
 | 
						|
 | 
						|
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
 | 
						|
around in byte buffers.
 | 
						|
 | 
						|
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
 | 
						|
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
 | 
						|
byte buffer.
 | 
						|
 | 
						|
Retrieving/Returning
 | 
						|
^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
The following diagrams illustrates the differences between no-split/allow-split and
 | 
						|
byte buffers in retrieving and returning data.
 | 
						|
 | 
						|
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_read_ret_non_byte_buf.diag
 | 
						|
    :caption: Retrieving/Returning items in no-split/allow-split ring buffers
 | 
						|
    :align: center
 | 
						|
 | 
						|
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
 | 
						|
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
 | 
						|
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
 | 
						|
are not returned in they were retrieved (20, 8, 16). As such, the space is not freed until the first item
 | 
						|
(16 byte) is returned.
 | 
						|
 | 
						|
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_read_ret_byte_buf.diag
 | 
						|
    :caption: Retrieving/Returning data in byte buffers
 | 
						|
    :align: center
 | 
						|
 | 
						|
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
 | 
						|
: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
 | 
						|
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,
 | 
						|
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.
 | 
						|
 | 
						|
Ring Buffers with Queue Sets
 | 
						|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
Ring buffers can be added to FreeRTOS queue sets using :cpp:func:`xRingbufferAddToQueueSetRead` such that every
 | 
						|
time a ring buffer receives an item or data, the queue set is notified. Once added to a queue set, every
 | 
						|
attempt to retrieve an item from a ring buffer should be preceded by a call to :cpp:func:`xQueueSelectFromSet`.
 | 
						|
To check whether the selected queue set member is the ring buffer, call :cpp:func:`xRingbufferCanRead`.
 | 
						|
 | 
						|
The following example demonstrates queue set usage with ring buffers.
 | 
						|
 | 
						|
.. code-block:: c
 | 
						|
 | 
						|
    #include "freertos/queue.h"
 | 
						|
    #include "freertos/ringbuf.h"
 | 
						|
 | 
						|
    ...
 | 
						|
 | 
						|
        //Create ring buffer and queue set
 | 
						|
        RingbufHandle_t buf_handle = xRingbufferCreate(1028, RINGBUF_TYPE_NOSPLIT);
 | 
						|
        QueueSetHandle_t queue_set = xQueueCreateSet(3);
 | 
						|
 | 
						|
        //Add ring buffer to queue set
 | 
						|
        if (xRingbufferAddToQueueSetRead(buf_handle, queue_set) != pdTRUE) {
 | 
						|
            printf("Failed to add to queue set\n");
 | 
						|
        }
 | 
						|
 | 
						|
    ...
 | 
						|
 | 
						|
        //Block on queue set
 | 
						|
        xQueueSetMemberHandle member = xQueueSelectFromSet(queue_set, pdMS_TO_TICKS(1000));
 | 
						|
 | 
						|
        //Check if member is ring buffer
 | 
						|
        if (member != NULL && xRingbufferCanRead(buf_handle, member) == pdTRUE) {
 | 
						|
            //Member is ring buffer, receive item from ring buffer
 | 
						|
            size_t item_size;
 | 
						|
            char *item = (char *)xRingbufferReceive(buf_handle, &item_size, 0);
 | 
						|
 | 
						|
            //Handle item
 | 
						|
            ...
 | 
						|
 | 
						|
        } else {
 | 
						|
            ...
 | 
						|
        }
 | 
						|
 | 
						|
Ring Buffers with Static Allocation
 | 
						|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
The :cpp:func:`xRingbufferCreateStatic` can be used to create ring buffers with specific memory requirements (such as a ring buffer being allocated in external RAM). All blocks of memory used by a ring buffer must be manually allocated beforehand then passed to the :cpp:func:`xRingbufferCreateStatic` to be initialized as a ring buffer. These blocks include the following:
 | 
						|
 | 
						|
- 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 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::
 | 
						|
    When deleting a ring buffer created via :cpp:func:`xRingbufferCreateStatic`,
 | 
						|
    the function :cpp:func:`vRingbufferDelete` will not free any of the memory blocks. This must be done manually by the user after :cpp:func:`vRingbufferDelete` is called.
 | 
						|
 | 
						|
The code snippet below demonstrates a ring buffer being allocated entirely in external RAM.
 | 
						|
 | 
						|
.. code-block:: c
 | 
						|
 | 
						|
    #include "freertos/ringbuf.h"
 | 
						|
    #include "freertos/semphr.h"
 | 
						|
    #include "esp_heap_caps.h"
 | 
						|
 | 
						|
    #define BUFFER_SIZE     400      //32-bit aligned size
 | 
						|
    #define BUFFER_TYPE     RINGBUF_TYPE_NOSPLIT
 | 
						|
    ...
 | 
						|
 | 
						|
    //Allocate ring buffer data structure and storage area into external RAM
 | 
						|
    StaticRingbuffer_t *buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM);
 | 
						|
    uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*BUFFER_SIZE, MALLOC_CAP_SPIRAM);
 | 
						|
 | 
						|
    //Create a ring buffer with manually allocated memory
 | 
						|
    RingbufHandle_t handle = xRingbufferCreateStatic(BUFFER_SIZE, BUFFER_TYPE, buffer_storage, buffer_struct);
 | 
						|
 | 
						|
    ...
 | 
						|
 | 
						|
    //Delete the ring buffer after used
 | 
						|
    vRingbufferDelete(handle);
 | 
						|
 | 
						|
    //Manually free all blocks of memory
 | 
						|
    free(buffer_struct);
 | 
						|
    free(buffer_storage);
 | 
						|
 | 
						|
 | 
						|
Ring Buffer API Reference
 | 
						|
-------------------------
 | 
						|
 | 
						|
.. note::
 | 
						|
    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
 | 
						|
    in the ring buffer's underlying implementation, priority inversion may occur under very
 | 
						|
    specific circumstances.
 | 
						|
 | 
						|
    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
 | 
						|
    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
 | 
						|
    always be given to the highest priority task.
 | 
						|
 | 
						|
    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
 | 
						|
    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
 | 
						|
    in the **semaphore being acquired by the second highest priority task** waiting to send, hence
 | 
						|
    causing priority inversion.
 | 
						|
 | 
						|
    This side effect will not affect ring buffer performance drastically given if the number
 | 
						|
    of tasks using the ring buffer simultaneously is low, and the ring buffer is not operating
 | 
						|
    near maximum capacity.
 | 
						|
 | 
						|
.. include-build-file:: inc/ringbuf.inc
 | 
						|
 | 
						|
 | 
						|
.. _hooks:
 | 
						|
 | 
						|
Hooks
 | 
						|
-----
 | 
						|
 | 
						|
FreeRTOS consists of Idle Hooks and Tick Hooks which allow for application
 | 
						|
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
 | 
						|
provided by Vanilla FreeRTOS. ESP-IDF hooks have the added benefit of
 | 
						|
being run time configurable and asymmetrical.
 | 
						|
 | 
						|
Vanilla FreeRTOS Hooks
 | 
						|
^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
Idle and Tick Hooks in vanilla FreeRTOS are implemented by the user
 | 
						|
defining the functions ``vApplicationIdleHook()`` and  ``vApplicationTickHook()``
 | 
						|
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
 | 
						|
Interrupt respectively.
 | 
						|
 | 
						|
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
 | 
						|
in :doc:`project configuration menu </api-reference/kconfig>`.
 | 
						|
 | 
						|
Due to vanilla FreeRTOS being designed for single core, ``vApplicationIdleHook()``
 | 
						|
and ``vApplicationTickHook()`` can only be defined once. However, the ESP32 is dual core
 | 
						|
in nature, therefore same Idle Hook and Tick Hook are used for both cores (in other words,
 | 
						|
the hooks are symmetrical for both cores).
 | 
						|
 | 
						|
In a dual core system, ``vApplicationTickHook()`` must be located in IRAM (for example
 | 
						|
by adding the IRAM_ATTR attribute).
 | 
						|
 | 
						|
ESP-IDF Idle and Tick Hooks
 | 
						|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
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
 | 
						|
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
 | 
						|
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
 | 
						|
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
 | 
						|
in turn.
 | 
						|
 | 
						|
 | 
						|
Hooks API Reference
 | 
						|
-------------------
 | 
						|
 | 
						|
.. include-build-file:: inc/esp_freertos_hooks.inc
 | 
						|
 | 
						|
 | 
						|
.. _component-specific-properties:
 | 
						|
 | 
						|
Component Specific Properties
 | 
						|
-----------------------------
 | 
						|
 | 
						|
Besides standart component variables that could be gotten with basic cmake build properties FreeRTOS component also provides an arguments (only one so far) for simpler integration with other modules:
 | 
						|
 | 
						|
- `ORIG_INCLUDE_PATH` -  contains an absolute path to freertos root include folder. Thus instead of `#include "freertos/FreeRTOS.h"` you can refer to headers directly: `#include "FreeRTOS.h"`.
 |