TEENSY 4.0 EEPROM & RAM Questions

neroroxxx

Well-known member
Hi all, i see everywhere that 64K are allocated to recovery and EEPROM but what's the actual size that is used by the EEPROM library?

Also I see that its has 1MB of RAM but says 512KB rightly coupled, can anybody elaborate on how this is different to an end user from a T3.6?

sorry if this has been asked before but i couldn't find any info on the forum

PS: i also was wondering whats the Processor def for the 4.0, i use these for the other teensy models i use

#if defined(__MK66FX1M0__)
// Teensy 3.6

#elif defined(__MK64FX512__)
// Teensy 3.5

#elif defined(__MK20DX256__)
// Teensy 3.2 / 3.1

#elif defined(__MK20DX128__)
// Teensy 3.0

#elif defined(__MKL26Z64__)
// Teensy LC

#endif


Would it be __MIMXRT1062__?
 
Hi all, i see everywhere that 64K are allocated to recovery and EEPROM but what's the actual size that is used by the EEPROM library?

The EEPROM lib provides 1080 bytes, using wear leveling across 60K of the flash. The last 4K stores the recovery program.


Also I see that its has 1MB of RAM but says 512KB rightly coupled, can anybody elaborate on how this is different to an end user from a T3.6?

For most end users using Arduino and libraries, you would just write code the same way as Teensy 3.x and pretty much all other boards.
 
just waiting to see the 4.0 in stock somewhere to get my hands on it!

Don't wait. If you place an order, you'll get into the queue. First we ship to everyone who has been waiting. Then the website will show "in stock" only if more are left over. We're currently 80% of the way through the 2nd production batch. Odds are slim we'll show "in stock" again for the 2nd batch.

We did recently send stock to several distributors. Their situation with backorders is probably similar. Maybe you'll find some who show it in stock, before they sell out.

The 3rd batch is starting production tomorrow. It's a larger batch than the first 2, so in a couple weeks we should have plenty. If you wait for the website to say "in stock", you'll probably get one of those 3rd batch boards.


And yeah, only __IMXRT1062__. In December 2018 to February 2019, 20 boards were shipped to beta testers with the 1052. I know one of them died and was returned here, so only 19 of those boards exist in the wild. Everyone who has one has been sent either a late beta or final Teensy 4.0 with 1062 chip. Most of the code still has __IMXRT1052__ checks, but the reality is only 19 of those boards exist (outside PJRC - and I have maybe half a dozen here). Everyone who got them also has the new hardware.
 
1080 bytes of ram, that's a bit disappointing, I was hoping there would be more than that as I need storage space for user presets, and 1080 only gets me maybe 8 presets
 
From my reading of eeprom.c, it can be increased pretty significantly - up to 0xEC6, for a total of 3783 byte addresses. 0xEC3 is realistically what you should probably set it to if you're storing 32-bit values and need as much space as possible. That's 945 32-bit values.

0x86F, or doubling the stock amount, is probably a reasonably safe bet. Of course, that halves your write cycles.


Technical details below:

The wear leveling took me a minute to understand, but it looks like it groups 32 bits at a time across the 15 flash blocks. It does some bit shuffling on the address to determine an index within each block, with 0xFF being used to mean an unused slot where a value can be stored (this is why there's a max address of 254 in implementations that use a single flash block). I didn't really feel like doing the math on what that means for valid addresses, so I went ahead and wrote a little program to find the first invalid address:

Code:
fn main() {
    for i in 0..(256*15) {
        let upper = (i >> 2) / 15;
        let lower = i & 3;
        let idx = (upper << 2) | lower;
        if idx >= 0xFF {
            panic!("{}", i);
        }
    }
}

If 945 dwords aren't enough for you, there are a couple ways to eke out a bit more storage:

There are 42 more valid addresses above 0xEC6, but they're non-contiguous. Any address above 0xEC6 with the bottom two bits set is invalid (that is, any hex address ending in 3, 7, B, or F cannot be used). If you were feeling brave you could set your max address higher and avoid the invalid addresses to get those extra bytes. eeprom.c caps the limit at 0xEF0, but there are valid addresses up to 0xEFE. You'd have to adjust eeprom.c to allow that, though.

If you don't care about the recovery program, you could possibly also steal its space for a 16th flash block, which would increase the maximum contiguous address to 0xFC2, with 45 non-contiguous values above that point up to 0xFFE. I'm unsure if there are any flash protection settings or fuses that prevent this, and I don't intend to find out on my own Teensies :). If you wanted to do this and keep the stock wear leveling, it'd be a max address of 0x47F or 1152 bytes.
 
you could use the flexcan memory region while it’s in freeze mode to access the RAM in that area for temporary data (wiped on reset). They are at offsets 0x080 to 0x47F. Since theres 3 controllers, you have 3 areas for temporary writes. The area must be initialized on reset. That range has 2 memory blocks that can be written in increments as they are next to each other.

0x47F -0x80 == 0x3FF? ... 1023 dwords ram per CAN controller? ;P

Since it’s ram you don’t need to worry about wear levelling, copy it to SD/EEPROM over a schedule time while keeping the values updated live in RAM
 
Thanks for all the info!!! Makes a lot more sense now as to way it is limited. Will be fun to mess around with the values to see what happens. I got a board to learn and play with so I'll only cry a little if I kill all the write cycles lol.

Forgive me for my ignorance, I'm new to the micro-controller world. With the limit on EEPROM, I'm guessing that means it is really only used for storing configurations and such. Any kind of data logging should be done with either SD card or sending it off to a server. Maybe use the EEPROM to cache data if the connection is lost and what not.
 
Wow, you really read through the code and understood it very well. :)

