Initialize Variable in SPI Flash

Winlep

Member
Hi all, apologies for the dumb question. Is there any way to initialize a read-only variable at compile time that is stored in external flash, like we can do with internal flash using PROGMEM?
 
Correct, 4.1. Basically looking for a way to store an array in external flash and very quickly access the values at non sequential indices. I suppose I could accomplish this by using SerialFlash to read one value, seek to another index, read, seek, and so on. But I’m wondering if there’s a smarter or more performant way.
 
Last edited:
Can the intent and use plan be clarified? The Compiler can put things into RAM or PROGMEM - but not external SPI or QSPI devices and more than it can an SD device.

Code can in setup() for instance confirm a desired initialization state and either push desired values or confirming they already exist then use them on such an external device.

The 1062 is unique already in that the build specifies code for RAM that prior Teensys could not do. And on Reset PJRC has code that relocates the expected code from the HEX into RAM DTCM address space with a copy from PROGMEM FLASH.

Setup() as noted above could do similar things as needed once the system is ready for SPI access.
 
When you say "external flash" on Teensy 4.1, are you asking about the main W25Q64 flash chip which PJRC solders to every Teensy 4.1? Or are you talking about another flash chip which you have soldered to the bottom side?

For the main flash memory, just use PROGMEM on const initialized variables.

For adding a QSPI flash chip on the bottom side, LittleFS_QSPI is the main way to access that memory. But using it as a filesystem has quite a bit of overhead, and especially LittleFS is designed to bring many benefits like wear leveling and safety from filesystem corruption on power loss during a write operation, but those features involve design trade-offs against raw performance.

There are other ways you might use a QSPI add-on chip, and even with the main program flash, there are issues like caching to consider. But first let's just be clear about which you mean by "external flash". Maybe also explain a bit more context about your application and anticipated performance requirements. Understaning your needs allows for time spent writing answers to be much more helpful.
 
Here is a small program that puts a 4MB array into T4.1 program flash and accesses it at runtime. You can experiment with how frequently you access the array.

Code:
#include "Arduino.h"

// nested arrays of integers to add code size for testing 
#define A0 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}  // 16  elements 64
#define A1 {A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0,A0}  // 256 elements 1KB 
#define A2 {A1,A1,A1,A1,A1,A1,A1,A1,A1,A1,A1,A1,A1,A1,A1,A1}  // 4K  elements 16KB
#define A3 {A2,A2,A2,A2,A2,A2,A2,A2,A2,A2,A2,A2,A2,A2,A2,A2}  // 64K elements 256KB 
#define A4 {A3,A3,A3,A3,A3,A3,A3,A3,A3,A3,A3,A3,A3,A3,A3,A3}  // 1M  elements 4MB

// const variables reside in flash and get optimized out if never accessed
PROGMEM const uint32_t a[16][16][16][16][16] = A4;

elapsedMicros usec;
uint32_t count;

void setup()
{
  while (!Serial) {}  // wait for Serial
  usec = 0;           // init usec timer    
}

void loop()
{
  if (usec > 1000) {  // every 1 ms
    int i = count % 16;
    uint32_t *address = (uint32_t*)&a[i][i][i][i][i];
    uint32_t value = *address;
    Serial.printf("%8lu %08X %1lu\n", count, (uint32_t)address, value );
    count++;
    usec -= 1000;
  }
}
 
Thanks for your help. You all are too kind. I’m sorry for not being more clear. I’m referring to a qspi chip soldered to the bottom of a Teensy 4.1. I’m working with audio. The files are too large for the main flash memory, and I need fast polyphonic playback so SD is out. I can’t get too deep into the details, but based on tests I’ve seen posted in the LittleFS thread, it wont be able to keep up with the number of voices.

Through my many attempts at finding solutions on the forums, SerialFlash seems like the best option. I’ll use the copy to sd sketch to sync the sd files to SerialFlash and read from there. I dont need to do any writing beyond that initial “caching” process.

However, all the literature around playing audio from SerialFlash seems geared towards consecutive reads, so I’m just wondering if there’s any more performant solution for more of a random-read use case. This is effectively granular synthesis that is often reading just one or two samples from a SerialFlash “file” before jumping to a set position in another file to read the next few samples… with other voices doing this same thing simultaneously. It’s an adaptation of a program that, on a platform with more internal RAM, was simply pulling samples from audio files stored as arrays.

I guess I’m trying to force a program flash paradigm onto an spi flash system, which I know isn’t exactly ideal, but I believe it’s the only option given the constraints. The nature of the real-time logic and the amount of data that’s potentially eligible for reading at any given moment rules out copying or caching to the main flash. So I was just curious if there’s a better way to approach a random-read-heavy use case on spi flash than SerialFlash with tons of seeks on many simultaneously opened files.
 
Last edited:
Back
Top