Teensy 4.1 extmem_malloc fails


I am using a Teensy 4.1 for a project and need to dynamically allocate and reallocate memory throughout the life of the program. I have soldered on 16mb of psram and the memory test passes . . . but every time i attempt to use extmem_realloc and extmem_malloc it returns null each time and no memory is allocated. Please advise what I need to do. Happy to answer any questions to help get a better view of what may be going on but on my end it just seems those two function are just not working at all.

in case it helps anyone this is the code in question
void* reallocate (GC* gc, void* pointer, size_t oldSize, size_t newSize)
    gc->bytesAllocated += newSize - oldSize;
    if (newSize > oldSize)
        if (debugStressGC) collectGarbage(gc);
        if (gc->bytesAllocated > gc->nextGC) collectGarbage(gc);

    if (newSize == 0)
        return NULL;

    void* result = _realloc(pointer, newSize);
    if (result == NULL)
        printf("realloc error (return NULL) >> %s [%i,%i]\n", (pointer == NULL ? "NULL ptr" : "active ptr"), oldSize, newSize);
    return result;
in above both _free and _realloc is just a wrapper to directly call extmem_free and extmem_realloc since this was a part of a project on a different platform that i was bringing to the teensy

here is the result of the memtest code along with allocation to show u what i mean . . .
extern "C" uint8_t external_psram_size;

bool memory_ok = false;
uint32_t *memory_begin, *memory_end;

bool check_fixed_pattern(uint32_t pattern);
bool check_lfsr_pattern(uint32_t seed);

void setup()
    while (!Serial) ; // wait
    pinMode(13, OUTPUT);
    uint8_t size = external_psram_size;
    Serial.printf("EXTMEM Memory Test, %d Mbyte\n", size);
    if (size == 0) return;
    const float clocks[4] = {396.0f, 720.0f, 664.62f, 528.0f};
    const float frequency = clocks[(CCM_CBCMR >> 8) & 3] / (float)(((CCM_CBCMR >> 29) & 7) + 1);
    Serial.printf(" CCM_CBCMR=%08X (%.1f MHz)\n", CCM_CBCMR, frequency);
    memory_begin = (uint32_t *)(0x70000000);
    memory_end = (uint32_t *)(0x70000000 + size * 1048576);
    elapsedMillis msec = 0;
    if (!check_fixed_pattern(0x5A698421)) return;
    . . . lfsr pattern tests
    . . . fixed pattern tests
    Serial.printf(" test ran for %.2f seconds\n", (float)msec / 1000.0f);
    Serial.println("All memory tests passed :-)");
    memory_ok = true;

    size_t total, totalUser, free;
    int blocks;
    sm_malloc_stats_pool(&extmem_smalloc_pool, &total, &totalUser, &free, &blocks);
        "Total used:       %u bytes\n"
        "Total user vars:  %u bytes\n"
        "Free space:       %.4f MB\n"
        "Allocated blocks: %u\n\n",
        total, totalUser, free / 1024 / 1024.0f, blocks

    void* mem;
    mem = extmem_malloc(1024 * 1024 * 5);
    Serial.printf("10mb allocation >> %s\n", mem == NULL ? "NULL" : "ALLOCATED");

. . . rest of memory test code

EXTMEM Memory Test, 16 Mbyte
CCM_CBCMR=B5AE8304 (88.0 MHz)
. . . many pattern outputs
test ran for 72.86 seconds
All memory tests passed :)
Total used: 0 bytes
Total user vars: 0 bytes
Free space: 15.9990 MB
Allocated blocks: 0

10mb allocation >> NULL
Last edited:
well i figured out the issue
extmem_realloc(pointer, size) . . . does absolutely nothing
sm_realloc_pool(&extmem_smalloc_pool, pointer, size) . . . actually reallocates the external memory
now not saying it just doesnt do anything . . . but calling that from c code is doing nothing . . . i have to use the smalloc functions for it to actually work
Is the initial call made with pointer set to NULL? I could see how that would be a problem.
happens quite a bit. as any new object that needs to be created is first ran through that function. However, since extmem_realloc is simply just a wrapper to the sm_realloc_pool with the addition of seeing if u even have external ram, why would that matter? after i replaced the wrapper with the smalloc functions themselves it worked perfectly fine so im just not understanding why the wrapper wouldnt do the same
Because NULL isn't recognized as a value inside the extmem range, so the call is punted to regular (stdlib) realloc instead of sm_realloc_pool and there may not be enough RAM2/DMAMEM to fulfill the request.
Because NULL isn't recognized as a value inside the extmem range, so the call is punted to regular (stdlib) realloc instead of sm_realloc_pool and there may not be enough RAM2/DMAMEM to fulfill the request.
ok that makes sense. Thanks for letting me know that. will keep that in mind when doing future memory stuffs. Very good to know. But, that does beg the question then why does calling sm_realloc_pool directly allow it to happen? I only briefly looked at the code and it seems to not be doing much beyond wrapping.