Serial Flash file.erase() not working?

Hi, I ran into a problem while building an audio looper.
When I call file.erase() it actually blocks the code for a while, but when I call SerialFlash.exists() after, it still returns "true". If you remove the file with remove() after erase(), the exists() returns false. However, in both cases the file is not actually erased, and the chip eventually runs out of memory. I've put together a code that shows this issue. After running "eraseTest()" a number of timer (in my case with 8Mb chip - 11 tries) it's no longer able to create a new file, not until you run full chip erase.

Board: Teensy 3.6
Audio adapter with Winbond 25Q64FVSIG soldered onto the Audio board.
Arduino IDE 1.8.13
Teensyduino version 1.53
Windows 10

It seems that a friend of mine reproduced it with Teensy 4.0 and a breakout with SPI flash.

Here's the code that reproduces the problem:
Code:
#include <SPI.h>
#include <SerialFlash.h>

#define FLASH_CHIP_SELECT  6

// The file where data is recorded
SerialFlashFile file0;
SerialFlashFile file1;
SerialFlashFile file2;


//define file size
float filesize = 65536 * 10;

void setup() {

  //uncomment these if using Teensy audio shield
  SPI.setSCK(14);  // Audio shield has SCK on pin 14
  SPI.setMOSI(7);  // Audio shield has MOSI on pin 7

  Serial.begin(115200);

  // Start SerialFlash
  if (!SerialFlash.begin(FLASH_CHIP_SELECT)) {
    while (1) {
      Serial.println ("Cannot access SPI Flash chip");
      delay (1000);
    }
  }
  Serial.println("READY TO GO");

}
void eraseTest() {
  const char *filename = "test.csv";
  byte buffer[512];
  static int n = 0;
  for (int i = 0; i < 512; i++) {
    buffer[i] = i % 10 + n;
  }

  Serial.print("Creating file...");
  Serial.println(filename);
  if (!SerialFlash.exists(filename)) {
    SerialFlash.createErasable(filename, filesize);
  }
  else Serial.println(" file already exists");

  file0 = SerialFlash.open(filename);
  if (file0) {
    file0.write(buffer, 512);
  }
  else {
    Serial.println("unable to create file");
    return;
  }
  file0.close();
  
  delay(10);

  Serial.println("Read test:");
  byte buf[256];
  file1 = SerialFlash.open(filename);
  file1.read(buf,256);
  for (int i = 42; i < 58; i++) {
    Serial.print(buf[i]); Serial.print(",");
  }
  Serial.println();

  delay(10);
  Serial.println("Erasing file...");
  unsigned long t = millis();
  file2 = SerialFlash.open(filename);
  file2.erase();
  Serial.print("done in ");
  Serial.print(millis()-t);
  Serial.println(" ms");
  delay(10);
  Serial.print("Checking if file exists:"); 
  Serial.println(SerialFlash.exists(filename));
  Serial.println("removing with remove() ");
  SerialFlash.remove(filename);
  Serial.print("Checking if file exists again:"); 
  Serial.println(SerialFlash.exists(filename));
  
  Serial.print("counter:"); Serial.println(n++);
}

void loop() {
  eraseTest();
  delay(1000);
}

Could anybody try running this? Any help would be much appreciated.
 
Lets take a look at the documentation:
For remove, it states:
Delete A File

SerialFlash.remove(filename);
The actual space used by the file is not reclaimed. However, a new file with this name may be created after the original is deleted.

So remove does not not free any space. It just meas you can create a new file with the same name.
Deleting the filename would need time-expensive operations. Clearing a flash-block and rewriting it takes a long time.
So, I'm not 100% sure and it would be necessary to take a look at the source code, but I would say it's pretty normal for exists() to still report the existence of the file.

rase Data

file.erase();
Only files created for erasing can be erased. The entire file is erased to all 255 (0xFF) bytes, which allows the file to be written with new data.


The contents of the file are erased. Not filename.
Again, I'd say it's pretty normal that exists() still reports the existing of the file.

I may be wrong or misunderstood something, but I can't see a bug here.
It's just that your expectations differ from the documentation.

Edit: doing both erase() and remove(), as in your program, does not help.

Not sure what the Audio-Looper does - For live-recording which involves over-writing, a Flash-chip is wrong type of memory....
Maybe use a SD-Card? It handles the erasing in the background and assignes empty blocks for new data automatically. The controller on the card does this.
 
