Merge branch 'refactor/freertos_port_malloc_macros' into 'master'

FreeRTOS(IDF): Refactor pvPortMalloc()/vPortFree(), Implement IDF heap wrapper for FreeRTOS.

Closes IDF-3997

See merge request espressif/esp-idf!22565
This commit is contained in:
Darian 2023-03-07 17:30:10 +08:00
commit daf4150846
17 changed files with 266 additions and 232 deletions

View File

@ -21,6 +21,7 @@ set(arch "linux")
endif()
set(srcs
"heap_idf.c"
"${kernel_dir}/list.c"
"${kernel_dir}/queue.c"
"${kernel_dir}/tasks.c"

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -286,15 +286,32 @@ static inline bool IRAM_ATTR xPortCanYield(void)
void vPortSetStackWatchpoint(void *pxStackStart);
#define portVALID_TCB_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr))
#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
#define portVALID_STACK_MEM(ptr) (esp_ptr_byte_accessible(ptr))
#else
#define portVALID_STACK_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr))
#endif
// -------------------- Heap Related -----------------------
#define portTcbMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
#define portStackMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
/**
* @brief Checks if a given piece of memory can be used to store a task's TCB
*
* - Defined in heap_idf.c
*
* @param ptr Pointer to memory
* @return true Memory can be used to store a TCB
* @return false Otherwise
*/
bool xPortCheckValidTCBMem(const void *ptr);
/**
* @brief Checks if a given piece of memory can be used to store a task's stack
*
* - Defined in heap_idf.c
*
* @param ptr Pointer to memory
* @return true Memory can be used to store a task stack
* @return false Otherwise
*/
bool xPortcheckValidStackMem(const void *ptr);
#define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr)
#define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr)
/* ------------------------------------------------------ Misc ---------------------------------------------------------
* - Miscellaneous porting macros

View File

@ -349,42 +349,6 @@ void vPortEndScheduler(void)
abort();
}
// ----------------------- Memory --------------------------
#define FREERTOS_SMP_MALLOC_CAPS (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
void *pvPortMalloc( size_t xSize )
{
return heap_caps_malloc(xSize, FREERTOS_SMP_MALLOC_CAPS);
}
void vPortFree( void *pv )
{
heap_caps_free(pv);
}
void vPortInitialiseBlocks( void )
{
; //Does nothing, heap is initialized separately in ESP-IDF
}
size_t xPortGetFreeHeapSize( void )
{
return esp_get_free_heap_size();
}
#if( configSTACK_ALLOCATION_FROM_SEPARATE_HEAP == 1 )
void *pvPortMallocStack( size_t xSize )
{
return NULL;
}
void vPortFreeStack( void *pv )
{
}
#endif
// ------------------------ Stack --------------------------
/**

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -352,15 +352,32 @@ static inline bool IRAM_ATTR xPortCanYield(void)
void vPortSetStackWatchpoint(void *pxStackStart);
#define portVALID_TCB_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr))
#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
#define portVALID_STACK_MEM(ptr) (esp_ptr_byte_accessible(ptr))
#else
#define portVALID_STACK_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr))
#endif
// -------------------- Heap Related -----------------------
#define portTcbMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
#define portStackMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
/**
* @brief Checks if a given piece of memory can be used to store a task's TCB
*
* - Defined in heap_idf.c
*
* @param ptr Pointer to memory
* @return true Memory can be used to store a TCB
* @return false Otherwise
*/
bool xPortCheckValidTCBMem(const void *ptr);
/**
* @brief Checks if a given piece of memory can be used to store a task's stack
*
* - Defined in heap_idf.c
*
* @param ptr Pointer to memory
* @return true Memory can be used to store a task stack
* @return false Otherwise
*/
bool xPortcheckValidStackMem(const void *ptr);
#define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr)
#define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr)
// --------------- Compatibility Includes ------------------
/*

View File

@ -386,42 +386,6 @@ void vPortEndScheduler( void )
;
}
// ----------------------- Memory --------------------------
#define FREERTOS_SMP_MALLOC_CAPS (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
void *pvPortMalloc( size_t xSize )
{
return heap_caps_malloc(xSize, FREERTOS_SMP_MALLOC_CAPS);
}
void vPortFree( void *pv )
{
heap_caps_free(pv);
}
void vPortInitialiseBlocks( void )
{
; //Does nothing, heap is initialized separately in ESP-IDF
}
size_t xPortGetFreeHeapSize( void )
{
return esp_get_free_heap_size();
}
#if( configSTACK_ALLOCATION_FROM_SEPARATE_HEAP == 1 )
void *pvPortMallocStack( size_t xSize )
{
return NULL;
}
void vPortFreeStack( void *pv )
{
}
#endif
// ------------------------ Stack --------------------------
// User exception dispatcher when exiting

View File

@ -139,8 +139,6 @@
#endif
#endif /* if ( portUSING_MPU_WRAPPERS == 1 ) */
#ifdef configUSE_FREERTOS_PROVIDED_HEAP
/* Used by heap_5.c to define the start address and size of each memory region
* that together comprise the total FreeRTOS heap space. */
typedef struct HeapRegion
@ -189,29 +187,6 @@ void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION;
size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;
#if( configSTACK_ALLOCATION_FROM_SEPARATE_HEAP == 1 )
void *pvPortMallocStack( size_t xSize ) PRIVILEGED_FUNCTION;
void vPortFreeStack( void *pv ) PRIVILEGED_FUNCTION;
#else
#define pvPortMallocStack pvPortMalloc
#define vPortFreeStack vPortFree
#endif
#else // configUSE_FREERTOS_PROVIDED_HEAP
/*
* Map to the memory management routines required for the port.
*
* Note that libc standard malloc/free are also available for
* non-FreeRTOS-specific code, and behave the same as
* pvPortMalloc()/vPortFree().
*/
#define pvPortMalloc malloc
#define vPortFree free
#define xPortGetFreeHeapSize esp_get_free_heap_size
#define xPortGetMinimumEverFreeHeapSize esp_get_minimum_free_heap_size
#endif
/*
* Setup the hardware ready for the scheduler to take control. This generally
* sets up a tick interrupt and sets timers for the correct tick frequency.

View File

@ -51,18 +51,30 @@ static inline BaseType_t IRAM_ATTR xPortGetCoreID(void)
return (BaseType_t) 0;
}
static inline bool portVALID_TCB_MEM(const void *ptr)
{
return true;
}
/**
* @brief Checks if a given piece of memory can be used to store a task's TCB
*
* - Defined in heap_idf.c
*
* @param ptr Pointer to memory
* @return true Memory can be used to store a TCB
* @return false Otherwise
*/
bool xPortCheckValidTCBMem(const void *ptr);
static inline bool portVALID_STACK_MEM(const void *ptr)
{
return true;
}
/**
* @brief Checks if a given piece of memory can be used to store a task's stack
*
* - Defined in heap_idf.c
*
* @param ptr Pointer to memory
* @return true Memory can be used to store a task stack
* @return false Otherwise
*/
bool xPortcheckValidStackMem(const void *ptr);
#define pvPortMallocTcbMem(size) pvPortMalloc(size)
#define pvPortMallocStackMem(size) pvPortMalloc(size)
#define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr)
#define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr)
BaseType_t xPortCheckIfInISR(void);

View File

@ -303,20 +303,6 @@ FORCE_INLINE_ATTR BaseType_t xPortGetCoreID(void)
* - Maps to forward declared functions
* ------------------------------------------------------------------------------------------------------------------ */
// ----------------------- Memory --------------------------
/**
* @brief Task memory allocation macros
*
* @note Because the ROM routines don't necessarily handle a stack in external RAM correctly, we force the stack
* memory to always be internal.
* @note [refactor-todo] Update portable.h to match v10.4.3 to use new malloc prototypes
*/
#define portTcbMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
#define portStackMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
#define pvPortMallocTcbMem(size) pvPortMalloc(size)
#define pvPortMallocStackMem(size) pvPortMalloc(size)
// --------------------- Interrupts ------------------------
#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK_FROM_ISR()
@ -446,7 +432,7 @@ FORCE_INLINE_ATTR bool xPortCanYield(void)
/**
* @brief Checks if a given piece of memory can be used to store a task's TCB
*
* - Defined in port_common.c
* - Defined in heap_idf.c
*
* @param ptr Pointer to memory
* @return true Memory can be used to store a TCB
@ -457,7 +443,7 @@ bool xPortCheckValidTCBMem(const void *ptr);
/**
* @brief Checks if a given piece of memory can be used to store a task's stack
*
* - Defined in port_common.c
* - Defined in heap_idf.c
*
* @param ptr Pointer to memory
* @return true Memory can be used to store a task stack
@ -465,8 +451,8 @@ bool xPortCheckValidTCBMem(const void *ptr);
*/
bool xPortcheckValidStackMem(const void *ptr);
#define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr)
#define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr)
#define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr)
#define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr)
// --------------------- App-Trace -------------------------

View File

@ -414,20 +414,6 @@ FORCE_INLINE_ATTR BaseType_t xPortGetCoreID(void);
* - Maps to forward declared functions
* ------------------------------------------------------------------------------------------------------------------ */
// ----------------------- Memory --------------------------
/**
* @brief Task memory allocation macros
*
* @note Because the ROM routines don't necessarily handle a stack in external RAM correctly, we force the stack
* memory to always be internal.
* @note [refactor-todo] Update portable.h to match v10.4.3 to use new malloc prototypes
*/
#define portTcbMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
#define portStackMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
#define pvPortMallocTcbMem(size) heap_caps_malloc(size, portTcbMemoryCaps)
#define pvPortMallocStackMem(size) heap_caps_malloc(size, portStackMemoryCaps)
// --------------------- Interrupts ------------------------
/**
@ -656,7 +642,7 @@ void vPortCleanUpCoprocArea(void *pvTCB);
/**
* @brief Checks if a given piece of memory can be used to store a task's TCB
*
* - Defined in port_common.c
* - Defined in heap_idf.c
*
* @param ptr Pointer to memory
* @return true Memory can be used to store a TCB
@ -667,7 +653,7 @@ bool xPortCheckValidTCBMem(const void *ptr);
/**
* @brief Checks if a given piece of memory can be used to store a task's stack
*
* - Defined in port_common.c
* - Defined in heap_idf.c
*
* @param ptr Pointer to memory
* @return true Memory can be used to store a task stack
@ -675,8 +661,8 @@ bool xPortCheckValidTCBMem(const void *ptr);
*/
bool xPortcheckValidStackMem(const void *ptr);
#define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr)
#define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr)
#define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr)
#define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr)
// --------------------- App-Trace -------------------------

View File

@ -820,7 +820,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION;
/* Allocate space for the TCB. Where the memory comes from depends
* on the implementation of the port malloc function and whether or
* not static allocation is being used. */
pxNewTCB = ( TCB_t * ) pvPortMallocTcbMem( sizeof( TCB_t ) );
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL )
{
@ -877,14 +877,14 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION;
/* Allocate space for the TCB. Where the memory comes from depends on
* the implementation of the port malloc function and whether or not static
* allocation is being used. */
pxNewTCB = ( TCB_t * ) pvPortMallocTcbMem( sizeof( TCB_t ) );
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL )
{
/* Allocate space for the stack used by the task being created.
* The base of the stack memory stored in the TCB so the task can
* be deleted later if required. */
pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocStackMem( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
if( pxNewTCB->pxStack == NULL )
{
@ -899,12 +899,12 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION;
StackType_t * pxStack;
/* Allocate space for the stack used by the task being created. */
pxStack = pvPortMallocStackMem( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */
pxStack = pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */
if( pxStack != NULL )
{
/* Allocate space for the TCB. */
pxNewTCB = ( TCB_t * ) pvPortMallocTcbMem( sizeof( TCB_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of TCB_t is always a pointer to the task's stack. */
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of TCB_t is always a pointer to the task's stack. */
if( pxNewTCB != NULL )
{

View File

@ -0,0 +1,127 @@
/*
* SPDX-FileCopyrightText: 2020 Amazon.com, Inc. or its affiliates
*
* SPDX-License-Identifier: MIT
*
* SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD
*/
/*
* FreeRTOS Kernel V10.4.3
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#include "sdkconfig.h"
/* This file implements the heap related functions that are called by FreeRTOS.
* ESP-IDF provides its own heap containing memory with different capabilities
* (see esp_heap_caps.h). Thus, this file maps a subset of the ESP-IDF heap to
* act as the FreeRTOS heap.
*
* All dynamic allocation done by FreeRTOS should be placed in internal 8-bit
* accessible RAM (i.e., using the MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT flags).
* This is due to the fact that FreeRTOS objects (e.g., task stacks, TCBs,
* queues etc) must be accessible even if the cache is disabled. Therefore, the
* heap that is made available to FreeRTOS for dynamic allocation is a subset of
* the ESP-IDF heap (where all MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT memory is
* made available to FreeRTOS for dynamic allocation).
*/
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
* all the API functions to use the MPU wrappers. That should only be done when
* task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
#include "esp_heap_caps.h"
#if !CONFIG_IDF_TARGET_LINUX
/* Memory util functions are not implemented in the Linux simulator */
#include "esp_memory_utils.h"
#endif /* CONFIG_IDF_TARGET_LINUX */
#define portFREERTOS_HEAP_CAPS ( MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT )
/*-----------------------------------------------------------*/
void * pvPortMalloc( size_t xWantedSize )
{
void * pvReturn = NULL;
/* All dynamic allocation done by FreeRTOS goes through this function. If
* users need to allocate FreeRTOS objects into external RAM, they should
* use the "static" equivalents of FreeRTOS API to create FreeRTOS objects
* (e.g., queues). */
pvReturn = heap_caps_malloc( xWantedSize, portFREERTOS_HEAP_CAPS );
return pvReturn;
}
/*-----------------------------------------------------------*/
void vPortFree( void * pv )
{
heap_caps_free( pv );
}
/*-----------------------------------------------------------*/
size_t xPortGetFreeHeapSize( void )
{
return heap_caps_get_free_size( portFREERTOS_HEAP_CAPS );
}
/*-----------------------------------------------------------*/
size_t xPortGetMinimumEverFreeHeapSize( void )
{
return heap_caps_get_minimum_free_size( portFREERTOS_HEAP_CAPS );
}
/*-----------------------------------------------------------*/
bool xPortCheckValidTCBMem(const void *ptr)
{
#if CONFIG_IDF_TARGET_LINUX
return true;
#else /* CONFIG_IDF_TARGET_LINUX */
return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
#endif /* CONFIG_IDF_TARGET_LINUX */
}
bool xPortcheckValidStackMem(const void *ptr)
{
#if CONFIG_IDF_TARGET_LINUX
return true;
#else /* CONFIG_IDF_TARGET_LINUX */
#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
return esp_ptr_byte_accessible(ptr);
#else
return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
#endif
#endif /* CONFIG_IDF_TARGET_LINUX */
}

View File

@ -46,6 +46,23 @@ entries:
# ------------------------------------------------------------------------------------------------------------------
FreeRTOS-openocd (noflash)
# ------------------------------------------------------------------------------------------------------------------
# heap_idf.c
# Placement Rules:
# - Default: Place all functions in internal RAM.
# - CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH: Place functions in flash if they are never called from an ISR
# context (directly or indirectly).
# ------------------------------------------------------------------------------------------------------------------
heap_idf (noflash_text) # Default all functions to internal RAM
if FREERTOS_PLACE_FUNCTIONS_INTO_FLASH = y:
heap_idf:pvPortMalloc (default)
heap_idf:vPortFree (default)
heap_idf:xPortGetFreeHeapSize (default)
heap_idf:xPortGetMinimumEverFreeHeapSize (default)
if FREERTOS_SMP = n:
heap_idf:xPortCheckValidTCBMem (default)
heap_idf:xPortcheckValidStackMem (default)
# ------------------------------------------------------------------------------------------------------------------
# port_common.c
# Placement Rules:
@ -55,8 +72,5 @@ entries:
# ------------------------------------------------------------------------------------------------------------------
port_common (noflash_text) # Default all functions to internal RAM
if FREERTOS_PLACE_FUNCTIONS_INTO_FLASH = y:
if FREERTOS_SMP = n:
port_common:xPortCheckValidTCBMem (default)
port_common:xPortcheckValidStackMem (default)
port_common:vApplicationGetIdleTaskMemory (default)
port_common:vApplicationGetTimerTaskMemory (default)

View File

@ -16,32 +16,13 @@
* - These functions are common to all FreeRTOS ports (i.e., on all architectures and all FreeRTOS implementations).
* ------------------------------------------------------------------------------------------------------------------ */
// -------------------- Heap Related -----------------------
#if !CONFIG_FREERTOS_SMP // IDF-3997
bool xPortCheckValidTCBMem(const void *ptr)
{
return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
}
bool xPortcheckValidStackMem(const void *ptr)
{
#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
return esp_ptr_byte_accessible(ptr);
#else
return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
#endif
}
#endif
// ------------- FreeRTOS Static Allocation ----------------
/*
These function are required by FreeRTOS when configSUPPORT_STATIC_ALLOCATION is
enabled and is used by FreeRTOS to obtain memory for its IDLE/Timer tasks.
Like the pvPortMallocTcbMem() and pvPortMallocStackMem() macros, TCB and stack
memory MUST be placed in internal RAM.
We simply allocate the IDLE/Timer tasks memory from the FreeRTOS heap.
*/
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
@ -51,30 +32,20 @@ void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
StaticTask_t *pxTCBBufferTemp;
StackType_t *pxStackBufferTemp;
/* If the stack grows down then allocate the stack then the TCB so the stack
/* Allocate TCB and stack buffer from the FreeRTOS heap
*
* If the stack grows down then allocate the stack then the TCB so the stack
* does not grow into the TCB. Likewise if the stack grows up then allocate
* the TCB then the stack. */
#if (portSTACK_GROWTH > 0)
{
//Allocate TCB and stack buffer in internal memory
#if CONFIG_FREERTOS_SMP // IDF-3997
pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
pxStackBufferTemp = pvPortMalloc(configMINIMAL_STACK_SIZE);
#else
pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
pxStackBufferTemp = pvPortMallocStackMem(configMINIMAL_STACK_SIZE);
#endif /* CONFIG_FREERTOS_SMP */
pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
pxStackBufferTemp = pvPortMalloc(configMINIMAL_STACK_SIZE);
}
#else /* portSTACK_GROWTH */
{
//Allocate TCB and stack buffer in internal memory
#if CONFIG_FREERTOS_SMP // IDF-3997
pxStackBufferTemp = pvPortMalloc(configMINIMAL_STACK_SIZE);
pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
#else
pxStackBufferTemp = pvPortMallocStackMem(configMINIMAL_STACK_SIZE);
pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
#endif /* CONFIG_FREERTOS_SMP */
pxStackBufferTemp = pvPortMalloc(configMINIMAL_STACK_SIZE);
pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
}
#endif /* portSTACK_GROWTH */
@ -93,30 +64,20 @@ void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
StaticTask_t *pxTCBBufferTemp;
StackType_t *pxStackBufferTemp;
/* If the stack grows down then allocate the stack then the TCB so the stack
/* Allocate TCB and stack buffer from the FreeRTOS heap
*
* If the stack grows down then allocate the stack then the TCB so the stack
* does not grow into the TCB. Likewise if the stack grows up then allocate
* the TCB then the stack. */
#if (portSTACK_GROWTH > 0)
{
//Allocate TCB and stack buffer in internal memory
#if CONFIG_FREERTOS_SMP // IDF-3997
pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
pxStackBufferTemp = pvPortMalloc(configTIMER_TASK_STACK_DEPTH);
#else
pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
pxStackBufferTemp = pvPortMallocStackMem(configTIMER_TASK_STACK_DEPTH);
#endif /* CONFIG_FREERTOS_SMP */
pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
pxStackBufferTemp = pvPortMalloc(configTIMER_TASK_STACK_DEPTH);
}
#else /* portSTACK_GROWTH */
{
//Allocate TCB and stack buffer in internal memory
#if CONFIG_FREERTOS_SMP // IDF-3997
pxStackBufferTemp = pvPortMalloc(configTIMER_TASK_STACK_DEPTH);
pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
#else
pxStackBufferTemp = pvPortMallocStackMem(configTIMER_TASK_STACK_DEPTH);
pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
#endif /* CONFIG_FREERTOS_SMP */
pxStackBufferTemp = pvPortMalloc(configTIMER_TASK_STACK_DEPTH);
pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
}
#endif /* portSTACK_GROWTH */

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -31,7 +31,7 @@
#define NO_OF_TSKS 3
#define DELAY_TICKS 2
/* Caps of all memory which is allocated from when a task is created */
#define HEAP_CAPS (portTcbMemoryCaps | portStackMemoryCaps)
#define HEAP_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#define DELAY_US_ITERATIONS 1000

View File

@ -16,6 +16,7 @@
#include "freertos/queue.h"
#include "unity.h"
#include "esp_heap_caps.h"
#include "esp_system.h"
#include "sdkconfig.h"
@ -127,7 +128,7 @@ TEST_CASE("unreasonable allocs should all fail", "[heap]")
TEST_ASSERT_NULL(test_malloc_wrapper(16*1024*1024));
TEST_ASSERT_NULL(test_malloc_wrapper(SIZE_MAX / 2));
TEST_ASSERT_NULL(test_malloc_wrapper(SIZE_MAX - 256));
TEST_ASSERT_NULL(test_malloc_wrapper(xPortGetFreeHeapSize() - 1));
TEST_ASSERT_NULL(test_malloc_wrapper(esp_get_free_heap_size() - 1));
}
TEST_CASE("malloc(0) should return a NULL pointer", "[heap]")

View File

@ -13,6 +13,7 @@
#include "esp_private/esp_clk.h"
#include "sdkconfig.h"
#include "esp_cpu.h"
#include "esp_system.h"
#include "spi_flash_mmap.h"
@ -43,10 +44,10 @@ TEST(wear_levelling, wl_unmount_doesnt_leak_memory)
wl_unmount(handle);
// test that we didn't leak any memory on the next init/deinit
size_t size_before = xPortGetFreeHeapSize();
size_t size_before = esp_get_free_heap_size();
TEST_ESP_OK(wl_mount(partition, &handle));
wl_unmount(handle);
size_t size_after = xPortGetFreeHeapSize();
size_t size_after = esp_get_free_heap_size();
TEST_ASSERT_EQUAL(size_before, size_after);
}
@ -64,21 +65,21 @@ TEST(wear_levelling, wl_mount_checks_partition_params)
// test small partition: result should be error
for (int i = 0; i < 5; i++) {
fake_partition.size = SPI_FLASH_SEC_SIZE * (i);
size_before = xPortGetFreeHeapSize();
size_before = esp_get_free_heap_size();
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, wl_mount(&fake_partition, &handle));
// test that we didn't leak any memory
size_after = xPortGetFreeHeapSize();
size_after = esp_get_free_heap_size();
TEST_ASSERT_EQUAL_HEX32(size_before, size_after);
}
// test minimum size partition: result should be OK
fake_partition.size = SPI_FLASH_SEC_SIZE * 5;
size_before = xPortGetFreeHeapSize();
size_before = esp_get_free_heap_size();
TEST_ESP_OK(wl_mount(&fake_partition, &handle));
wl_unmount(handle);
// test that we didn't leak any memory
size_after = xPortGetFreeHeapSize();
size_after = esp_get_free_heap_size();
TEST_ASSERT_EQUAL_HEX32(size_before, size_after);
}

View File

@ -117,3 +117,11 @@ 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
-------------
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.