T4.0 Memory - trying to make sense of the different regions

@defragster - wonder if I need to learn more about how VS... works and try to build a version that is totally stand alone and does not require run time support?
 
@defragster - wonder if I need to learn more about how VS... works and try to build a version that is totally stand alone and does not require run time support?

Everything is so in paranoid mode {justifiably} - download an office DOC and it can't run/edit/print without APPROVE.

I opened the imxtr-size github VS SLN file - and had to APPROVE it to open to build! It does build and run fine.

There is a way to PACK an app to hold what it needs - or perhaps auto install it. That probably has issues as well as there are blocks to running EXE's on machines other than yours - with some extension to DEV machines? Though in that case it likely has the needed DLL's.

I did it once for a VB app in the last year - worked well as I had to update it for a failed USB Touch screen's new model and put on a new computer.

Perhaps this is the start link for this app deploy?:: deploying-native-desktop-applications-visual-cpp?view=vs-2019
 
Quick followup to this old thread. Teensyduino 1.49 was recently released, making the "FLASHMEM" name official.

Generally, PROGMEM is meant for variables and FLASHMEM is meant for functions. They do the same thing, but we need 2 different names because of a limitation in the way the compiler handles sections within the same compiled file.
 
When did it happen that OCRAM is in use in a blank program, and what uses OCRAM here?
My RAM-Info says, 12384 bytes are not available.

I tried to use a 512kB Block.. and was sure that it is free..
 
The USB buffers grew in 1.49 and moved to OCRAM, so they're not burning up precious high-speed DTCM.

If you run the USB lines/sec benchmark, you'll see 1.49 is much faster (and again, pushing the limits on Windows & Macs, even with the serial monitor speedups). Larger USB packet sizes and bigger USB buffers and multiple transfer queuing improvements are most of the reason for the speed increase.

Just to give you fair warning, I'm also planning to do something similar with the SD library later this year. Today it allocates a single 512 byte sector buffer in DTCM. Eventually that will become a cache (like the experimental speedup work from before Teensy 3.6), probably between 20K to 40K in size, allocated in OCRAM.

Ethernet support on Teensy 4.1 will also allocate a chunk of OCRAM for packet buffers.

Also... I have special plans for the last 4K of OCRAM. Future linker scripts and default MPU settings may cause those 4096 bytes to be unusable.
 
Ah, ok , good to know. Thank you :)
Is there a way (for annyoing users like me) to change this without patching teensyduino? Or can be added a "#ifdef" for that?
 
@DD4WH, others:
here is a better (more exact) version of the Runtime-Ram-Info:
Code:
/*
  (c) Frank B, 2020
  License: MIT
  Please keep this info.
*/

inline
unsigned memfree(void) {
  extern unsigned long _ebss;
  extern unsigned long _sdata;
  extern unsigned long _estack;
  const unsigned DTCM_START = 0x20000000UL;
  unsigned dtcm = (unsigned)&_estack - DTCM_START;
  unsigned stackinuse = (unsigned) &_estack -  (unsigned) __builtin_frame_address(0);
  unsigned varsinuse = (unsigned)&_ebss - (unsigned)&_sdata;
  unsigned freemem = dtcm - (stackinuse + varsinuse);
  return freemem;
}

