freertos(IDF): Refactor port heap functions

Vanilla FreeRTOS expects applications to use one of the heap implementations
provided by FreeRTOS (i.e., heap_x.c), where functions such as pvPortMalloc()
and vPortFree() are defined in the heap implementation.

However, ESP-IDF already provides its own heap implementation
(i.e., esp_heap_caps.h). Thus, the pvPortMallc()/vPortFree() functions were
previously overriden by macro to call esp_heap functions directly.

This commit refactors the FreeRTOS port's heap as such:

- Added a heap_idf.c that implements all of the heap related functions required
  by FreeRTOS source
- All dynamic memory allocated by FreeRTOS is from internal memory. Thus, the
  FreeRTOS heap is the internal memory subset of the ESP-IDF heap.
- Removed some old macros to reduce diff from upstream source code.
This commit is contained in:
Darian Leung 2023-03-01 19:06:10 +08:00
parent 1b8a2c264d
commit e21ab0332b
15 changed files with 257 additions and 225 deletions

View File

@ -21,6 +21,7 @@ set(arch "linux")
endif() endif()
set(srcs set(srcs
"heap_idf.c"
"${kernel_dir}/list.c" "${kernel_dir}/list.c"
"${kernel_dir}/queue.c" "${kernel_dir}/queue.c"
"${kernel_dir}/tasks.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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -286,15 +286,32 @@ static inline bool IRAM_ATTR xPortCanYield(void)
void vPortSetStackWatchpoint(void *pxStackStart); void vPortSetStackWatchpoint(void *pxStackStart);
#define portVALID_TCB_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr)) // -------------------- Heap Related -----------------------
#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
#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 --------------------------------------------------------- /* ------------------------------------------------------ Misc ---------------------------------------------------------
* - Miscellaneous porting macros * - Miscellaneous porting macros

View File

@ -349,42 +349,6 @@ void vPortEndScheduler(void)
abort(); 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 -------------------------- // ------------------------ 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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -352,15 +352,32 @@ static inline bool IRAM_ATTR xPortCanYield(void)
void vPortSetStackWatchpoint(void *pxStackStart); void vPortSetStackWatchpoint(void *pxStackStart);
#define portVALID_TCB_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr)) // -------------------- Heap Related -----------------------
#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
#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 ------------------ // --------------- 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 -------------------------- // ------------------------ Stack --------------------------
// User exception dispatcher when exiting // User exception dispatcher when exiting

View File

@ -139,8 +139,6 @@
#endif #endif
#endif /* if ( portUSING_MPU_WRAPPERS == 1 ) */ #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 /* Used by heap_5.c to define the start address and size of each memory region
* that together comprise the total FreeRTOS heap space. */ * that together comprise the total FreeRTOS heap space. */
typedef struct HeapRegion typedef struct HeapRegion
@ -189,29 +187,6 @@ void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION; size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION;
size_t xPortGetMinimumEverFreeHeapSize( 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 * 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. * 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; return (BaseType_t) 0;
} }
static inline bool portVALID_TCB_MEM(const void *ptr) /**
{ * @brief Checks if a given piece of memory can be used to store a task's TCB
return true; *
} * - 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) /**
{ * @brief Checks if a given piece of memory can be used to store a task's stack
return true; *
} * - 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 portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr)
#define pvPortMallocStackMem(size) pvPortMalloc(size) #define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr)
BaseType_t xPortCheckIfInISR(void); BaseType_t xPortCheckIfInISR(void);

View File

@ -303,20 +303,6 @@ FORCE_INLINE_ATTR BaseType_t xPortGetCoreID(void)
* - Maps to forward declared functions * - 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 ------------------------ // --------------------- Interrupts ------------------------
#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK_FROM_ISR() #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 * @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 * @param ptr Pointer to memory
* @return true Memory can be used to store a TCB * @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 * @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 * @param ptr Pointer to memory
* @return true Memory can be used to store a task stack * @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); bool xPortcheckValidStackMem(const void *ptr);
#define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr) #define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr)
#define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr) #define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr)
// --------------------- App-Trace ------------------------- // --------------------- App-Trace -------------------------

View File

@ -414,20 +414,6 @@ FORCE_INLINE_ATTR BaseType_t xPortGetCoreID(void);
* - Maps to forward declared functions * - 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 ------------------------ // --------------------- 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 * @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 * @param ptr Pointer to memory
* @return true Memory can be used to store a TCB * @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 * @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 * @param ptr Pointer to memory
* @return true Memory can be used to store a task stack * @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); bool xPortcheckValidStackMem(const void *ptr);
#define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr) #define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr)
#define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr) #define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr)
// --------------------- App-Trace ------------------------- // --------------------- 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 /* Allocate space for the TCB. Where the memory comes from depends
* on the implementation of the port malloc function and whether or * on the implementation of the port malloc function and whether or
* not static allocation is being used. */ * not static allocation is being used. */
pxNewTCB = ( TCB_t * ) pvPortMallocTcbMem( sizeof( TCB_t ) ); pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL ) 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 /* Allocate space for the TCB. Where the memory comes from depends on
* the implementation of the port malloc function and whether or not static * the implementation of the port malloc function and whether or not static
* allocation is being used. */ * allocation is being used. */
pxNewTCB = ( TCB_t * ) pvPortMallocTcbMem( sizeof( TCB_t ) ); pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL ) if( pxNewTCB != NULL )
{ {
/* Allocate space for the stack used by the task being created. /* 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 * The base of the stack memory stored in the TCB so the task can
* be deleted later if required. */ * 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 ) if( pxNewTCB->pxStack == NULL )
{ {
@ -899,12 +899,12 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION;
StackType_t * pxStack; StackType_t * pxStack;
/* Allocate space for the stack used by the task being created. */ /* 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 ) if( pxStack != NULL )
{ {
/* Allocate space for the TCB. */ /* 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 ) 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) 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 # port_common.c
# Placement Rules: # Placement Rules:
@ -55,8 +72,5 @@ entries:
# ------------------------------------------------------------------------------------------------------------------ # ------------------------------------------------------------------------------------------------------------------
port_common (noflash_text) # Default all functions to internal RAM port_common (noflash_text) # Default all functions to internal RAM
if FREERTOS_PLACE_FUNCTIONS_INTO_FLASH = y: 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:vApplicationGetIdleTaskMemory (default)
port_common:vApplicationGetTimerTaskMemory (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). * - 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 ---------------- // ------------- FreeRTOS Static Allocation ----------------
/* /*
These function are required by FreeRTOS when configSUPPORT_STATIC_ALLOCATION is 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. enabled and is used by FreeRTOS to obtain memory for its IDLE/Timer tasks.
Like the pvPortMallocTcbMem() and pvPortMallocStackMem() macros, TCB and stack We simply allocate the IDLE/Timer tasks memory from the FreeRTOS heap.
memory MUST be placed in internal RAM.
*/ */
#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
@ -51,30 +32,20 @@ void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
StaticTask_t *pxTCBBufferTemp; StaticTask_t *pxTCBBufferTemp;
StackType_t *pxStackBufferTemp; 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 * does not grow into the TCB. Likewise if the stack grows up then allocate
* the TCB then the stack. */ * the TCB then the stack. */
#if (portSTACK_GROWTH > 0) #if (portSTACK_GROWTH > 0)
{ {
//Allocate TCB and stack buffer in internal memory pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
#if CONFIG_FREERTOS_SMP // IDF-3997 pxStackBufferTemp = pvPortMalloc(configMINIMAL_STACK_SIZE);
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 */
} }
#else /* portSTACK_GROWTH */ #else /* portSTACK_GROWTH */
{ {
//Allocate TCB and stack buffer in internal memory pxStackBufferTemp = pvPortMalloc(configMINIMAL_STACK_SIZE);
#if CONFIG_FREERTOS_SMP // IDF-3997 pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
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 */
} }
#endif /* portSTACK_GROWTH */ #endif /* portSTACK_GROWTH */
@ -93,30 +64,20 @@ void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
StaticTask_t *pxTCBBufferTemp; StaticTask_t *pxTCBBufferTemp;
StackType_t *pxStackBufferTemp; 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 * does not grow into the TCB. Likewise if the stack grows up then allocate
* the TCB then the stack. */ * the TCB then the stack. */
#if (portSTACK_GROWTH > 0) #if (portSTACK_GROWTH > 0)
{ {
//Allocate TCB and stack buffer in internal memory pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
#if CONFIG_FREERTOS_SMP // IDF-3997 pxStackBufferTemp = pvPortMalloc(configTIMER_TASK_STACK_DEPTH);
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 */
} }
#else /* portSTACK_GROWTH */ #else /* portSTACK_GROWTH */
{ {
//Allocate TCB and stack buffer in internal memory pxStackBufferTemp = pvPortMalloc(configTIMER_TASK_STACK_DEPTH);
#if CONFIG_FREERTOS_SMP // IDF-3997 pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t));
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 */
} }
#endif /* portSTACK_GROWTH */ #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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -31,7 +31,7 @@
#define NO_OF_TSKS 3 #define NO_OF_TSKS 3
#define DELAY_TICKS 2 #define DELAY_TICKS 2
/* Caps of all memory which is allocated from when a task is created */ /* 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 #define DELAY_US_ITERATIONS 1000

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. 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.