I have raised an issue against the esp-idf for this bug:
https://github.com/espressif/esp-idf/issues/7808.
Since Espressif implemented the TLSF allocator (commit bd9b921713d80) on October 2020 the semantics of
heap_cap_get_largest_free_block() has changed. It now returns the largest allocatable block rounded down to the nearest power of 2. This is also in disagreement with the documentation
https://docs.espressif.com/projects/esp ... k8uint32_t.
Micropython uses this function to calculate how much memory to allocate for the micropython heap:
ports/esp32/main.c:main_task(), which gets rounded down from 110592 bytes to 65536 bytes on the esp32. This only affects non SPIRAM modules.
The following quick hack patch works around this issue by using the returned value as a starting point and searching for the largest allocatable block by iteration.
I'll also post an issue against micropython for this upstream bug.
EDIT: Also note that on the ESP32S2 this fix will increase the amount of RAM allocated to the gc heap from 128k to 157k (which may starve the IDF chip functions of allocatable memory). The available memory on the ESP32S2 is less fragmented than the ESP32.
Code: Select all
diff --git a/ports/esp32/main.c b/ports/esp32/main.c
index 2ba613668..dce82b7fb 100644
--- a/ports/esp32/main.c
+++ b/ports/esp32/main.c
@@ -131,7 +131,20 @@ void mp_task(void *pvParameter) {
#else
// Allocate the uPy heap using malloc and get the largest available region
size_t mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
- void *mp_task_heap = malloc(mp_task_heap_size);
+ void *mp_task_heap;
+ for (size_t incr = mp_task_heap_size >> 1;
+ incr > 4;
+ incr >>= 1)
+ {
+ mp_task_heap_size += incr;
+ mp_task_heap = heap_caps_malloc(mp_task_heap_size, MALLOC_CAP_8BIT);
+ if (mp_task_heap == NULL) {
+ mp_task_heap_size -= incr;
+ }
+ heap_caps_free(mp_task_heap);
+ printf("HeapSize=0x%x %d\n", mp_task_heap_size, mp_task_heap_size);
+ }
+ mp_task_heap = malloc(mp_task_heap_size);
#endif
soft_reset: