This post shows a minimal example sketch for storing a 2D array in PSRAM memory of ESP32 WROVER modules. It’s mainly for my own reference, now that I’ve finally figured out how these notorious C++ pointers work*.
(An earlier post already showed a simple way to store 2D arrays in PSRAM, but that required some row/column book keeping).
The following sketch creates a 2D array named grid for storing float values in PSRAM. Then it fills all ‘cells’ with values of the form <column>.<row>. Finally, it prints the value of grid[123][234] (which should be 123.234, of course).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#define cols 240 #define rows 320 float *ptr, **grid; void setup() { Serial.begin(115200); // --- 1. Create the 2D array --- long len = sizeof(float *) * cols + sizeof(float) * rows * cols; grid = (float **)ps_malloc(len); ptr = (float *)(grid + cols); for (int i = 0; i < cols; i++) { grid[i] = (ptr + rows * i); } // --- 2. Fill the array with test values --- for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { grid[x][y] = x + y/1000.0; } } // --- 3. Read and print a single test value from the array --- Serial.println(grid[123][234],3); } void loop() { } |
Storing, for example, uint16_t values instead of floats only requires replacement of all occurrences of float with uint16_t.
Note that you can store multiple 2D arrays (even of different types) this way. Just declare an additional pair of global pointers of the desired type and add a corresponding ‘create’ section for each array in setup().
Elements in the grid array from the above example can now simply be addressed like grid[x][y], just like in regular 2D arrays. This convenience comes at a price:
- The presented method needs some extra memory for storing additional column pointers (the term sizeof(float *) * cols in the calculation formula of len).
- My (and probably everybody’s) favorite ESP graphics library TFT_eSPI can push an entire buffer of pixel values to a TFT display (very fast!). However, that buffer needs to be referrenced to by a single pointer, whereas grid is declared as a double pointer. As far as I know, that means that you’ll have to push the grid array column by column, where grid[i] is a pointer to the column with (zero-offset) index i.
I’m now using the described method in sketches with many single-pixel read/write operations, or with multiple arrays stored in PSRAM. For ‘speedy’ TFT projects, I’ll keep stitching my rows and columns together for storage in a single 1D PSRAM array.
* Finding this piece of information about pointers was very helpful: “… type is required to declare a pointer. This is the type of data that will live at the memory address it points to.” Before that, I presumed that pointers were supposed to be unsigned integers, long enough to hold any address they could point to.