Crashes with PSRAM

jimmie

Well-known member
I have a Teensy 4.1 and added an 8 MB PSRAM chip and it passed the memory test.

In my sketch, I am using the PSRAM memory to save a String array:

Code:
const int BUFFER_SIZE = 200;                  
EXTMEM String circularBuffer[BUFFER_SIZE];

This compiles fine with the following memory usage:
-----------------------------------------------------------------------------------------------
Memory Usage on Teensy 4.1:
FLASH: code:180352, data:23500, headers:9136 free for files:7913476
RAM1: variables:30976, code:177076, padding:19532 free for local variables:296704
RAM2: variables:79488 free for malloc/new:444800
EXTRAM: variables:3200
-----------------------------------------------------------------------------------------------

The code above will run fine with or without PSRAM.


But when I make the following change in the code by increasing the buffer size to 250:

Code:
const int BUFFER_SIZE = 250;                  
EXTMEM String circularBuffer[BUFFER_SIZE];

This compiles fine with the following memory usage:
-----------------------------------------------------------------------------------------------
Memory Usage on Teensy 4.1:
FLASH: code:180352, data:23500, headers:9136 free for files:7913476
RAM1: variables:30976, code:177076, padding:19532 free for local variables:296704
RAM2: variables:79488 free for malloc/new:444800
EXTRAM: variables:4000
-----------------------------------------------------------------------------------------------

However, after a few seconds, the code crashes.

What could be causing that given that the hardware passed the memory test.

Thanks in advance to the community.
 
EXTMEM String only causes the String pointer to be placed into PSRAM. The actual character data still goes into RAM2.

Maybe we should add code in future versions which check for this at runtime (adding slight overhead to all String usage) but as String exists today, it always stores the actual character data in RAM2.

To store strings in PSRAM, you need to use C style char arrays, of course with EXTRAM.
 
regarding this: "However, after a few seconds, the code crashes."
> is that when there is or is not physical usable PSRAM chip? re: "run fine with or without PSRAM"
> will it crash in a few seconds when there is a PSRAM chip?

Posted console output shows: EXTRAM: variables:3200
> That would be PSRAM EXTMEM was used and seems the text ref uses EXTRAM
> Odd it shows allocation to that region if that memory area won't be used? : EXTMEM String circularBuffer[BUFFER_SIZE];

It might actually use that area as 'pre-allocated'?

If so it might work with or without a PSRAM chip when the data works from the 32KB cache. But as soon as the cache needs to be flushed to cover other memory regions (RAM2 data) then any ref to the PSRAM address space that the cache provided will be unsupported and data lost.
> this happened in early Beta testing of working PSRAM over a small region - it appeared to be working when it was not as the cache will hold the data until it gets pushed out and lost.
 
I meant that my board has the PSRAM chip installed. When using

Code:
const int BUFFER_SIZE = 200;                  
EXTMEM String circularBuffer[BUFFER_SIZE];

or

Code:
const int BUFFER_SIZE = 200;                  
String circularBuffer[BUFFER_SIZE];

The code works.

When
Code:
const int BUFFER_SIZE = 250;
it crashes which according to Paul's explanation makes sense since Strings are not stored in PSRAM.

In the posted memory stats, this was always from the same board with the extra PSRAM.
 
I will add code that converts my string array to an array of character array so I can store it in PSRAM. My knowledge of Arduino strings is limited so I will do some reading on it.

Thank you Paul and @defragster.
 
Posted console output shows: EXTRAM: variables:3200
> That would be PSRAM EXTMEM was used and seems the text ref uses EXTRAM
> Odd it shows allocation to that region if that memory area won't be used? : EXTMEM String circularBuffer[BUFFER_SIZE];

It might actually use that area as 'pre-allocated'?

The name "BUFFER_SIZE" is misleading in this case, the allocation being made in EXTMEM is an array of String objects. The extmem usage is increasing by 50 base objects (all of which use dynamic memory for their local storage).
 
I will add code that converts my string array to an array of character array so I can store it in PSRAM. My knowledge of Arduino strings is limited so I will do some reading on it.
Will the strings you are storing always be the same size? Or have a maximum size that you know they will always be under?

The big issue with strings (either c++ string class of c style char arrays) is that their size is variable. If you create an array of char* to store a set of c style strings you'll hit the same issue that all the compiler does is allocate a block of pointers but no storage for the actual text.

If you know all the strings will be under a certain length then you can do something like:

Code:
const int BUFFER_SIZE= 200;
const int MaxStringLength = 64;
EXTMEM char StringStorage[BUFFER_SIZE*(MaxStringLength +1)]; // +1 to allow for null termination
EXTMEM char* circularBuffer[BUFFER_SIZE];

init() {
// init circularBuffer to point to correct locations in large storage array.
  for (int i=0;i<BUFFER_SIZE;i++) circularBuffer[i]= StringStorage+i*(MaxStringLength +1);
}

Which will allocate the storage in one large block and then on startup create your array of pointers to the appropriate points in the storage.
However if you go over the assumed maximum string length you'll end up corrupting the next string in the array.
 
Thank you @AndyA. My strings are all constant length. Also, 8MB is so large for my needs.
 
Thank you @AndyA. My strings are all constant length. Also, 8MB is so large for my needs.

Then that makes things easy. :)

As noted in the comments in my example, make sure you allocate 1 byte more than the length for each string. The way c strings work is that a null (0x00) is added on to the end to indicate that the end of the string has been reached so you need to allow for that space. Well technically you don't if you know things will always be an exact length, but all of the standard c string functions will assume this and it makes life a _lot_ easier if you can stick to the standards.

One refinement - If possible make it so that the space per string (including the extra null) is always a multiple of 4. So if your strings are 64 characters use 68 bytes per string rather than the minimum of 65. This wastes a bit of memory but keeps the start of each string aligned to a 32 bit boundary which is always good whenever possible.
Code:
const int StringLength = 64;
const int SpacePerString = StringLength  + 4 - StringLength%4; // add between 1 and 4 bytes to ensure space is always a multiple of 4
 
Back
Top