Jelajahi Sumber

esp32: Allow SPIRAM_MALLOC_RESERVE_INTERNAL to span multiple regions of memory

- Allocate this pool after main_task is running, so it can use startup stack RAM
- Raise the maximum allowed value in KConfig to 256KB
- Based on forum discussions https://esp32.com/viewtopic.php?f=2&t=6550&sid=76cd27bda76c6d0e83d3fcc9ec30c650&start=10#p28253
Angus Gratton 7 tahun lalu
induk
melakukan
304e9085eb
3 mengubah file dengan 34 tambahan dan 13 penghapusan
  1. 5 1
      components/esp32/Kconfig
  2. 9 7
      components/esp32/cpu_start.c
  3. 20 5
      components/esp32/spiram.c

+ 5 - 1
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

+ 9 - 7
components/esp32/cpu_start.c

@@ -269,13 +269,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
@@ -445,6 +438,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))

+ 20 - 5
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 <stdint.h>
 #include <string.h>
+#include <sys/param.h>
 
 #include "sdkconfig.h"
 #include "esp_attr.h"
@@ -138,12 +139,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()