mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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:
commit
daf4150846
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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 --------------------------
|
||||
|
||||
/**
|
||||
|
@ -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 ------------------
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 -------------------------
|
||||
|
||||
|
@ -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 -------------------------
|
||||
|
||||
|
@ -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 )
|
||||
{
|
||||
|
127
components/freertos/heap_idf.c
Normal file
127
components/freertos/heap_idf.c
Normal 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 */
|
||||
}
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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]")
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user