/*
-ToDo: These are very dependent on the linker script, and the logic involving this works only
-because we're not using the SPI flash yet! If we enable that, this will break. ToDo: Rewrite by then.
+Warning: These variables are assumed to have the start and end of the data and iram
+area used statically by the program, respectively. These variables are defined in the ld
+file.
*/
extern int _bss_start, _heap_start, _init_start, _iram_text_end;
*/
void heap_alloc_caps_init() {
int i;
+ //Compile-time assert to see if we don't have more tags than is set in heap_regions.h
+ _Static_assert((sizeof(tag_desc)/sizeof(tag_desc[0]))-1 <= HEAPREGIONS_MAX_TAGCOUNT, "More than HEAPREGIONS_MAX_TAGCOUNT tags defined!");
//Disable the bits of memory where this code is loaded.
disable_mem_region(&_bss_start, &_heap_start); //DRAM used by bss/data static variables
disable_mem_region(&_init_start, &_iram_text_end); //IRAM used by code
}
}
- ESP_EARLY_LOGI(TAG, "Initializing. RAM available for heap:");
+ ESP_EARLY_LOGI(TAG, "Initializing. RAM available for dynamic allocation:");
for (i=0; regions[i].xSizeInBytes!=0; i++) {
if (regions[i].xTag != -1) {
ESP_EARLY_LOGI(TAG, "At %08X len %08X (%d KiB): %s",
#ifndef HEAP_ALLOC_CAPS_H
#define HEAP_ALLOC_CAPS_H
-#define MALLOC_CAP_EXEC (1<<0) //Memory must be able to run executable code
-#define MALLOC_CAP_32BIT (1<<1) //Memory must allow for aligned 32-bit data accesses
-#define MALLOC_CAP_8BIT (1<<2) //Memory must allow for 8/16/...-bit data accesses
-#define MALLOC_CAP_DMA (1<<3) //Memory must be able to accessed by DMA
-#define MALLOC_CAP_PID2 (1<<4) //Memory must be mapped to PID2 memory space
-#define MALLOC_CAP_PID3 (1<<5) //Memory must be mapped to PID3 memory space
-#define MALLOC_CAP_PID4 (1<<6) //Memory must be mapped to PID4 memory space
-#define MALLOC_CAP_PID5 (1<<7) //Memory must be mapped to PID5 memory space
-#define MALLOC_CAP_PID6 (1<<8) //Memory must be mapped to PID6 memory space
-#define MALLOC_CAP_PID7 (1<<9) //Memory must be mapped to PID7 memory space
-#define MALLOC_CAP_SPISRAM (1<<10) //Memory must be in SPI SRAM
-#define MALLOC_CAP_INVALID (1<<31) //Memory can't be used / list end marker
+/**
+ * @brief Flags to indicate the capabilities of the various memory systems
+ */
+#define MALLOC_CAP_EXEC (1<<0) ///< Memory must be able to run executable code
+#define MALLOC_CAP_32BIT (1<<1) ///< Memory must allow for aligned 32-bit data accesses
+#define MALLOC_CAP_8BIT (1<<2) ///< Memory must allow for 8/16/...-bit data accesses
+#define MALLOC_CAP_DMA (1<<3) ///< Memory must be able to accessed by DMA
+#define MALLOC_CAP_PID2 (1<<4) ///< Memory must be mapped to PID2 memory space
+#define MALLOC_CAP_PID3 (1<<5) ///< Memory must be mapped to PID3 memory space
+#define MALLOC_CAP_PID4 (1<<6) ///< Memory must be mapped to PID4 memory space
+#define MALLOC_CAP_PID5 (1<<7) ///< Memory must be mapped to PID5 memory space
+#define MALLOC_CAP_PID6 (1<<8) ///< Memory must be mapped to PID6 memory space
+#define MALLOC_CAP_PID7 (1<<9) ///< Memory must be mapped to PID7 memory space
+#define MALLOC_CAP_SPISRAM (1<<10) ///< Memory must be in SPI SRAM
+#define MALLOC_CAP_INVALID (1<<31) ///< Memory can't be used / list end marker
+/**
+ * @brief Initialize the capability-aware heap allocator.
+ *
+ * For the ESP32, this is called once in the startup code.
+ */
void heap_alloc_caps_init();
+
+/**
+ * @brief Allocate a chunk of memory which has the given capabilities
+ *
+ * @param xWantedSize Size, in bytes, of the amount of memory to allocate
+ * @param caps Bitwise OR of MALLOC_CAP_* flags indicating the type
+ * of memory to be returned
+ *
+ * @return A pointer to the memory allocated on success, NULL on failure
+ */
void *pvPortMallocCaps(size_t xWantedSize, uint32_t caps);
+
+/**
+ * @brief Get the total free size of all the regions that have the given capabilities
+ *
+ * This function takes all regions capable of having the given capabilities allocated in them
+ * and adds up the free space they have.
+ *
+ * @param caps Bitwise OR of MALLOC_CAP_* flags indicating the type
+ * of memory
+ *
+ * @return Amount of free bytes in the regions
+ */
size_t xPortGetFreeHeapSizeCaps( uint32_t caps );
+
+/**
+ * @brief Get the total minimum free memory of all regions with the given capabilities
+ *
+ * This adds all the lowmarks of the regions capable of delivering the memory with the
+ * given capabilities
+ *
+ * @param caps Bitwise OR of MALLOC_CAP_* flags indicating the type
+ * of memory
+ *
+ * @return Amount of free bytes in the regions
+ */
size_t xPortGetMinimumEverFreeHeapSizeCaps( uint32_t caps );
#endif
\ No newline at end of file
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
/* Define the linked list structure. This is used to link free blocks in order
-of their memory address. */
-/* This is optimized and assumes a region is never larger than 16MiB. */
+ of their memory address. This is optimized for size of the linked list struct
+ and assumes a region is never larger than 16MiB. */
+#define HEAPREGIONS_MAX_REGIONSIZE (16*1024*1024)
typedef struct A_BLOCK_LINK
{
struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */
}
configASSERT(pxHeapRegion->xTag < HEAPREGIONS_MAX_TAGCOUNT);
+ configASSERT(pxHeapRegion->xSizeInBytes < HEAPREGIONS_MAX_REGIONSIZE);
xTotalRegionSize = pxHeapRegion->xSizeInBytes;
/* Ensure the heap region starts on a correctly aligned boundary. */
/* The maximum amount of tags in use */
#define HEAPREGIONS_MAX_TAGCOUNT 16
-
+/**
+ * @brief Structure to define a memory region
+ */
typedef struct HeapRegionTagged
{
- uint8_t *pucStartAddress;
- size_t xSizeInBytes;
- BaseType_t xTag;
- uint32_t xExecAddr;
+ uint8_t *pucStartAddress; ///< Start address of the region
+ size_t xSizeInBytes; ///< Size of the region
+ BaseType_t xTag; ///< Tag for the region
+ uint32_t xExecAddr; ///< If non-zero, indicates the region also has an alias in IRAM.
} HeapRegionTagged_t;
+/**
+ * @brief Initialize the heap allocator by feeding it the usable memory regions and their tags.
+ *
+ * This takes an array of heapRegionTagged_t structs, the last entry of which is a dummy entry
+ * which has pucStartAddress set to NULL. It will initialize the heap allocator to serve memory
+ * from these ranges.
+ *
+ * @param pxHeapRegions Array of region definitions
+ */
void vPortDefineHeapRegionsTagged( const HeapRegionTagged_t * const pxHeapRegions );
+
+
+/**
+ * @brief Allocate memory from a region with a certain tag
+ *
+ * Like pvPortMalloc, this returns an allocated chunk of memory. This function,
+ * however, forces the allocator to allocate from a region specified by a
+ * specific tag.
+ *
+ * @param xWantedSize Size needed, in bytes
+ * @param tag Tag of the memory region the allocation has to be from
+ *
+ * @return Pointer to allocated memory if succesful.
+ * NULL if unsuccesful.
+ */
void *pvPortMallocTagged( size_t xWantedSize, BaseType_t tag );
+
+/**
+ * @brief Get the lowest amount of memory free for a certain tag
+ *
+ * This function allows the user to see what the least amount of
+ * free memory for a certain tag is.
+ *
+ * @param tag Tag of the memory region
+ *
+ * @return Minimum amount of free bytes available in the runtime of
+ * the program
+ */
size_t xPortGetMinimumEverFreeHeapSizeTagged( BaseType_t tag );
+
+/**
+ * @brief Get the amount of free bytes in a certain tagged region
+ *
+ * Works like xPortGetFreeHeapSize but allows the user to specify
+ * a specific tag
+ *
+ * @param tag Tag of the memory region
+ *
+ * @return Remaining amount of free bytes in region
+ */
size_t xPortGetFreeHeapSizeTagged( BaseType_t tag );
../components/app_update/include/esp_ota_ops.h \
../components/ethernet/include/esp_eth.h \
../components/ulp/include/esp32/ulp.h \
- ../components/esp32/include/esp_intr_alloc.h
+ ../components/esp32/include/esp_intr_alloc.h \
+ ../components/esp32/include/esp_heap_alloc_caps.h \
+ ../components/freertos/include/freertos/heap_regions.h
## Get warnings for functions that have no documentation for their parameters or return value
##
--- /dev/null
+Memory allocation
+====================
+
+Overview
+--------
+
+The ESP32 has multiple types of RAM. Internally, there's IRAM, DRAM as well as RAM that can be used as both. It's also
+possible to connect external SPI flash to the ESP32; it's memory can be integrated into the ESP32s memory map using
+the flash cache.
+
+In order to make use of all this memory, esp-idf has a capabilities-based memory allocator. Basically, if you want to have
+memory with certain properties (for example, DMA-capable, accessible by a certain PID, or capable of executing code), you
+can create an OR-mask of the required capabilities and pass that to pvPortMallocCaps. For instance, the normal malloc
+code internally allocates memory with ```pvPortMallocCaps(size, MALLOC_CAP_8BIT)``` in order to get data memory that is
+byte-addressable.
+
+Internally, this allocator is split in two pieces. The allocator in the FreeRTOS directory can allocate memory from
+tagged regions: a tag is an integer value and every region of free memory has one of these tags. The esp32-specific
+code initializes these regions with specific tags, and contains the logic to select applicable tags from the
+capabilities given by the user. While shown in the public API, tags are used in the communication between the two parts
+and should not be used directly.
+
+Special Uses
+------------
+
+If a certain memory structure is only addressed in 32-bit units, for example an array of ints or pointers, it can be
+useful to allocate it with the MALLOC_CAP_32BIT flag. This also allows the allocator to give out IRAM memory; something
+which it can't do for a normal malloc() call. This can help to use all the available memory in the ESP32.
+
+
+API Reference
+-------------
+
+Header Files
+^^^^^^^^^^^^
+
+ * `esp_heap_alloc_caps.h <https://github.com/espressif/esp-idf/blob/master/components/esp32/include/esp_heap_alloc_caps.h>`_
+ * `heap_regions.h <https://github.com/espressif/esp-idf/blob/master/components/freertos/include/freertos/heap_regions.h>`_
+
+
+Macros
+^^^^^^
+
+.. doxygendefine:: MALLOC_CAP_EXEC
+.. doxygendefine:: MALLOC_CAP_32BIT
+.. doxygendefine:: MALLOC_CAP_8BIT
+.. doxygendefine:: MALLOC_CAP_DMA
+.. doxygendefine:: MALLOC_CAP_PID2
+.. doxygendefine:: MALLOC_CAP_PID3
+.. doxygendefine:: MALLOC_CAP_PID4
+.. doxygendefine:: MALLOC_CAP_PID5
+.. doxygendefine:: MALLOC_CAP_PID6
+.. doxygendefine:: MALLOC_CAP_PID7
+.. doxygendefine:: MALLOC_CAP_SPISRAM
+.. doxygendefine:: MALLOC_CAP_INVALID
+
+Type Definitions
+^^^^^^^^^^^^^^^^
+
+.. doxygentypedef:: HeapRegionTagged_t
+
+Enumerations
+^^^^^^^^^^^^
+
+Structures
+^^^^^^^^^^
+
+Functions
+^^^^^^^^^
+
+.. doxygenfunction:: heap_alloc_caps_init
+.. doxygenfunction:: pvPortMallocCaps
+.. doxygenfunction:: xPortGetFreeHeapSizeCaps
+.. doxygenfunction:: xPortGetMinimumEverFreeHeapSizeCaps
+.. doxygenfunction:: vPortDefineHeapRegionsTagged
+.. doxygenfunction:: pvPortMallocTagged
+.. doxygenfunction:: xPortGetMinimumEverFreeHeapSizeTagged
+.. doxygenfunction:: xPortGetFreeHeapSizeTagged
1.3. Flash encryption and secure boot: how they work and APIs
1.4. Lower Power Coprocessor - TBA
1.5. Watchdogs <api/wdts>
- 1.6. ...
+ 1.6. Memory allocation <api/mem_alloc>
+ 1.7. ...
2. Memory - TBA
2.1. Memory layout of the application (IRAM/IROM, limitations of each) - TBA
2.2. Flash layout and partitions - TBA
Virtual Filesystem <api/vfs>
Ethernet <api/esp_eth>
Interrupt Allocation <api/intr_alloc>
+ Memory Allocation <api/mem_alloc>
deep-sleep-stub
Template <api/template>