Last edited:
Thanks Frank, I did investigate this and even looked inside the library. As you can see the problem is although I use erase(), the chip still runs out of space after a certain predictable amount of created files. So the erase in this case, although seems to be going over the blocks for a while, does not actually free up the space on the flash chip as the docs suggest.

As for SD, it was used in earlier stage, however the SD libraries that I tried do not support simultaneous read and write that are so crucial for my looper setup. Hence the switch to the flash memory.

If you happen to have the hardware to try and reproduce it, it would be much appreciated.
 
I can test it - maybe we find a so far unknown bug?
But I'll remove the remove() ;)

The counter is at 202 now. How long does it take?

I'm using this:
Code:
#include <SPI.h>
#include <SerialFlash.h>

#define FLASH_CHIP_SELECT  6

// The file where data is recorded
SerialFlashFile file0;
SerialFlashFile file1;
SerialFlashFile file2;


//define file size
float filesize = 65536 * 10;

void setup() {

  //uncomment these if using Teensy audio shield
  SPI.setSCK(14);  // Audio shield has SCK on pin 14
  SPI.setMOSI(7);  // Audio shield has MOSI on pin 7

  Serial.begin(115200);

  // Start SerialFlash
  if (!SerialFlash.begin(FLASH_CHIP_SELECT)) {
    while (1) {
      Serial.println ("Cannot access SPI Flash chip");
      delay (1000);
    }
  }
  Serial.println("READY TO GO");

}
void eraseTest() {
  const char *filename = "test.csv";
  byte buffer[512];
  static int n = 0;
  for (int i = 0; i < 512; i++) {
    buffer[i] = i % 10 + n;
  }

  Serial.print("Creating file...");
  Serial.println(filename);
  if (!SerialFlash.exists(filename)) {
    SerialFlash.createErasable(filename, filesize);
  }
  else Serial.println(" file already exists");

  file0 = SerialFlash.open(filename);
  if (file0) {
    file0.write(buffer, 512);
  }
  else {
    Serial.println("unable to create file");
    return;
  }
  file0.close();
  
  delay(10);

  Serial.println("Read test:");
  byte buf[256];
  file1 = SerialFlash.open(filename);
  file1.read(buf,256);
  for (int i = 42; i < 58; i++) {
    Serial.print(buf[i]); Serial.print(",");
  }
  Serial.println();

  delay(10);
  Serial.println("Erasing file...");
  unsigned long t = millis();
  file2 = SerialFlash.open(filename);
  file2.erase();
  Serial.print("done in ");
  Serial.print(millis()-t);
  Serial.println(" ms");
#if 0  
  delay(10);
  Serial.print("Checking if file exists:"); 
  Serial.println(SerialFlash.exists(filename));
  Serial.println("removing with remove() ");
  SerialFlash.remove(filename);
  Serial.print("Checking if file exists again:"); 
  Serial.println(SerialFlash.exists(filename));
#endif
  Serial.print("counter:"); Serial.println(n++);
}

void loop() {
  eraseTest();
  delay(1000);
}

Edit: 258
 
I'm stopping the test now.
Code:
Read test:
114,115,116,117,118,119,120,121,112,113,114,115,116,117,118,119,
Erasing file...
done in 1306 ms
counter:[COLOR=#ff0000][U][I][B]624[/B][/I][/U][/COLOR]
Creating file...test.csv
 file already exists
Read test:
115,116,117,118,119,120,121,122,113,114,115,116,117,118,119,120,
Erasing file...
done in 1272 ms
It works without problems (with remove() removed)
 
Hi Frank, thanks a lot for giving it some time. Can I ask you, what kind of memory chip you're using? Your erase time is much faster than mine (mine is ~2000ms).

Seems that I misunderstood the function of file.erase() after all, and file.remove() indeed "cancels out" with the erase. And instead of checking for existence of the file, I should just make sure somehow it was erased and then just write to it. Thanks a lot!
 
Good question. It was illegible, so I had to take a picture and enlarge it. It is a very old audio shield.
It looks like I soldered in a W25Q128FV*.

For this test I connected the audio board to a Teensy 3.2.

You can test the file is empty by reading it. if it returns all 0xff it's empty.
But, this is not needed. You can just erase() without checking.

Glad that it works now.

*I can't read the other markings. After "FV" comes a 8 or"B"? , maybe. (Edit: No, "S")
The second line is completely unreadable. Would be interesting to know the year of production!
 
Last edited:
Back
Top