FLASHMEM
void flexRamInfo(void) {

#if defined(ARDUINO_TEENSY40)
  static const unsigned DTCM_START = 0x20000000UL;
  static const unsigned OCRAM_START = 0x20200000UL;
  static const unsigned OCRAM_SIZE = 512;
  static const unsigned FLASH_SIZE = 1984;
#elif defined(ARDUINO_TEENSY41)
  static const unsigned DTCM_START = 0x20000000UL;
  static const unsigned OCRAM_START = 0x20200000UL;
  static const unsigned OCRAM_SIZE = 512;
  static const unsigned FLASH_SIZE = 7936;
#endif

  Serial.println(__FILE__ " " __DATE__ " " __TIME__ );
  Serial.print("Teensyduino version ");
  Serial.println(TEENSYDUINO / 100.0f);
  Serial.println();

  int itcm = 0;
  int dtcm = 0;
  int ocram = 0;
  uint32_t gpr17 = IOMUXC_GPR_GPR17;

  char __attribute__((unused)) dispstr[17] = {0};
  dispstr[16] = 0;

  for (int i = 15; i >= 0; i--) {
    switch ((gpr17 >> (i * 2)) & 0b11) {
      default: dispstr[15 - i] = '.'; break;
      case 0b01: dispstr[15 - i] = 'O'; ocram++; break;
      case 0b10: dispstr[15 - i] = 'D'; dtcm++; break;
      case 0b11: dispstr[15 - i] = 'I'; itcm++; break;
    }
  }

  Serial.printf("ITCM: %dkB, DTCM: %dkB, OCRAM: %d(+%d)kB [%s]\n", itcm * 32, dtcm * 32, ocram * 32, OCRAM_SIZE, dispstr);
  const char* fmtstr = "%-6s%7d %5.02f%% of %4dkB (%7d Bytes free) %s\n";

  extern unsigned long _stext;
  extern unsigned long _etext;
  extern unsigned long _sdata;
  extern unsigned long _ebss;
  extern unsigned long _flashimagelen;
  extern unsigned long _heap_start;
  extern unsigned long _estack;

  Serial.printf(fmtstr, "ITCM:",
                (unsigned)&_etext - (unsigned)&_stext,
                (float)((unsigned)&_etext - (unsigned)&_stext) / ((float)itcm * 32768.0f) * 100.0f,
                itcm * 32,
                itcm * 32768 - ((unsigned)&_etext - (unsigned)&_stext), "(RAM1) FASTRUN");

  Serial.printf(fmtstr, "OCRAM:",
                (unsigned)&_heap_start - OCRAM_START,
                (float)((unsigned)&_heap_start - OCRAM_START) / (OCRAM_SIZE * 1024.0f) * 100.0f,
                OCRAM_SIZE,
                OCRAM_SIZE * 1024 - ((unsigned)&_heap_start - OCRAM_START), "(RAM2) DMAMEM, Heap");

  Serial.printf(fmtstr, "FLASH:",
                (unsigned)&_flashimagelen,
                ((unsigned)&_flashimagelen) / (FLASH_SIZE * 1024.0f) * 100.0f,
                FLASH_SIZE,
                FLASH_SIZE * 1024 - ((unsigned)&_flashimagelen), "FLASHMEM, PROGMEM");

  // Serial.println();
  unsigned _dtcm = (unsigned)&_estack - DTCM_START; //or, one could use dtcm * 32768 here.
  unsigned stackinuse = (unsigned) &_estack -  (unsigned) __builtin_frame_address(0);
  unsigned varsinuse = (unsigned)&_ebss - (unsigned)&_sdata;
  unsigned freemem = _dtcm - stackinuse - varsinuse;
  Serial.printf("DTCM:\n  %7d Bytes (%d kB)\n", _dtcm, _dtcm / 1024);
  Serial.printf("- %7d Bytes (%d kB) global variables\n", varsinuse, varsinuse / 1024);
  Serial.printf("- %7d Bytes (%d kB) stack (currently)\n", stackinuse, stackinuse / 1024);
  Serial.println("=========");
  Serial.printf("  %7d Bytes free (%d kB), %d Bytes in use (%d kB).\n",
                _dtcm - (varsinuse + stackinuse), (_dtcm - (varsinuse + stackinuse)) / 1024,
                varsinuse + stackinuse, (varsinuse + stackinuse) / 1024
               );
}


void setup() {
   while (!Serial && millis() < 4000);   
   flexRamInfo();
  // Serial.println(memfree());
}

void loop() {
}

Output looks like this:
Code:
C:\Users\Frank\Documents\Arduino\sketch_jan24a\sketch_jan24a.ino Jan 24 2020 15:45:33

Teensyduino version 1.49

