From: Jeroen Domburg Date: Tue, 13 Dec 2016 09:01:10 +0000 (+0800) Subject: Fix small things noticed in MR, add documentation X-Git-Tag: v2.0-rc1~131^2~2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1e117dc3d31513928528bd178611f67b8ffde1f7;p=esp-idf Fix small things noticed in MR, add documentation --- diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 7ce8ba5ca6..511903c438 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -164,8 +164,9 @@ static void disable_mem_region(void *from, void *to) { /* -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; @@ -177,6 +178,8 @@ Same with loading of apps. Same with using SPI RAM. */ 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 @@ -217,7 +220,7 @@ void heap_alloc_caps_init() { } } - 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", diff --git a/components/esp32/include/esp_heap_alloc_caps.h b/components/esp32/include/esp_heap_alloc_caps.h index 42bc614c21..21c24de6bf 100644 --- a/components/esp32/include/esp_heap_alloc_caps.h +++ b/components/esp32/include/esp_heap_alloc_caps.h @@ -14,23 +14,65 @@ #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 diff --git a/components/freertos/heap_regions.c b/components/freertos/heap_regions.c index 6e1cb103fd..5ff1f2817e 100644 --- a/components/freertos/heap_regions.c +++ b/components/freertos/heap_regions.c @@ -147,8 +147,9 @@ task.h is included from an application 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. */ @@ -496,6 +497,7 @@ const HeapRegionTagged_t *pxHeapRegion; } 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. */ diff --git a/components/freertos/include/freertos/heap_regions.h b/components/freertos/include/freertos/heap_regions.h index 3e632dac7a..30d0dcb39c 100644 --- a/components/freertos/include/freertos/heap_regions.h +++ b/components/freertos/include/freertos/heap_regions.h @@ -19,19 +19,68 @@ /* 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 ); diff --git a/docs/Doxyfile b/docs/Doxyfile index bdb91a4dce..2456b6c2ea 100755 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -28,7 +28,9 @@ INPUT = ../components/esp32/include/esp_wifi.h \ ../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 ## diff --git a/docs/api/mem_alloc.rst b/docs/api/mem_alloc.rst new file mode 100644 index 0000000000..d2af7f2875 --- /dev/null +++ b/docs/api/mem_alloc.rst @@ -0,0 +1,78 @@ +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 `_ + * `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 diff --git a/docs/index.rst b/docs/index.rst index 4e58cfe02f..8a42e762c0 100755 --- a/docs/index.rst +++ b/docs/index.rst @@ -48,7 +48,8 @@ Contents: 1.3. Flash encryption and secure boot: how they work and APIs 1.4. Lower Power Coprocessor - TBA 1.5. Watchdogs - 1.6. ... + 1.6. Memory allocation + 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 @@ -111,6 +112,7 @@ Contents: Virtual Filesystem Ethernet Interrupt Allocation + Memory Allocation deep-sleep-stub Template