Skip to content
luni64 edited this page Dec 5, 2020 · 16 revisions

WIP (luni)

Here some information about how the various Teensies utilize the available on- and off chip memory, how you can specify which part of the memory to use and how to handle sketches with high memory demand.

Memory Maps

Teensy LC and Teensy 3.x

The Teensy LC and all of the Teensy 3.x boards have a very simple memory model: There is a single block of flash and a single block of RAM memory. The size of RAM and flash depend on the board type. For all boards the flash memory starts at address 0x0000'0000. The image below shows the flash and RAM sizes and the respective start/end addresses.

image

Please note: the processors used on the T3.x boards distinguish between a low (< 0x1FFF'FFFF) and high (> 0x1FFF'FFFF) part of the RAM. Usually this splitting has no consequences. However, in rare cases it can generate weird alignment errors if the linker places a variable across the bank border (see here for more information on this issue).

For the T-LC and T3.x boards, both, RAM and flash memory are part of the processor and can be accessed very quickly. The maximum wait cycles to access RAM is 2 cycles (for consecutive reads the processor often can access the RAM without any wait cycle). Data from the flash can be read with maximal 4 wait cycles.

Teensy 4.x is different

to be described

Memory Map T4x

to be described

What is stored where

The linker will place different objects, like constants, variables, code etc. into various locations in the given memory. (For those, interested in technical details, these locations are defined in so called linker scripts. Here for example the one for the T3.2 and here the script for the T4.1)

Static and global variables

Global variables are variables defined outside of any functions, static variables are defined inside a function. Here some examples.

int i;            // global variable (uninitalized)
double x = 42;    // global variable (uninitalized)

void setup(){
  static int k;
}

void loop(){
}

The linker places such variables at a fixed location in the RAM. This location, is determined at link-time and can not change at runtime.

If you want to have a closer look yourself, you can use the MemoryTool which consists of the two files MemoryTool.h and MemoryTool.cpp and can be downloaded from here: https://github.com/luni64/TeensyHelpers.

int i;                    // global variable (uninitalized)
double x = 42;            // global variable (initalized)

void setup(){
    static int k;         // static variable, stored in the same place as global variables

    while (!Serial) {}    // wait until the pc connected
    printMemoryInfo(i);   // print info about the variables
    printMemoryInfo(x);
    printMemoryInfo(k);
}

void loop(){
}

For a T3.6 this prints:

i
  Start address: 0x1FFF'11EC
  End address:   0x1FFF'11EF
  Size:          4 Bytes
  Location:      RAM (not initialized)

x
  Start address: 0x1FFF'0738
  End address:   0x1FFF'073F
  Size:          8 Bytes
  Location:      RAM (initialized)

k
  Start address: 0x1FFF'11F0
  End address:   0x1FFF'11F3
  Size:          4 Bytes
  Location:      RAM (not initialized)

Lets see what happens if we change x to a constant:

int i;
const double x = 42;  // <== constant

void setup(){
    static int k;

    while (!Serial) {}
    printMemoryInfo(i);
    printMemoryInfo(x);
    printMemoryInfo(k);
}

void loop(){
}

Since one can't change a constant at runtime the linker leaves the constant in the flash as you can see in the printout below:

i
  Start address: 0x1FFF'11E4
  End address:   0x1FFF'11E7
  Size:          4 Bytes
  Location:      RAM (not initialized)

x
  Start address: 0x0001'08C8
  End address:   0x0001'08CF
  Size:          8 Bytes
  Location:      FLASH

k
  Start address: 0x1FFF'11E8
  End address:   0x1FFF'11EB
  Size:          4 Bytes
  Location:      RAM (not initialized)

What about c-strings:

char myString[]               = "This is a global c-string"; // can be changed at runtime
const char myConstantString[] = "I'm constant";              // can not be changed

void setup()
{
    while(!Serial){}

    char myLocalString[] = "Local c-string";

    printMemoryInfo(myString);
    printMemoryInfo(myConstantString);
    printMemoryInfo(myLocalString);
}

void loop(){
}

Here the printout which shows that if you want to place a string in the flash, all you need to do is declaring it const.

myString
  Start address: 0x1FFF'0734
  End address:   0x1FFF'074D
  Size:          26 Bytes
  Location:      RAM (initialized)

myConstantString
  Start address: 0x0001'0908
  End address:   0x0001'0914
  Size:          13 Bytes
  Location:      FLASH

myLocalString
  Start address: 0x2002'FFD0
  End address:   0x2002'FFDE
  Size:          15 Bytes
  Location:      STACK

To be continued

Clone this wiki locally