ITCM: 32kB, DTCM: 480kB, OCRAM: 0(+512)kB [DDDDDDDDDDDDDDDI]
ITCM:   23584 71.97% of   32kB (   9184 Bytes free) (RAM1) FASTRUN
OCRAM:  12384  2.36% of  512kB ( 511904 Bytes free) (RAM2) DMAMEM
FLASH:  33920  1.62% of 2048kB (2063232 Bytes free) FLASHMEM, PROGMEM
DTCM:
   491520 Bytes (480 kB)
-   12992 Bytes (12 kB) global variables
-      80 Bytes (0 kB) stack (currently)
=========

   478448 Bytes free (467 kB), 13072 Bytes in use (12 kB).

memfree() can tell you the currently(depends on the stack-usage!) free memory in DTCM.
 
Last edited:
..and if you want to know the maximal stack usage during runtime,
this should give an answer:
(well, if there is no horrible bug)

Code:
extern "C" {
void startup_late_hook(void) {
  extern unsigned long _ebss;
  unsigned long * p =  &_ebss; 
  size_t size = (size_t)(uint8_t*)__builtin_frame_address(0) - 16 - (uintptr_t) &_ebss;
  memset((void*)p, 0, size);  
}
}

unsigned long maxstack() {
  extern unsigned long _ebss;
  extern unsigned long _estack;
  unsigned long * p =  &_ebss;  
  while (*p == 0) p++;
  return (unsigned) &_estack - (unsigned) p;
}

Call maxstack() at the end of your program for example.
 
Good MemInfo Frank.

needs line added in setup():
Code:
void setup() {
  [B]while (!Serial && millis() < 4000);[/B]
  flexRamInfo();

I did a sketch that gets the used ITCM boundary and gets a pointer to the free RAM before DTCM starts - might be small or large part of 32KB. You could probably do that better.
 
No
(addsomedummycharacters)

Okay, Here is what I did - added to your code here with call to getFreeITCM():
Code:
#if defined(__IMXRT1062__) // Get Pointer to FREE ITCM
uint32_t *ptrFreeITCM;  // Set to Usable ITCM free RAM
uint32_t  sizeofFreeITCM; // sizeof free RAM in uint32_t units.
uint32_t  SizeLeft_etext;
FLASHMEM
void   getFreeITCM() { // end of CODE ITCM, skip full 32 bits
  extern unsigned long _stext;
  extern unsigned long _etext;
  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 );
  Serial.printf( "Size of Free ITCM in Bytes = %u\n", sizeofFreeITCM*sizeof(ptrFreeITCM[0]) );
  Serial.printf( "Start of Free ITCM = %u [%X] \n", ptrFreeITCM, ptrFreeITCM);
  Serial.printf( "End of Free ITCM = %u [%X] \n", ptrFreeITCM + sizeofFreeITCM, ptrFreeITCM + sizeofFreeITCM);
}
#else
void   getFreeITCM() {}
#endif

Code:
T:\tCode\T4\T4_MemoryInfo\T4_MemoryInfo.ino Jan 24 2020 11:48:53
Teensyduino version 1.49

ITCM: 32kB, DTCM: 480kB, OCRAM: 0(+512)kB [DDDDDDDDDDDDDDDI]
ITCM:   24176 73.78% of   32kB (   8592 Bytes free) (RAM1) FASTRUN
OCRAM:  12384  2.36% of  512kB ( 511904 Bytes free) (RAM2) DMAMEM
FLASH:  34768  1.66% of 2048kB (2062384 Bytes free) FLASHMEM, PROGMEM
DTCM:
   491520 Bytes (480 kB)
-   12992 Bytes (12 kB) global variables
-      96 Bytes (0 kB) stack (currently)
=========
   478432 Bytes free (467 kB), 13088 Bytes in use (12 kB).
memfree()=478504
maxstack()=1348


++++++++++++++++++++++
Size of Free ITCM in Bytes = 8588
Start of Free ITCM = 24180 [5E74] 
End of Free ITCM = 32768 [8000]

btw: Static RAM can be allocated in ITCM :: FASTRUN byte fill[10000];
Doing that pushes ITCM to a second 32KB segment giving:
++++++++++++++++++++++
Size of Free ITCM in Bytes = 31900
Start of Free ITCM = 33636 [8364]
End of Free ITCM = 65536 [10000]
Funny note: If not 'used' the build drops that 'fill[]' from allocation
 
