Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 24 of 24

Thread: How to display free ram.

  1. #1
    Senior Member
    Join Date
    Feb 2016
    Location
    Australia
    Posts
    282

    How to display free ram.

    With my arduino nano I'm using the following function to display free ram.
    Code:
    int freeRam ()
    {
      extern int __heap_start, *__brkval;
      int v;
      return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
    }
    I don't know what/how that code works but would like an equivalent for teensy 3.2.
    Does anyone know how?
    Thanks.

  2. #2
    Senior Member blackketter's Avatar
    Join Date
    May 2015
    Location
    San Francisco
    Posts
    343
    This seems to work for me:

    Code:
    uint32_t FreeMem(){ // for Teensy 3.0
        uint32_t stackTop;
        uint32_t heapTop;
    
        // current position of the stack.
        stackTop = (uint32_t) &stackTop;
    
        // current position of heap.
        void* hTop = malloc(1);
        heapTop = (uint32_t) hTop;
        free(hTop);
    
        // The difference is (approximately) the free, available ram.
        return stackTop - heapTop;
    }

  3. #3
    Senior Member
    Join Date
    Feb 2016
    Location
    Australia
    Posts
    282
    That worked fine.
    Thanks.

  4. #4
    Senior Member
    Join Date
    Jan 2015
    Location
    SF Bay Area
    Posts
    255
    sdfat library use this for ARM processor

    Code:
    extern "C" char* sbrk(int incr);
    int SdFatUtil::FreeRam() {
      char top;
      return &top - reinterpret_cast<char*>(sbrk(0));
    }
    if you have sdfat library, and #include <SdFatUtil.h>
    you can just call FreeRam();

  5. #5
    Senior Member
    Join Date
    Oct 2015
    Location
    Vermont, USA
    Posts
    312
    Quote Originally Posted by doughboy View Post
    sdfat library use this for ARM processor

    Code:
    extern "C" char* sbrk(int incr);
    int SdFatUtil::FreeRam() {
      char top;
      return &top - reinterpret_cast<char*>(sbrk(0));
    }
    if you have sdfat library, and #include <SdFatUtil.h>
    you can just call FreeRam();
    This is so nice and tight! It doesn't seem to work for Teensy 4, however (I get negative values). Is there any easy mod to get it to work for both T3 and T4?

    Chip

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    25,026
    Try replacing "reinterpret_cast<char*>(sbrk(0))" with "(char *)&_heap_end".

    EDIT: oh, wait... using "&top" is completely wrong for Teensy 4.x.

    Try this instead:

    Code:
    extern unsigned long _heap_start;
    extern unsigned long _heap_end;
    extern char *__brkval;
    
    int freeram() {
      return (char *)&_heap_end - __brkval;
    }
    
    
    void setup() {
      while (!Serial) ;
      Serial.print("freeram = ");
      Serial.println(freeram());
      volatile char *p = (char *)malloc(152000);
      *p = 0;
      Serial.print("freeram = ");
      Serial.println(freeram());
    }
    
    void loop() {
    }
    Last edited by PaulStoffregen; 03-29-2021 at 11:36 PM.

  7. #7
    Senior Member
    Join Date
    Oct 2015
    Location
    Vermont, USA
    Posts
    312
    Seems to work great!

    Thanks!

  8. #8
    Senior Member
    Join Date
    Apr 2019
    Posts
    158
    Is there a way to see RAM usage during program execution, in the similar way as repeatedly calling AudioProcessorUsage()? Thanks.

  9. #9
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    25,026
    With the audio library, you can use AudioMemoryUsage() to see how much of the AudioMemory you reserved is actually in use. Details here:

    https://www.pjrc.com/teensy/td_libs_...onnection.html

    Using the more generic ways discussed on this thread won't work for the audio library. The purpose of using AudioMemory() at the beginning of your program is it takes a portion of Teensy's memory to be constantly allocated for the audio library. So if you use AudioMemory(50) to reserve 50 blocks of audio, to these more generic functions all 50 are always consumed, even if the audio library is only using a portion of them. This is one of the many things the audio library does to minimize the chance of non-audio activity glitching the audio. By keeping all of the audio memory allocated (with respect to the rest of the system) the audio library can manage that memory in a way that gives highly deterministic latency. The downside is all of that memory is dedicated to audio and other libraries can't use any of it, even if the audio library isn't making any use of some portion.

    With regard to the non-audio memory, the code in msg #6 will tell you the portion of RAM2 which is still unused by malloc() & C++ new.



    One way Teensy 4.x differs from earlier Teensy and many other microcontrollers is the local variables are in a physically different memory than the heap for malloc(). A more common arrangement is the heap starts right after the zeroed variable and grows upward in the same memory as the local variables which start at the top and grown downward.

  10. #10
    Senior Member
    Join Date
    Apr 2019
    Posts
    158
    Ok, I'm asking because I tried the code in #6 expecting to see the free RAM size change when called during execution, but it stays the same value. I think I'm misunderstanding something. I was hoping to see if available RAM runs out during execution.
    Last edited by UHF; 04-03-2021 at 02:28 PM.

  11. #11
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    25,026
    If you run the code from msg #6 and change the number of bytes in the line with malloc(), you should see the reported memory usage change.

  12. #12
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    119
    Am I right in thinking that using __brkval only shows you the "most ever" used heap memory, rather than some estimate of the "current state"? I'm interested in checking for the latter, to ensure (barring fragmentation issues) that a piece of code doesn't have a memory leak. I'm now using:
    Code:
    extern unsigned long _heap_end;
    extern char *__brkval;
    uint32_t FreeMem(){ // for Teensy 4.1
      char* p = (char*) malloc(10000); // size should be quite big, to avoid allocating fragment!
      free(p);
      return (char *)&_heap_end - p; // __brkval;
    }
    The 10000-byte allocation size ensures (in my use case) that p isn't inside the possibly-fragmented start of the heap, giving a misleading idea of the space remaining at the time of the call.

    Cheers

    Jonathan
    Last edited by h4yn0nnym0u5e; 05-05-2021 at 11:25 AM.

  13. #13
    Quote Originally Posted by PaulStoffregen View Post
    With the audio library, you can use AudioMemoryUsage() to see how much of the AudioMemory you reserved is actually in use. Details here:

    https://www.pjrc.com/teensy/td_libs_...onnection.html

    Using the more generic ways discussed on this thread won't work for the audio library. The purpose of using AudioMemory() at the beginning of your program is it takes a portion of Teensy's memory to be constantly allocated for the audio library. So if you use AudioMemory(50) to reserve 50 blocks of audio, to these more generic functions all 50 are always consumed, even if the audio library is only using a portion of them. This is one of the many things the audio library does to minimize the chance of non-audio activity glitching the audio. By keeping all of the audio memory allocated (with respect to the rest of the system) the audio library can manage that memory in a way that gives highly deterministic latency. The downside is all of that memory is dedicated to audio and other libraries can't use any of it, even if the audio library isn't making any use of some portion.

    With regard to the non-audio memory, the code in msg #6 will tell you the portion of RAM2 which is still unused by malloc() & C++ new.



    One way Teensy 4.x differs from earlier Teensy and many other microcontrollers is the local variables are in a physically different memory than the heap for malloc(). A more common arrangement is the heap starts right after the zeroed variable and grows upward in the same memory as the local variables which start at the top and grown downward.
    Can someone confirm that when you use AudioMemory you are essentially reserving a section of RAM2 for sole use by the audio library? So, for example, if I set AudioMemory(64) I'd be reserving 64 blocks, 16384 bytes in RAM2?

  14. #14
    Member
    Join Date
    Jan 2013
    Posts
    29
    I don't know about audio, but you can find out where things live by comparing with the linker load map (tl062_t41.ld):

    Code:
    	ITCM (rwx):  ORIGIN = 0x00000000, LENGTH = 512K
    	DTCM (rwx):  ORIGIN = 0x20000000, LENGTH = 512K
    	RAM (rwx):   ORIGIN = 0x20200000, LENGTH = 512K
    	FLASH (rwx): ORIGIN = 0x60000000, LENGTH = 7936K
    	ERAM (rwx):  ORIGIN = 0x70000000, LENGTH = 16384K
    (RAM is RAM2 in the image, ERAM is PSRAM in the image)
    So if you have a pointer to something, print it out in hex and compare.

  15. #15
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,067
    Seems as a macro the data will be a STATIC allocation, and then code to pass the resulting data pointer to the Audio system?

    It does indeed do the alloc from DMAMEM/RAM2: {local install}\hardware\teensy\avr\cores\teensy4\AudioSt ream.h
    Code:
    #define AudioMemory(num) ({ \
    	static DMAMEM audio_block_t data[num]; \
    	AudioStream::initialize_memory(data, num); \
    })
    And that will alloc 260 bytes per usable block?
    Code:
    #define AUDIO_BLOCK_SAMPLES  128
    ...
    typedef struct audio_block_struct {
    	uint8_t  ref_count;
    	uint8_t  reserved1;
    	uint16_t memory_pool_index;
    	int16_t  data[AUDIO_BLOCK_SAMPLES];
    } audio_block_t;

  16. #16
    Member
    Join Date
    Jan 2013
    Posts
    29
    Here's some code to get to grips with memory layout and use (for the Teensy 4.1):

    Code:
    void memInfo () {
        constexpr auto RAM_BASE   = 0x2020'0000;
        constexpr auto RAM_SIZE   = 512 << 10;
        constexpr auto FLASH_BASE = 0x6000'0000;
        constexpr auto FLASH_SIZE = 8 << 20;
    
        extern char _stext[],_etext[],_sbss[],_ebss[],_sdata[],_edata[],_estack[],
                _heap_start[],_heap_end[],_extram_start[],_extram_end[],*__brkval;
    
        char* sp = __builtin_frame_address(0);
    
        Serial.printf("_stext        %08x\n",      _stext);
        Serial.printf("_etext        %08x +%db\n", _etext, _etext-_stext);
        Serial.printf("_sdata        %08x\n",      _sdata);
        Serial.printf("_edata        %08x +%db\n", _edata, _edata-_sdata);
        Serial.printf("_sbss         %08x\n",      _sbss);
        Serial.printf("_ebss         %08x +%db\n", _ebss, _ebss-_sbss);
        Serial.printf("curr stack    %08x +%db\n", sp, sp-_ebss);
        Serial.printf("_estack       %08x +%db\n", _estack, _estack-sp);
        Serial.printf("_heap_start   %08x\n",      _heap_start);
        Serial.printf("__brkval      %08x +%db\n", __brkval, __brkval-_heap_start);
        Serial.printf("_heap_end     %08x +%db\n", _heap_end, _heap_end-__brkval);
        Serial.printf("_extram_start %08x\n",      _extram_start);
        Serial.printf("_extram_end   %08x +%db\n", _extram_end,
                                                    _extram_end-_extram_start);
        Serial.printf("\n");
    
        Serial.printf("<ITCM>  %08x .. %08x\n",
                _stext, _stext + ((int) _itcm_block_count << 15) - 1);
        Serial.printf("<DTCM>  %08x .. %08x\n",
                _sdata, _estack - 1);
        Serial.printf("<RAM>   %08x .. %08x\n",
                RAM_BASE, RAM_BASE + RAM_SIZE - 1);
        Serial.printf("<FLASH> %08x .. %08x\n",
                FLASH_BASE, FLASH_BASE + FLASH_SIZE - 1);
        Serial.printf("<PSRAM> %08x .. %08x\n",
                _extram_start, _extram_start + (external_psram_size<<20) - 1);
        Serial.printf("\n");
    
        auto stack = sp-_ebss,
             heap = _heap_end-__brkval,
             psram = _extram_start + (external_psram_size<<20) - _extram_end;
        Serial.printf("avail STACK %8d b %5d kb\n", stack, stack>>10);
        Serial.printf("avail HEAP  %8d b %5d kb\n", heap, heap>>10);
        Serial.printf("avail PSRAM %8d b %5d kb\n", psram, psram>>10);
    }
    Sample output with PSRAM fitted:

    Code:
    _stext        00000000
    _etext        00006128 +24872b
    _sdata        20000000
    _edata        2000133c +4924b
    _sbss         2000133c
    _ebss         200032e0 +8100b
    curr stack    20077fd0 +478448b
    _estack       20078000 +48b
    _heap_start   20203060
    __brkval      2021d000 +106400b
    _heap_end     20280000 +405504b
    _extram_start 70000000
    _extram_end   70000000 +0b
    
    <ITCM>  00000000 .. 00007fff
    <DTCM>  20000000 .. 20077fff
    <RAM>   20200000 .. 2027ffff
    <FLASH> 60000000 .. 607fffff
    <PSRAM> 70000000 .. 707fffff
    
    avail STACK   478448 b   467 kb
    avail HEAP    405504 b   396 kb
    avail PSRAM  8388608 b  8192 kb
    A bit over the top perhaps, but at least it helped me better understand how things are laid out.
    I didn't find an easy way to get at the PSRAM high-water mark in the SMalloc code.
    Last edited by jcw; 07-29-2021 at 06:42 PM. Reason: remove redundant value

  17. #17
    Thanks JCW and defragster, starting to understand how and where the memory goes now which is great. I'm suffering random crashes on a Teensy 4.1 so wanting to understand exactly what's where so I can diagnose the issue.

  18. #18
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,067
    @jcw - made sketch below and it hits CrashReport - and the ELF search worked to show line #47 - in RED. And printing stop short of that line?
    Running on a T_4.1 with twin PSRAM's.

    @Paul: Good work on the CrashReport output message! It found the line and 'addr2line' even in my path.

    Code:
    Added this line to see the value of _itcm_block_count and it faults on this line:
      Serial.printf("_itcm_block_count %08x\n",      _itcm_block_count);
    Code:
    T:\TEMP\arduino_build_T4MemInfo.ino>addr2line -e T4MemInfo.ino.elf 0x166
    T:\tCode\Memory\T4MemInfo/T4MemInfo.ino:47
    Code:
    T:\tCode\Memory\T4MemInfo\T4MemInfo.ino Jul 29 2021 12:59:38
    CrashReport:
      A problem occurred at (system time) 11:59:45
      Code was executing from address 0x166
      CFSR: 82
    	(DACCVIOL) Data Access Violation
    	(MMARVALID) Accessed Address: 0x1 (nullptr)
    	  Check code at 0x166 - very likely a bug!
    	  Run "addr2line -e mysketch.ino.elf 0x166" for filename & line number.
      Temperature inside the chip was 48.33 C
      Startup CPU clock speed is 600MHz
      Reboot was caused by auto reboot after fault or bad interrupt detected
    _stext        00000000
    _etext        00006198 +24984b
    _sdata        20000000
    _edata        20001818 +6168b
    _sbss         20001818
    _ebss         200042c0 +10920b
    curr stack    20077fd0 +474384b
    _estack       20078000 +48b
    _heap_start   20203060
    __brkval      20203060 +0b
    _heap_end     20280000 +511904b
    _extram_start 70000000
    _extram_end   70000000 +0b
    
    Fault 1

    Code:
    void setup() {
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(115200);
      while (!Serial);
      Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
      if ( CrashReport ) Serial.print ( CrashReport );
      memInfo();
    }
    
    
    void loop() {
      // put your main code here, to run repeatedly:
    
    }
    
    extern unsigned long _itcm_block_count;
    extern uint32_t external_psram_size;
    
    void memInfo () {
      constexpr auto RAM_BASE   = 0x20200000;
      constexpr auto RAM_SIZE   = 512 << 10;
      constexpr auto FLASH_BASE = 0x60000000;
      constexpr auto FLASH_SIZE = 8 << 20;
    
      extern char _stext[], _etext[], _sbss[], _ebss[], _sdata[], _edata[], _estack[],
             _heap_start[], _heap_end[], _extram_start[], _extram_end[], *__brkval;
    
      char* sp = __builtin_frame_address(0);
    
      Serial.printf("_stext        %08x\n",      _stext);
      Serial.printf("_etext        %08x +%db\n", _etext, _etext - _stext);
      Serial.printf("_sdata        %08x\n",      _sdata);
      Serial.printf("_edata        %08x +%db\n", _edata, _edata - _sdata);
      Serial.printf("_sbss         %08x\n",      _sbss);
      Serial.printf("_ebss         %08x +%db\n", _ebss, _ebss - _sbss);
      Serial.printf("curr stack    %08x +%db\n", sp, sp - _ebss);
      Serial.printf("_estack       %08x +%db\n", _estack, _estack - sp);
      Serial.printf("_heap_start   %08x\n",      _heap_start);
      Serial.printf("__brkval      %08x +%db\n", __brkval, __brkval - _heap_start);
      Serial.printf("_heap_end     %08x +%db\n", _heap_end, _heap_end - __brkval);
      Serial.printf("_extram_start %08x\n",      _extram_start);
      Serial.printf("_extram_end   %08x +%db\n", _extram_end, _extram_end - _extram_start);
      Serial.printf("\n");
    
      Serial.printf("Fault 1\n");
      Serial.flush(); delay(10);
      Serial.printf("<ITCM>  %08x .. %08x\n", _stext, _stext + ((int) _itcm_block_count << 15) - 1); //line 47
      Serial.printf("Fault 2\n");
      Serial.flush(); delay(10);
      Serial.printf("<DTCM>  %08x .. %08x\n",
                    _sdata, _estack - 1);
      Serial.printf("<RAM>   %08x .. %08x\n",
                    RAM_BASE, RAM_BASE + RAM_SIZE - 1);
      Serial.printf("<FLASH> %08x .. %08x\n",
                    FLASH_BASE, FLASH_BASE + FLASH_SIZE - 1);
      Serial.printf("<PSRAM> %08x .. %08x\n",
                    _extram_start, _extram_start + (external_psram_size << 20) - 1);
      Serial.printf("\n");
    
      auto stack = sp - _ebss,
           heap = _heap_end - __brkval,
           psram = _extram_start + (external_psram_size << 20) - _extram_end;
      Serial.printf("avail STACK %8d b %5d kb\n", stack, stack >> 10);
      Serial.printf("avail HEAP  %8d b %5d kb\n", heap, heap >> 10);
      Serial.printf("avail PSRAM %8d b %5d kb\n", psram, psram >> 10);
    }

  19. #19
    Member
    Join Date
    Jan 2013
    Posts
    29
    Yeah, my bad - I left out some important definitions. Change the definition to:

    Code:
    extern char _itcm_block_count [];
    .

    This is nasty linker stuff. The address is the value, it's not a variable, i.e. it's not a memory location.
    Also: "external_psram_size" is a byte, not a long ... I think.

    Update - I've placed a better version at https://gist.github.com/jcw/73b2c29f...8fb577035d248d.
    Last edited by jcw; 07-29-2021 at 09:05 PM.

  20. #20
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,067
    Copied new memInfo () code and it still faulting here ???

    Indeed :: extern "C" uint8_t external_psram_size;

  21. #21
    Member
    Join Date
    Jan 2013
    Posts
    29
    I've pasted the code at https://gist.github.com/jcw/73b2c29f...8fb577035d248d
    That way it can be edited/fixed/tweaked without cluttering up this forum with buggy code.

  22. #22
    +1 on CrashReport, looks like exactly what I need to figure out what's going on in my code. Thanks for sharing.

  23. #23
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,067
    Great - That works without problem.

    Code:
    T:\tCode\Memory\T4MemInfo\T4MemInfo.ino Jul 29 2021 14:45:17
    _stext        00000000
    _etext        00006158 +24920b
    _sdata        20000000
    _edata        20001800 +6144b
    _sbss         20001800
    _ebss         200042c0 +10944b
    curr stack    20077fd0 +474384b
    _estack       20078000 +48b
    _heap_start   20203060
    __brkval      20203060 +0b
    _heap_end     20280000 +511904b
    _extram_start 70000000
    _extram_end   70000000 +0b
    
    <ITCM>  00000000 .. 00007fff
    <DTCM>  20000000 .. 20077fff
    <RAM>   20200000 .. 2027ffff
    <FLASH> 60000000 .. 607fffff
    <PSRAM> 70000000 .. 70ffffff
    
    avail STACK   474384 b   463 kb
    avail HEAP    511904 b   499 kb
    avail PSRAM 16777216 b 16384 kb

  24. #24
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,067
    This from last edit 6 months back - this works when getFreeITCM() called from the linked setup() to Set a pointer to FREE RAM in the ITCM section - and get the size of that 'orphaned' area.
    Code:
    uint32_t *ptrFreeITCM;  // Set to Usable ITCM free RAM
    uint32_t  sizeofFreeITCM; // sizeof free RAM in uint32_t units.
    uint32_t  SizeLeft_etext;
    extern unsigned long _stext;
    extern unsigned long _etext;
    FLASHMEM
    void   getFreeITCM() { // end of CODE ITCM, skip full 32 bits
      Serial.println("\n\n++++++++++++++++++++++");
      SizeLeft_etext = (32 * 1024) - (((uint32_t)&_etext - (uint32_t)&_stext) % (32 * 1024));
      sizeofFreeITCM = SizeLeft_etext - 4;
      sizeofFreeITCM /= sizeof(ptrFreeITCM[0]);
      ptrFreeITCM = (uint32_t *) ( (uint32_t)&_stext + (uint32_t)&_etext + 4 );
      printf( "Size of Free ITCM in Bytes = %u\n", sizeofFreeITCM * sizeof(ptrFreeITCM[0]) );
      printf( "Start of Free ITCM = %u [%X] \n", ptrFreeITCM, ptrFreeITCM);
      printf( "End of Free ITCM = %u [%X] \n", ptrFreeITCM + sizeofFreeITCM, ptrFreeITCM + sizeofFreeITCM);
      for ( uint ii = 0; ii < sizeofFreeITCM; ii++) ptrFreeITCM[ii] = 1;
      uint jj = 0;
      for ( uint ii = 0; ii < sizeofFreeITCM; ii++) jj += ptrFreeITCM[ii];
      printf( "ITCM DWORD cnt = %u [#bytes=%u] \n", jj, jj*4);
    }
    Check just now it was still writeable - with the added for() loops at the end of getFreeITCM().

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •