freertos: Add task creation with caps functions

This commit adds the corresponding CreateWithCaps functions for tasks:

- xTaskCreatePinnedToCoreWithCaps()
- xTaskCreateWithCaps()
- vTaskDeleteWithCaps()

Documentation and migraiton guide have been updated accordingly.

Closes https://github.com/espressif/esp-idf/issues/11216
pull/11519/head
Darian Leung 2023-04-13 16:30:49 +08:00
rodzic 4a35536244
commit ad5044c5f6
6 zmienionych plików z 213 dodań i 6 usunięć

Wyświetl plik

@ -28,6 +28,73 @@
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
/* ---------------------------------- Tasks --------------------------------- */
BaseType_t xTaskCreatePinnedToCoreWithCaps( TaskFunction_t pvTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pvCreatedTask,
const BaseType_t xCoreID,
UBaseType_t uxMemoryCaps )
{
TaskHandle_t xHandle;
StaticTask_t * pxTaskBuffer;
StackType_t * pxStack;
/* Allocate memory for the task's TCB. We use pvPortMalloc() here as the
* TCB must be in internal memory. */
pxTaskBuffer = pvPortMalloc( sizeof( StaticTask_t ) );
/* Allocate memory for the task's stack using the provided memory caps
* */
pxStack = heap_caps_malloc( usStackDepth, ( uint32_t ) uxMemoryCaps );
if( ( pxTaskBuffer == NULL ) || ( pxStack == NULL ) )
{
goto err;
}
/* Create the task using static creation API*/
xHandle = xTaskCreateStaticPinnedToCore( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxStack, pxTaskBuffer, xCoreID );
if( xHandle == NULL )
{
/* Failed to create task */
goto err;
}
else if( pvCreatedTask != NULL )
{
/* Task created successfully. Return the task handle */
*pvCreatedTask = xHandle;
}
return pdPASS;
err:
heap_caps_free( pxStack );
vPortFree( pxTaskBuffer );
return pdFAIL;
}
void vTaskDeleteWithCaps( TaskHandle_t xTaskToDelete )
{
BaseType_t xResult;
StaticTask_t * pxTaskBuffer;
StackType_t * puxStackBuffer;
xResult = xTaskGetStaticBuffers( xTaskToDelete, &puxStackBuffer, &pxTaskBuffer );
configASSERT( xResult == pdTRUE );
/* Delete the task */
vTaskDelete( xTaskToDelete );
/* Free the memory buffers */
heap_caps_free( puxStackBuffer );
vPortFree( pxTaskBuffer );
}
/* ---------------------------------- Queue --------------------------------- */
QueueHandle_t xQueueCreateWithCaps( UBaseType_t uxQueueLength,

Wyświetl plik

@ -201,7 +201,89 @@
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
/* ---------------------- Queue ------------------------- */
/* ---------------------------------- Tasks --------------------------------- */
/**
* @brief Creates a pinned task where its stack has specific memory capabilities
*
* This function is similar to xTaskCreatePinnedToCore(), except that it allows
* the memory allocated for the task's stack to have specific capabilities
* (e.g., MALLOC_CAP_SPIRAM).
*
* However, the specified capabilities will NOT apply to the task's TCB as a TCB
* must always be in internal RAM.
*
* @param pvTaskCode Pointer to the task entry function
* @param pcName A descriptive name for the task
* @param usStackDepth The size of the task stack specified as the number of
* bytes
* @param pvParameters Pointer that will be used as the parameter for the task
* being created.
* @param uxPriority The priority at which the task should run.
* @param pvCreatedTask Used to pass back a handle by which the created task can
* be referenced.
* @param xCoreID Core to which the task is pinned to, or tskNO_AFFINITY if
* unpinned.
* @param uxMemoryCaps Memory capabilities of the task stack's memory (see
* esp_heap_caps.h)
* @return pdPASS if the task was successfully created and added to a ready
* list, otherwise an error code defined in the file projdefs.h
*/
BaseType_t xTaskCreatePinnedToCoreWithCaps( TaskFunction_t pvTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pvCreatedTask,
const BaseType_t xCoreID,
UBaseType_t uxMemoryCaps );
/**
* @brief Creates a task where its stack has specific memory capabilities
*
* This function is similar to xTaskCreate(), except that it allows the memory
* allocated for the task's stack to have specific capabilities (e.g.,
* MALLOC_CAP_SPIRAM).
*
* However, the specified capabilities will NOT apply to the task's TCB as a TCB
* must always be in internal RAM.
*
* @note A task created using this function must only be deleted using
* vTaskDeleteWithCaps()
* @param pvTaskCode Pointer to the task entry function
* @param pcName A descriptive name for the task
* @param usStackDepth The size of the task stack specified as the number of
* bytes
* @param pvParameters Pointer that will be used as the parameter for the task
* being created.
* @param uxPriority The priority at which the task should run.
* @param pvCreatedTask Used to pass back a handle by which the created task can
* be referenced.
* @param uxMemoryCaps Memory capabilities of the task stack's memory (see
* esp_heap_caps.h)
* @return pdPASS if the task was successfully created and added to a ready
* list, otherwise an error code defined in the file projdefs.h
*/
static inline BaseType_t xTaskCreateWithCaps( TaskFunction_t pvTaskCode,
const char * const pcName,
configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * pvCreatedTask,
UBaseType_t uxMemoryCaps )
{
return xTaskCreatePinnedToCoreWithCaps( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask, tskNO_AFFINITY, uxMemoryCaps );
}
/**
* @brief Deletes a task previously created using xTaskCreateWithCaps() or
* xTaskCreatePinnedToCoreWithCaps()
*
* @param xTaskToDelete A handle to the task to be deleted
*/
void vTaskDeleteWithCaps( TaskHandle_t xTaskToDelete );
/* ---------------------------------- Queue --------------------------------- */
/**
* @brief Creates a queue with specific memory capabilities
@ -229,7 +311,7 @@
*/
void vQueueDeleteWithCaps( QueueHandle_t xQueue );
/* -------------------- Semaphore ----------------------- */
/* -------------------------------- Semaphore ------------------------------- */
/** @cond */ /* Doxygen command to hide this from docs */
SemaphoreHandle_t xSemaphoreCreateGenericWithCaps( UBaseType_t uxMaxCount,
@ -323,7 +405,7 @@
*/
void vSemaphoreDeleteWithCaps( SemaphoreHandle_t xSemaphore );
/* ------------ Stream & Message Buffers ---------------- */
/* ------------------------ Stream & Message Buffers ------------------------ */
/** @cond */ /* Doxygen command to hide this from docs */
StreamBufferHandle_t xStreamBufferGenericCreateWithCaps( size_t xBufferSizeBytes,
@ -402,7 +484,7 @@
vStreamBufferGenericDeleteWithCaps( ( StreamBufferHandle_t ) xMessageBuffer, pdTRUE );
}
/* ------------------ Event Groups ---------------------- */
/* ------------------------------ Event Groups ------------------------------ */
/**
* @brief Creates an event group with specific memory capabilities
@ -430,5 +512,5 @@
#endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
#ifdef __cplusplus
}
}
#endif

Wyświetl plik

@ -14,6 +14,7 @@
#include "freertos/idf_additions.h"
#include "esp_memory_utils.h"
#include "unity.h"
#include "test_utils.h"
/*
Test ...Create...WithCaps() functions
@ -33,6 +34,31 @@ Expected:
#define OBJECT_MEMORY_CAPS (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
static void task_with_caps(void *arg)
{
xTaskNotifyGive((TaskHandle_t)arg);
vTaskSuspend(NULL);
}
TEST_CASE("IDF additions: Task creation with memory caps", "[freertos]")
{
TaskHandle_t task_handle = NULL;
StackType_t *puxStackBuffer;
StaticTask_t *pxTaskBuffer;
// Create a task with caps
TEST_ASSERT_EQUAL(pdPASS, xTaskCreatePinnedToCoreWithCaps(task_with_caps, "task", 4096, (void *)xTaskGetCurrentTaskHandle(), UNITY_FREERTOS_PRIORITY + 1, &task_handle, UNITY_FREERTOS_CPU, OBJECT_MEMORY_CAPS));
TEST_ASSERT_NOT_EQUAL(NULL, task_handle);
// Get the task's memory
TEST_ASSERT_EQUAL(pdTRUE, xTaskGetStaticBuffers(task_handle, &puxStackBuffer, &pxTaskBuffer));
TEST_ASSERT(esp_ptr_in_dram(puxStackBuffer));
TEST_ASSERT(esp_ptr_in_dram(pxTaskBuffer));
// Wait for the created task to block
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// Delete the task
vTaskDeleteWithCaps(task_handle);
}
TEST_CASE("IDF additions: Queue creation with memory caps", "[freertos]")
{
QueueHandle_t queue_handle;

Wyświetl plik

@ -118,10 +118,15 @@ FreeRTOS Additions
ESP-IDF provides some supplemental features to FreeRTOS such as Ring Buffers, ESP-IDF style Tick and Idle Hooks, and TLSP deletion callbacks. See :doc:`freertos_additions` for more details.
.. _freertos-heap:
FreeRTOS Heap
-------------
Vanilla FreeRTOS provides its own `selection of heap implementations <https://www.freertos.org/a00111.html>`_. However, ESP-IDF already implements its own heap (see :doc:`/api-reference/system/mem_alloc`), thus ESP-IDF does not make use of the heap implementations provided by Vanilla FreeRTOS. All FreeRTOS ports in ESP-IDF map FreeRTOS memory allocation/free calls (e.g., ``pvPortMalloc()`` and ``pvPortFree()``) to ESP-IDF heap API (i.e., :cpp:func:`heap_caps_malloc` and :cpp:func:`heap_caps_free`). However, the FreeRTOS ports ensure that all dynamic memory allocated by FreeRTOS is placed in internal memory.
.. note::
If users wish to place FreeRTOS objects in external memory, users should allocate those objects manually using :cpp:func:`heap_caps_malloc`, then create the object using the object's ``...CreateStatic()`` function.
If users wish to place FreeRTOS tasks/objects in external memory, users can use the following methods:
- Allocate the task/object using one of the ``...CreateWithCaps()`` API such as :cpp:func:`xTaskCreateWithCaps` and :cpp:func:`xQueueCreateWithCaps` (see :ref:`freertos-idf-additional-api` for more details).
- Manually allocate external memory for those objects using :cpp:func:`heap_caps_malloc`, then create the objects from the allocated memory using on of the ``...CreateStatic()`` FreeRTOS functions.

Wyświetl plik

@ -432,6 +432,8 @@ When implementing TLSP callbacks, users should note the following:
.. ----------------------------------------------- IDF Additional API --------------------------------------------------
.. _freertos-idf-additional-api:
IDF Additional API
------------------

Wyświetl plik

@ -3,6 +3,31 @@ System
:link_to_translation:`zh_CN:[中文]`
FreeRTOS
--------
.. only:: SOC_SPIRAM_SUPPORTED
Dynamic Memory Allocation
^^^^^^^^^^^^^^^^^^^^^^^^^
Previously, most FreeRTOS dynamic allocation would eventually call to ``malloc()``. Thus, if an application was configured to allow ``malloc()`` to allocate from external RAM (i.e., :ref:`CONFIG_SPIRAM_USE` was set ``CONFIG_SPIRAM_USE_MALLOC``), then there was a possibility that FreeRTOS could allocate dynamic memory from external RAM, with the exact placement being decided by the heap allocator.
.. note::
Dynamic memory allocation for tasks (which are likely to consume the most memory) were an exception to the scenario above. FreeRTOS would use a separate memory allocation function to guarantee that dynamic memory allocate for a task was always placed in internal RAM.
Allowing FreeRTOS objects (such as queues and semaphores) to be placed in external RAM becomes an issue if those objects are accessed while the cache is disabled (such as during SPI Flash write operations) and would lead to a cache access errors (see :doc:`Fatal Errors </api-guides/fatal-errors>` for more details).
Therefore, FreeRTOS has been updated to always use internal memory (i.e., DRAM) for dynamic memory allocation. Calling FreeRTOS creation functions (e.g., :cpp:func:`xTaskCreate`, :cpp:func:`xQueueCreate`) will guarantee that the memory allocated for those tasks/objects is from internal memory (see :ref:`freertos-heap` for more details).
.. warning::
For users that previously relied on :ref:`CONFIG_SPIRAM_USE` to place FreeRTOS objects into external memory, this change will lead to increased usage of internal memory due the FreeRTOS objects now being allocated there.
Users that want to place a FreeRTOS task/object into external memory will now need to do so explicitly. Users can use one of the following methods:
- Allocate the task/object using one of the ``...CreateWithCaps()`` API such as :cpp:func:`xTaskCreateWithCaps` and :cpp:func:`xQueueCreateWithCaps` (see :ref:`freertos-idf-additional-api` for more details).
- Manually allocate external memory for those objects using :cpp:func:`heap_caps_malloc`, then create the objects from the allocated memory using one of the ``...CreateStatic()`` FreeRTOS functions.
Power Management
-----------------------