Last edited:
Great. Not easy to use - It's quite possible that if you change only one line in your program, the free space can be the half or even near zero :) - or you can get the opposite effect if one more 32kB page gets allocated.
But may be useful sometimes.
 
Great. Not easy to use - It's quite possible that if you change only one line in your program, the free space can be the half or even near zero :)
But may be usefule sometimes.

Yes that is true, that space is build dependant. But at runtime when RAM is short the size might be enough to avoid a malloc() of 4 times slower RAM that would end up polluting the DMAMEM/RAM2 cache for other data.

It might go to Zero or it might go to almost 32KB.
 
@Frank - did you see that KurtE updated github.com/KurtE/imxrt-size that you originally made?
FlexRAM section ITCM+DTCM = 512 KB
Config : aaaaaaaf
ITCM : 33632 B (51.32% of 64 KB)
DTCM : 12992 B ( 2.83% of 448 KB)
Available for Stack: 445760
OCRAM: 512KB
DMAMEM: 12384 B ( 2.36% of 512 KB)
Available for Heap: 511904 B (97.64% of 512 KB)
Flash: 42992 B ( 2.12% of 1984 KB)
 
@Frank - did you see that KurtE updated github.com/KurtE/imxrt-size that you originally made?

Yes :)

I don't use it anymore.

Edit: Would have been nice to see my name there - but OK, not really needed for such a dumb program with a few lines.
I'm using the sketch-version now - needs no patches and is more exact (stack-usage). I have it in a lib. Maybe I add it to the button-lib.
 
Last edited:
Yes :)

I don't use it anymore.

Edit: Would have been nice to see my name there - but OK, not really needed for such a dumb program with a few lines.
Could have sworn that some of the comments earlier in this thread already did mention that you started the imxrt-size stuff... :eek:

Also I believe credited you with how to add a call to it in platform.txt...

But with simple things like this, sometimes things like readme files don't exist... It was simply put up to github as there were requests to do so...

As for credit for things... I don't worry too much about others grabbing credit for some of the things that I do... or not, especially when some things like that are things that I borrowed from others and others from me, going back to probably the first Microcontrollers I ever played with.

Example when we were playing with the uncanny eyes code, and made a version that runs with the eyes being updated by DMA. I was worried about memory usage and the like.

So the example sketch in the current library: uncannyEyes_async_st7789_240x240.ino has things in it that print out some memory info and then at times figure out about how much stack is used.
It does not generate as pretty of output as your new stuff, but got the job done:
Code:
// from the linker
//  extern unsigned long _stextload;
extern unsigned long _stext;
extern unsigned long _etext;
//  extern unsigned long _sdataload;
extern unsigned long _sdata;
extern unsigned long _edata;
extern unsigned long _sbss;
extern unsigned long _ebss;
//  extern unsigned long _flexram_bank_config;
extern unsigned long _estack;

void DumpMemoryInfo() {
#if defined(__IMXRT1062__)
  uint32_t flexram_config = IOMUXC_GPR_GPR17;
  Serial.printf("IOMUXC_GPR_GPR17:%x IOMUXC_GPR_GPR16:%x IOMUXC_GPR_GPR14:%x\n",
                flexram_config, IOMUXC_GPR_GPR16, IOMUXC_GPR_GPR14);
  Serial.printf("Initial Stack pointer: %x\n", &_estack);
  uint32_t dtcm_size = 0;
  uint32_t itcm_size = 0;
  for (; flexram_config; flexram_config >>= 2) {
    if ((flexram_config & 0x3) == 0x2) dtcm_size += 32768;
    else if ((flexram_config & 0x3) == 0x3) itcm_size += 32768;
  }
  Serial.printf("ITCM allocated: %u  DTCM allocated: %u\n", itcm_size, dtcm_size);
  Serial.printf("ITCM init range: %x - %x Count: %u\n", &_stext, &_etext, (uint32_t)&_etext - (uint32_t)&_stext);
  Serial.printf("DTCM init range: %x - %x Count: %u\n", &_sdata, &_edata, (uint32_t)&_edata - (uint32_t)&_sdata);
  Serial.printf("DTCM cleared range: %x - %x Count: %u\n", &_sbss, &_ebss, (uint32_t)&_ebss - (uint32_t)&_sbss);
  Serial.println("Now fill rest of DTCM with known pattern"); Serial.flush(); //
  // Guess of where it is safe to fill memory... Maybe address of last variable we have defined - some slop...
  for (uint32_t *pfill = (&_ebss + 1); pfill < (&itcm_size - 10); pfill++) {
    *pfill = 0x01020304;  // some random value
  }
#endif
}
void EstimateStackUsage() {
#if defined(__IMXRT1062__)
  uint32_t *pmem = (&_ebss + 1);
  while (*pmem == 0x01020304) pmem++;
  Serial.printf("Estimated max stack usage: %d\n", (uint32_t)&_estack - (uint32_t)pmem);
#endif
}
 