But on this part...

If you don't care about the recovery program, you could possibly also steal its space for a 16th flash block

The top 4096 bytes are read-only. As we test each Teensy 4.0, test fixture writes the recovery program and then it sets the flash chip's permanent lock bits to make the top 4K of flash forever fixed to read-only access. You can't erase or alter those last 4096 bytes.

If you were really determined to get more non-volatile storage, you could try to also use more of the flash chip below the top 64K. You might wish to edit the linker script so the compiler "knows" less flash is available for your code. But the main downside to using flash below the top 64K is Teensy Loader will erase any data each time you upload a new program.
 
FWIW, during T4 beta testing I wrote a little sketch eeprom_meta.ino that would report the underlying metadata for managing the EEPROM wear-leveling. If you updated or added new data to the EEPROM, you could see how the meta data changed. And you could see the result of garbage-collection when a sector became full.
 
Last edited:
I just found this thread, unfortunately after I've finished developing my hardware around the T4 based on some incorrect assumptions about this line in the tech specs:
2048K Flash (64K reserved for recovery & EEPROM emulation)

Since I expected to have 5-10KB of configuration data, I wasn't worried about how much of the 64K was actually allocated to EEPROM (how big could a recovery program be?). So now I've discovered that only 1080 bytes of actual non-volatile storage are actually available. I see in this post that this total can be increased a little bit, but that's not going to be enough for my application. Not sure what I'm going to do now, other than kick myself. But may I suggest clarifying the specifications to avoid future customer disappointments?
 
Indeed the page www.pjrc.com/store/teensy40.htm indicates "(64K reserved for recovery & EEPROM emulation)"

Indicated below - the recovery program only takes 4K - but the 60K of EEPROM space is mapped many to one for wear leveling:
Code:
EEPROM Emulation - 60K of Flash memory is reserved for EEPROM emulation. Normally the Arduino EEPROM library is used, but the AVR eeprom functions are also supported for compatibility with legacy code. During uploading, this portion of the Flash is not erased or altered, so your data saved in the "EEPROM" is retained.
Restore Program - When you press the Teensy 4.0 pushbutton for 15 seconds (a quick flash on the red LED will tell you the moment to release), all of the Flash except this 4K is erased, and this known-good LED blink program is copied to the beginning of the Flash. This top 4K is special read-only memory, so you can always use this 15 second button press to fully erase your Teensy 4.0 and restore it to a known-good blink program.

Size is made clear on this page: pjrc.com/teensy/td_libs_EEPROM.html:
Code:
Board	EEPROM Size
Teensy 4.1	4284 bytes
Teensy 4.0	1080 bytes
Teensy 3.6	4096 bytes
Teensy 3.5	4096 bytes
...


But not the effective size of the EEPROM space after the emulation which is also not included in the device table here : www.pjrc.com/teensy/
 
Can you recommend the easiest way to add a micro SD adapter to a T4? It looks like I could use the small PJRC adapter with discrete wires, and it wasn't immediately obvious that the larger adapter is in any way pin-compatible (using the headers) with the T4. For future projects I'll switch to T4.1, but right now I have a custom PCB based on the T4.
 
Can you recommend the easiest way to add a micro SD adapter to a T4? It looks like I could use the small PJRC adapter with discrete wires, and it wasn't immediately obvious that the larger adapter is in any way pin-compatible (using the headers) with the T4. For future projects I'll switch to T4.1, but right now I have a custom PCB based on the T4.
One method is to use the Trainer4Edu breakout board:

The advantage of the Trainer4Edu board is the board without the USB host is exactly the size of the Teensy 4.1 with pins 0..33 being in the same location on the Trainer4Edu board and the Teensy 4.1 with some differences:
  • Pins 34..39 in the breakout board are in the the same location as the Teensy 4.1 pins;
  • On the 4.0, pins 34..39 are the pins connected to the micro SD card reader;
  • On the 4.1, pins 34..39 are new pins that aren't broken out on the Teensy 4.0;
  • On the breakout board, the two pins were pins 40..41 on the Teensy 4.1 are are not connected to anything;
  • On the Teensy 4.1, the micro SD pins are 42..47, and are only broken out in the micro SD card reader.

If you live in the USA and can't wait for OSHpark to make the PCB, I probably have some lying around that I could mail you 1-2.

There are other breakout boards. I put the ones I knew about in the unofficial Teensy wiki:

The unofficial twiki also has this page about adding a micro SD card:
 
