Teensy 4.1 QSPI Flash blocking behaviour

LeoSal99

Member
Hi everyone,
I'm in the process of developing a project that has to log some sensor data to Flash.
Since I'm not capable of understanding every bit of the code in the LittleFS library, I run some tests to see if writing to a W25Q128JVSIM soldered to the teensy 4.1 bottom pads would block the execution of my code and for how long.
I've written this short sketch that I used to characterize the behaviour changing the size of buf[] via DIMEN definition:
Code:
#include <LittleFS.h>
#include <Entropy.h>

#define DIMEN 65

LittleFS_QSPIFlash myfs;
//LittleFS_QPINAND myfs;

uint32_t prevSysCount = 0;
uint32_t ticksTacken = 0;

void setup() {
  Entropy.Initialize();
  Serial.begin(9600);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("LittleFS Blocking Test");
  if (!myfs.begin()) {
    Serial.printf("Error starting %s\n", "QSPI FLASH");
    while (1) ; // stop here
  }
}

void loop() {
  unsigned long buf[DIMEN];
  File myfile = myfs.open("WriteSpeedTest.bin", FILE_WRITE_BEGIN);
  if (myfile) {
    prevSysCount = ARM_DWT_CYCCNT;
    randomSeed(Entropy.random());
    for (int i=0; i<DIMEN; i++) buf[i] = random();
    ticksTacken = ARM_DWT_CYCCNT - prevSysCount;
    Serial.print("Just calcs: ");
    Serial.print(ticksTacken);
    Serial.print("   ");

    prevSysCount = ARM_DWT_CYCCNT;
    randomSeed(Entropy.random());
    for (int i=0; i<DIMEN; i++) buf[i] = random();
    myfile.write(buf, DIMEN*4);
    ticksTacken = ARM_DWT_CYCCNT - prevSysCount;
    Serial.print("Calcs and write: ");
    Serial.print(ticksTacken);
    Serial.println();
    
    myfile.close();
    myfs.remove("WriteSpeedTest.bin");
  }
  delay(1000);
}

I run tests with the following sizes :
DIMEN 32 Just calcs: 901 Calcs and write: 1198
DIMEN 64 Just calcs: 1796 Calcs and write: 2119
DIMEN 65 Just calcs: 1758 Calcs and write: ~29000000
DIMEN 128 Just calcs: 3396 Calcs and write: ~27000000

To me it seems that if I try to write more bytes that fit in a Flash page (64*4=256 bytes) it hangs the execution of the rest of the program for a while (about 48 ms).

Then I updated the Arduino IDE and Teensyduino from 1.55 to 1.56 and rerun some tests:
DIMEN 32 Just calcs: 935 Calcs and write: 1195
DIMEN 64 Just calcs: 1733 Calcs and write: 2061
DIMEN 65 Just calcs: 1759 Calcs and write: ~147000000 (actually varies from 132M to 147M)
DIMEN 128 Just calcs: 3396 Calcs and write: ~135000000(126M to 142M)
DIMEN 129 Just calcs: 3422 Calcs and write: ~135000000(pretty much the same as DIMEN 128)

Sadly I didn't test with higher DIMEN that 128 with the old version of teensyduino.
My questions are:
Why this much difference between the two versions of teensyduino?
Is there a way to make these larger writes non blocking? Would it be safe to execute large(ish) interrupts routine to keep my code running while it writes to flash?

Thanks, Leonardo

P.S. more informations about my project that I don't if are relevant:
I have a number of sensors connected via SPI that I read at around 1kHz (possibly more in the future). When I get a data ready signal via an interrupt pin I set a flag that tells me to retrieve data from the sensor in the next loop execution (or I could do that directly in the ISR, but I haven't decided yet).
I have to filter this data and check for some conditions to make certain actions. I the future I want to add some Serial communications to a GPS and a Lora module and also some active control that moves RC servos accordingly to the situation it senses.
 
Flash is - for writes - a slow memory technology. The chips are that slow. Pages have to be erased before a write can happen.
Basically, they are used for write once - read often. LittlsFS adds quite a high amount of "slowness", too and is even for reads slow.
Would be nice if we had a lib to use the chips directly, without LittlFS.

If you need to write often, flash is the wrong technology. You can add PSRAM or FRAM (FRAM is expensive).
Or just a fast SD Card.
 
Last edited:
Thanks for your reply.
PSRAM is not feasible because it is volatile. FRAM is very expensive and I would need a bit more space than 8Mb.

You say it is slow for writing, but a quick run of the example Write_Speed_Test gives me over 180KB/s of write speed that is more than enough for my purpose (~30KB/s atm, but I could log at a lesser frequence if necessary).
The main problem is that it blocks the execution of my code for longer than I can tolerate, so maybe more a latency problem than a writing speed one?

I'm waiting on a friend to run the test on a NAND chip, but I guess it will give similar results.
I would really like to make it work because data retention during power loss is very important for my project

EDIT: maybe something like preallocating (erasing maybe?) the blocks could help? I've seen it done with the SD and it might be stupid but I couldn't find an easy way to code it and test it
 
Last edited:
Why not use a battery back up. Something like this might be useful.
This would allow you to detect power loss, save data, and go to sleep. With an 18650 battery sleep could last for years.
 
ok, mea culpa for not giving enough details: I mentioned power loss because my teensy will be in a high vibrations high accelerations environment and I'm worried it could affect the reliability of the power connections. Also it would be important to have a chance at retrieving some data in case of an accident that leads to the destruction of the teensy or other parts of my board (with consequent power loss).

If a Flash or NAND chip really isn't appropriate for my use case I would think about using one or two PSRAM chips to buffer my data and then write it on an SD card for permanent storage. But from what I read SdFat is also blocking at the moment and I'm definitly not capable of fixing that, so I would have to wait the end of the "mission" to write on it
 
Since I am already set up and have a myriad of chips. Ran your sketch with DIMEN = 1024 on a W25M02 (2Gbit) NAND:
Code:
Just calcs: 27042   Calcs and write: 1373638

For DIMEN = 128
Code:
Just calcs: 3526   Calcs and write: 3917

Out of curiosity I reran your DIMEN-128 example on the W25Q128JVSIM
Code:
Just calcs: 3527   Calcs and write: 121395398

and a N01 NAND for a DIMEN = 128:
Code:
Just calcs: 3526   Calcs and write: 3917

Have to also remember that the block writes for FLASH is 256 while for NAND its 2048.
 
So, if I'm not mistaken, you should see the difference between DIMEN = 512 and DIMEN = 513.

Don't think you are going to see much of break? By break I assuming you mean performance time. Try it and see what happens.
 
Back
Top