diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 7824823a44..dc897dff2f 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -143,7 +143,7 @@ config SPIRAM_MALLOC_RESERVE_INTERNAL int "Reserve this amount of bytes for data that specifically needs to be in DMA or internal memory" depends on SPIRAM_USE_MALLOC default 32768 - range 0 131072 + range 0 262144 help Because the external/internal RAM allocation strategy is not always perfect, it sometimes may happen that the internal memory is entirely filled up. This causes allocations that are specifically done in @@ -156,6 +156,10 @@ config SPIRAM_MALLOC_RESERVE_INTERNAL Note that because FreeRTOS stacks are forced to internal memory, they will also use this memory pool; be sure to keep this in mind when adjusting this value. + Note also that the DMA reserved pool may not be one single contiguous memory region, depending on the + configured size and the static memory usage of the app. + + config SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY bool "Allow external memory as an argument to xTaskCreateStatic" default n diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 1c9ca73976..bf044bd7b2 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -270,13 +270,6 @@ void start_cpu0_default(void) ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!"); abort(); } -#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL - r=esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL); - if (r != ESP_OK) { - ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool!"); - abort(); - } -#endif #if CONFIG_SPIRAM_USE_MALLOC heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); #endif @@ -446,6 +439,15 @@ static void main_task(void* args) //Enable allocation in region where the startup stacks were located. heap_caps_enable_nonos_stack_heaps(); + // Now we have startup stack RAM available for heap, enable any DMA pool memory +#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL + esp_err_t r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL); + if (r != ESP_OK) { + ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r); + abort(); + } +#endif + //Initialize task wdt if configured to do so #ifdef CONFIG_TASK_WDT_PANIC ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_TASK_WDT_TIMEOUT_S, true)) diff --git a/components/esp32/spiram.c b/components/esp32/spiram.c index 21fade5be6..72198734e1 100644 --- a/components/esp32/spiram.c +++ b/components/esp32/spiram.c @@ -19,6 +19,7 @@ we add more types of external RAM memory, this can be made into a more intellige #include #include +#include #include "sdkconfig.h" #include "esp_attr.h" @@ -172,12 +173,26 @@ esp_err_t esp_spiram_add_to_heapalloc() static uint8_t *dma_heap; esp_err_t esp_spiram_reserve_dma_pool(size_t size) { - if (size==0) return ESP_OK; //no-op ESP_EARLY_LOGI(TAG, "Reserving pool of %dK of internal memory for DMA/internal allocations", size/1024); - dma_heap=heap_caps_malloc(size, MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL); - if (!dma_heap) return ESP_ERR_NO_MEM; - uint32_t caps[]={MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}; - return heap_caps_add_region_with_caps(caps, (intptr_t) dma_heap, (intptr_t) dma_heap+size-1); + /* Pool may be allocated in multiple non-contiguous chunks, depending on available RAM */ + while (size > 0) { + size_t next_size = heap_caps_get_largest_free_block(MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL); + next_size = MIN(next_size, size); + + ESP_EARLY_LOGD(TAG, "Allocating block of size %d bytes", next_size); + dma_heap = heap_caps_malloc(next_size, MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL); + if (!dma_heap || next_size == 0) { + return ESP_ERR_NO_MEM; + } + + uint32_t caps[] = { MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_8BIT|MALLOC_CAP_32BIT }; + esp_err_t e = heap_caps_add_region_with_caps(caps, (intptr_t) dma_heap, (intptr_t) dma_heap+next_size-1); + if (e != ESP_OK) { + return e; + } + size -= next_size; + } + return ESP_OK; } size_t esp_spiram_get_size()