As I said, not a big problem - but if you copy 99% of a whole program, modify just a very few lines and upload to another platform( Github) a little info there (Github) is nice.
Here, it's not needed. Here, with copying some lines or functions, I'm 100% with you.
Thanks :)

Let's forget that :)
 
Yes :)

I don't use it anymore.

I still use it - added it to TSet so it is there on every build as needed for reference - and not tied to TeensyDuino/Arduino install/build. It was updated to match changing T4's 1062 from original 1052 allocations. This thread was created because there was much mystery around the memory - then Paul wrote up the info on the product page.

That TSet with your Compile.CMD trick is very nice to compile form a real editor - and have an easy way to build for multiple Teensy's at the same time without the IDE. I edited it to run differently when clicked from File Explorer for from a CMD window so it doesn't auto close/exit so it can even build when editor is closed.

Great to see you back online after your last sabbatical :)
 
As I said, not a big problem - but if you copy 99% of a whole program, modify just a very few lines and upload to another platform( Github) a little info there (Github) is nice.
Here, it's not needed. Here, with copying some lines or functions, I'm 100% with you.
Thanks :)
Not a problem... There is now a readme... :D
 
@Frank B
Know I am late to game here - got side tracked. But really like this so don't have to keep update imxrt-size and the ide:)

Do you think it could be converted into a freemem_t4 mini-library just so you don't have to keep copy-pasting into sketches or would that cause other problems.
 
@mjs, it's now part of T4_PowerButton
Sorry, no documentation so far - just see the .h file
Attention, the lib uses the startup_late_hook() now for resetting the memory, so that maxstack() can work. So if you need this hook for other things, you can't use the lib.

the output is a little different - i thought it's more useful to see the all-time maximal stack usage, than the current.
Code:
[...]
DTCM:
   491520 Bytes (480 kB)
-   12992 Bytes (12 kB) global variables
-    1340 Bytes (1 kB) [COLOR=#b22222][I]max. stack so far[/I][/COLOR]
=========

   477188 Bytes free (466 kB), 14332 Bytes in use (13 kB).
[...]
I.e. if you use a large array locally in a function, you see its memusage now. (If you call flexRamInfo() or maxstack() at the end for example)
If you need reset, pls use this patch by Paul:https://github.com/PaulStoffregen/c...4b5bb72#diff-0ec022e950ef1cf4a79998316101c201
 
Last edited:
@Frank = thanks just forked it and copied into my libraries folder. Will definitely come in handy.

Hate to bring up a really old issue. But... now that reset is working temp monitor will now probable reset when the panic temp is hit as opposed to powering off. Will probably have to do some temp testing again to verify. Then guess we will probably have to put code in to shut down the t4?
 
That's a good point.
Maybe we can also extend startup.c so that it shuts down after reboot(?)
Its been so long now since I read the overtempt seq but I do remember that when a reset triggers the T4 sets a register value for overtemp and was wondering at the time if we could then use that to shut it down. Have to reread that RM again - argh!!! I think it was in SNVS section have to go back again so don't hold me to that.
 
Back
Top