Thanks for the suggestion, but I'm using the T4.0 mounted to a custom PCB without a lot of spare real estate. Even for the boards I haven't assembled yet, there wouldn't be room for this breakout board. I think I'll just use wires to connect a small SD adapter. Fortunately all of the necessary SPI pins are currently unused.
 
OK, I ended up getting a super cheap (<$2) Micro SD adapter and a super cheap (16GB, $6) SD card and hand wired the adapter to the T4 SPI pins (photo).
Got it up and running today using the SdFat library. It's only running with a 4MHz SCLK. I haven't tried to jack up the speed, and probably won't since speed isn't critical in my application.
 
What is the Status with Teensy 4.1 EEPROM?

I am writing

Code:
                    //float     FocusCalib[12][4];

                    Serial.println("***EEPROM WRITE***");
                    // Store Focus calibration data
                    addr = 0;
                    for (int i = 0; i < 12; i++) {
                    for (int j = 0; j < 4; j++) {
                     EEPROM.write(addr, *((uint8_t*)&FocusCalib[i][j]));
                     addr += 4;
                    }
                    }

and reading
Code:
        // Read Focus calibration data
        addr = 0;
        for (int i = 0; i < 12; i++) {
            for (int j = 0; j < 4; j++) {
                *((uint8_t*)&FocusCalib[i][j]) = EEPROM.read(addr);
                addr += 4;
            }
        }

The terminal connection gets erratic, it gets problematic to load new code, need to restart Arduino to do so.

How much emulated EEPROM there is? I read 4k, should this over all be avoided, what alternatives there is to store 1k data over power cycles ?

EDIT:

Did some testing, this works

Code:
        EEPROM.write(1024, 123);
        Serial.print(" EEPROM TEST "); Serial.println(EEPROM.read(1024));

so the problem was on the *((uint8_t*)&FocusCalib[j])
 
Last edited:
What is the Status with Teensy 4.1 EEPROM?

I am writing

Code:
                    //float     FocusCalib[12][4];

                    Serial.println("***EEPROM WRITE***");
                    // Store Focus calibration data
                    addr = 0;
                    for (int i = 0; i < 12; i++) {
                    for (int j = 0; j < 4; j++) {
                     EEPROM.write(addr, *((uint8_t*)&FocusCalib[i][j]));
                     addr += 4;
                    }
                    }

and reading
Code:
        // Read Focus calibration data
        addr = 0;
        for (int i = 0; i < 12; i++) {
            for (int j = 0; j < 4; j++) {
                *((uint8_t*)&FocusCalib[i][j]) = EEPROM.read(addr);
                addr += 4;
            }
        }

The terminal connection gets erratic, it gets problematic to load new code, need to restart Arduino to do so.

How much emulated EEPROM there is? I read 4k, should this over all be avoided, what alternatives there is to store 1k data over power cycles ?

You posted in an area with T4.0 in the subject line, but you seem to indicate that you are using a T4.1. You can look <here> for a comparison of Teensy Technical Specs (including EEPROM sizes for T4.0 & T4.1).

From your code snippets, it is not clear whether you have a single dimensional array of 12 floats or a 2-dimensional array of 48 floats. If you want to access/save the individual bytes in a float (from an array of floats or otherwise), you should probably either look into defining a union, or use bit shifting & bit masking to access the byte portions of that float. You could also write the entire contents of the float array in a single command, without having to separate it into individual bytes, and that might avoid all of your current troubles.

Hope that helps . . .

Mark J Culross
KD5RXT
 
Code:
                     EEPROM.write(addr, *((uint8_t*)&FocusCalib[i][j]));
                     addr += 4;
EEPROM.write ONLY writes a byte, so why are you advancing the addr by 4?

Why not use something like below:
Code:
#include <EEPROM.h>

struct myFloatType {
	float focusCalib[12][4];
};

myFloatType f;

void setup() {
	EEPROM.put(0, f);
	EEPROM.get(0, f);
}
 
Thanks for the fast replies.

This gives just the read and write https://www.pjrc.com/teensy/td_libs_EEPROM.html

So I used those. (but maybe should look into put and get if they are available)

It is a float, so 4 bytes, this does it correctly (or at least seems to do what it should)

Code:
Serial.println("***EEPROM WRITE***");
                      // Store Focus calibration data
                    addr_ = 0;
                    for (int i = 0; i < 12; i++) {
                      for (int j = 0; j < 4; j++) {
                        byte* data_FW = (byte*)&FocusCalib[i][j];
                        for (int k = 0; k < sizeof(float); k++) {
                          EEPROM.write(addr_, data_FW[k]);
                          addr_++;
                        }
                      }
                    }
 
I don't think it does work.
EEPROM.write ONLY writes ONE byte.
If you want to write the way you are doing you need to somehow strip out EACH byte of the 4 bytes making your float and send them individually.
Likewise EEPROM.read ONLY reads ONE byte. You would have to read the individiual bytes, then reconstruct the float.

Why do that when EEPROM.put(0, f); automates all of it.

See here for an explanation of EEPROM library.
 
Back
Top