SerialFlash filesystem question

Status
Not open for further replies.

sumotoy

Well-known member
I never used Serial Flash chip but just get the 'Prop Shield' so I started experimenting with Serial Flash Chip and my Teensy 3.2.
I wroted the following really basic sketch to understand the file system but get weird results, maybe I've done something really stupid but try to understand what's wrong:
Code:
/*
 * An horrible sketch to play with SerialFlash on Teensy 3.2
 * filesistem.
 * Not to be used as state of art example, just a playground to 
 * discover the commands and methods of SerialFlash library on a Tensy3.2
 * .s.u.m.o.t.o.y.
 * Here's the results:  ------------------------------
 * Compiled at 72Mhz not optimized:
 * abcdefghijklmnopqrstuvwxyz (correct)
 * Compiled at 72Mhz optimized:
 * abcdefghijklmnopqrstuvwxyÿ (missed z and get ÿ) 
 * Compiled at 96Mhz not optimized:
 * abcdefghijklmnopqrstuvwÿÿÿ (missed y,z and get 3 x ÿ)
 * Compiled at 96Mhz Optimized:
 * abcdefghijklmnopqrÿÿÿÿÿÿÿÿ (even worst...)
 */

#include <SerialFlash.h>
#include <SPI.h>

bool                serialChipOk = false;
const char * files[2] = {"file01.txt", "file02.txt"};
const unsigned long fileSize[2] = {65536, 65536};

SerialFlashFile file;

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(38400);
  long unsigned debug_start = millis ();
  while (!Serial && ((millis () - debug_start) <= 5000)) ;
  if (!SerialFlash.begin()) {
    Serial.println(F("Unable to access SPI Flash chip"));
  } else {
    serialChipOk = true;
    Serial.println(F("Serial Flash Chip OK"));
    unsigned int filesDir = listFiles();
    if (filesDir > 0) {
      Serial.print(F("Find "));
      Serial.print(filesDir);
      Serial.print(" files in directory\n");
    } else {
      Serial.print(F("NO Files present...\n"));
    }
    uint32_t buffLen;
    if (checkMyFile(0)){//file exists
      buffLen = testWriteA();//write some data
      readMyFile(0,buffLen);
    }
  }//
}

void loop() {
  // put your main code here, to run repeatedly:

}


//returns how many files are present and prints
//the file names....
unsigned int listFiles()
{
  unsigned int count = 0;
  SerialFlash.opendir();
  while (1) {
    char filename[64];
    unsigned long filesize;
    if (SerialFlash.readdir(filename, sizeof(filename), filesize)) {
      Serial.print("  ");
      Serial.print(filename);
      for (unsigned int i = 0; i < 20 - strlen(filename); i++) {
        Serial.print(" ");
      }
      Serial.print("  ");
      Serial.print(filesize);
      Serial.print(" bytes");
      Serial.println();
      count++;
    } else {
      break; // no more files
    }
  }
  return count;
}

//check if a file exists (and erase it), if not it will create it
//and check if it's created correctly.
//it returns 1 if ok or 0 if not
bool checkMyFile(uint8_t fileIndex)
{
  bool state = 0;
  file = SerialFlash.open(files[fileIndex]);
  if (file) {  // true if the file exists
    Serial.print(F("Found file: "));
    Serial.print(files[fileIndex]);
    Serial.print(F(" size:"));
    Serial.print(file.size());
    Serial.print(F(" - Start Adrs:"));
    Serial.println(file.getFlashAddress());
    file.erase();//now complete erase file content
    state = 1;
  } else {
    Serial.println(F("Unable to access file, attempt to create it"));
    if (!SerialFlash.createErasable(files[fileIndex], fileSize[fileIndex])) {
      Serial.println(F("Could not create file, I stop here"));
      state = 0;
    } else {
      //file created
      file = SerialFlash.open(files[fileIndex]);//open it
      if (file) {  // true if the file exists
        Serial.println(F("File created"));
        state = 1;
      } else {
        Serial.println(F("Cannot create. I will stop here!"));
        state = 0;
      }
    }
  }
  file.close();
  return state;
}

bool readMyFile(uint8_t fileIndex, uint32_t count)
{
  if (count < 1) return 0;
  bool state = 0;
  unsigned char buff[count+1];
  file = SerialFlash.open(files[fileIndex]);
  if (file) {
    file.seek(0);
    file.read(buff, count);
    Serial.print("\nHere's Data:(");
    Serial.print(count);
    Serial.print(") -> ");
    for (unsigned int i = 0; i < count; i++) {
      Serial.write(buff[i]);
    }
    state = 1;
    Serial.print("\n");
  } else {
    Serial.println(F("File not exists!"));
    state = 0;
  }
  file.close();
  return state;
}

uint32_t testWriteA(){
  uint32_t written = 0;
  file = SerialFlash.open(files[0]);//open first file
  if (file) {
    unsigned char buff[] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
    file.seek(0);//position to start of file
    written = file.write(buff,sizeof(buff));
    Serial.print(F("Written:"));
    Serial.print(written);
    Serial.print(F(" bytes"));
    Serial.println();
  } else {
    Serial.println(F("File not exists!"));
  }
  file.close();
  return written;
}

What it does?
1) get a list of files present on chip.
2) it check for a specific file existance, if not found it create it, if found it simple erase it.
3) open file, write some chars inside it, close file and get the number of char written
4) attempt to open file, read it and print results, then close it.

It's just for study file system so forgive me the massive printouts.
This chip seems write only 65K chunks, it's very silly use it for write some text but as I said it's just for study, maybe in the future it will be good enable 4k chunks for use as icon/font container.

If everithing goes at it should I have to read this sequence of chars: abcdefghijklmnopqrstuvwxyz, but this happen only at 72Mhz not optimized!
Here's the results:
- Compiled at 72Mhz not optimized: abcdefghijklmnopqrstuvwxyz (correct)
- Compiled at 72Mhz optimized: abcdefghijklmnopqrstuvwxyÿ (missed z and get ÿ)
- Compiled at 96Mhz not optimized: abcdefghijklmnopqrstuvwÿÿÿ (missed y,z and get 3 x ÿ)
- Compiled at 96Mhz Optimized: abcdefghijklmnopqrÿÿÿÿÿÿÿÿ (even worst...)

I'm using Teensyduino 2.8 beta.
Any help?

UPDATE:
Issue solved, was an error in library.
Look HERE
 
Last edited:
Could you try something ?

Add a line in SerialFlashChip.cpp (around line 205):
Code:
        addr += pagelen;
        len -= pagelen;
        [B]delayMicroseconds(1); //<--- add this[/B]
        do {
            SPI.transfer(*p++);
        } while (--pagelen > 0);

Not that such a long delay is really needed (a "nop" is sufficiant), but this microsecond delay is evrywhere in this file :)

Does it help ?
 
Last edited:
Hi Frank,
no, same results. I've already tried add some delay (even inside loop). It looks the array get corrupted or the wait function exit too fast...
In the meantime I've tried to limit the SPI transaction stuff to the necessary only, I've cloned the library here with the proposed suggestions (basically I have moved SPI Transactions out of Do while stuff and proposed a wait with an optional SPI transaction so it can stay inside wait.. do stuff without opening and closing stransactions). I've runned all the examples and it's fine, maybe can be a suggestion?
Unfortunatly no joy with my current problem, I just get a bit more speed and bit less weird results but everithing unchanged, at 72Mhz not optimized it's perfect but at any other speed I got weird results.
 
Last edited:
Ok,

i just tried your sketch from above.
I does not work for me, too.

Since my "TeensyTransfer" (look @ the prop shield thread) works and is able to wrtie and read files correctly (at least for me), i think it is a problem with your sketch.

Can you test with "TeensyTransfer" ?

Edit:

I tried reading your "file01.txt" with the tool.
It returns "abcdefghijklmnopqrstuvwxyzÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ..." (64Kb)
(ÿ is 0xff)
 
Last edited:
Did you try at 72Mhz not optimized? I wonder why it work perfectly (at list here) and not at any other speed or optimizations...
I'll try TeensyTransfer
 
Did this get fixed? Wasn't a delay() added to SerialFlash?

Running this at 96 MHz I get the xyz corruption and it won't run twice reliably. Going to 72 MHz after EraseEverything it works, and I can edit filename in files[2] and recompile to add another file twice more.

Leaving the speed at 72MHz - TeenyTransfer still gets CommErrors.

This suggests my hardware works but is speed sensitive to SerialFlash that worked before?
 
No, still not fixed. I know it's silly to works as this with such large chunks (even enabling 4K chunks) but this is the classical example that can drive me mad. In the maintime I'm avoiding using SPI flash in my project until I understand the issue.
 
Interesting. I have the TeensyTransfer working so well - except minor name length issues Frank fixed - now all of a sudden it won't communicate and I'm hoping Frank can help me figure it out. So I can here for a sample and it seems to work the first time - created the file . . . then it went to not working. Assuming it was fixed I never actually read how it was broken - then I saw I had the xyz loss. If it can corrupt that - it can corrupt the directory data area too. I played the one HALLOWEEN sound sketch recently and it worked well . . . I need to find that and try it.
 
I went back to this : Prop-Shield-Beta-Test

Had to use: libraries\SerialFlash\extras>rawfile-uploader.py this time since TeensyTransfer won't run - it seemed to complete at 96MHz:
C:\tCode\libraries\SerialFlash\extras>rawfile-uploader.py com13 SDTEST1.RAW SDTEST2.RAW SDTEST3.RAW SDTEST4.RAW
Uploading 4 files...
1: SDTEST1.RAW (674.63 KB/s)
2: SDTEST2.RAW (661.35 KB/s)
3: SDTEST3.RAW (626.58 KB/s)
4: SDTEST4.RAW (602.08 KB/s)
All files uploaded

But the sketch I saved does not play anything - the names tick off faster than the sounds could play if loaded.
 
I have other different SPI flash chip here, maybe it's an issue of this particular chip? I will try later, have to solder chip on some adaptor.
 
I have some of Frank's Memory boards and component chips I never built out yet. But if I did that and they didn't work now I'd never know if I soldered them wrong or it was the system. I should go back and find a copy of SerialFlash library from the date I did the p#10 sound test and see if that works - but I already lost more than a day trying to narrow this down.
 
I think the data is being written correctly to flash.
in readMyFile() if i use unsigned char buff[256];
it seems to read back ok on 2nd run, but i still haven't found the root cause ....
 
Last edited:
I have some of Frank's Memory boards and component chips I never built out yet. But if I did that and they didn't work now I'd never know if I soldered them wrong or it was the system. I should go back and find a copy of SerialFlash library from the date I did the p#10 sound test and see if that works - but I already lost more than a day trying to narrow this down.
serialFlash does not work with the Memoryboard. It needs 3 Chipselects.
 
Last edited:
I think the data is being written correctly to flash.
in readMyFile() if i use unsigned char buff[256];
it seems to read back ok on 2nd run, but i still haven't found the root cause ....

you can disregard above.

simplest fix is to add delay(2); to readMyFile() just before file.seek(0);
(or better after file.close() in testWriteA() )
 
Last edited:
you can disregard above.

simplest fix is to add delay(2); to readMyFile() just before file.seek(0);
(or better after file.close() in testWriteA() )

I found the reason:

The Chip is still writing, when the Sketch tries to read it.

Fix for the sketch above:
Code:
  if (file) {
[U][I][B]    while (!SerialFlash.ready()) Serial.write('.');[/B][/I][/U]
    file.seek(0);
    file.read(buff, count);
 
..that means there is a problem with read(), which -definately - should wait. or with write(), which does not cause read to wait properly.....
ok, i think i have a fix.
Code:
in SerialFlashChip.cpp, change "busy" from 1 to 4:
        do {
            SPI.transfer(*p++);
        } while (--pagelen > 0);
        CSRELEASE();
[U][I][B]        busy = 4;[/B][/I][/U]
        SPI.endTransaction();
    } while (len > 0);

Then, it works without that waiting-loop inmy previous post.
I'll do a pull-request with this fix on GitHub.
 
And....'TaaaDaaaa!'.... This fixes my issue as well even at 120Mhz!
Thanks Frank :D, this is 'the' solution, I was going mad that I cannot write 26 bytes without issue!
 
Last edited:
Someone can check the SPI.Transactions modifies I added to the library? It look faster to me.
FrankB fix included.
Testing Lib HERE
 
And....'TaaaDaaaa!'.... This fixes my issue as well even at 120Mhz!
Thanks Frank :D, this is 'the' solution, I was going mad that I cannot write 26 bytes without issue!

manitou gave the right hint :)
Your changes look good at a first glance - had'nt time to test it
 
And....'TaaaDaaaa!'.... This fixes my issue as well even at 120Mhz!
Thanks Frank :D, this is 'the' solution, I was going mad that I cannot write 26 bytes without issue!

sumotoy - check your file length - maybe it is my version of your OP code ( can you post a fresh working copy ) - when I ran it (96MHz OC) SerialMonitor goes nuts - it is getting the alphabet and then padding to 65536 with [undisplayble] "ÿ" for me - and that shows in the file length on SerialFlash - and reading that file back to a file shows that.
 
sumotoy - check your file length - maybe it is my version of your OP code ( can you post a fresh working copy ) - when I ran it (96MHz OC) SerialMonitor goes nuts - it is getting the alphabet and then padding to 65536 with [undisplayble] "ÿ" for me - and that shows in the file length on SerialFlash - and reading that file back to a file shows that.

Thats ok. Its because the use of createEraseble()
 
Interesting I wondered where that character came from - good to know - it makes -r reading the file back - or Serial.print() of it dangerous though. It was making me think my machine was broken!

Question: What is the unique property of a createEraseble file? I would have assumed it was written to a flash area where it could be block erased, but I think that isn't correct.
 
ÿ it's the code 255. The erasing function writes 255 all over.
createErasable it's pretty similar to create but will use partition sector blocks to accomodate the file inside, so the file can be easily erased by erasing the block where it was.
chips >= 512 mbit use 256K sectors, everything else seems to have 64K sectors, in my case, write 26 byte will use 262144 or 65536 sectors! Use SPI flash to store small files, configuration data or small text it's a waste of sector...
 
That makes sense sumotoy . . . I read whatever I could on createErasable it left me with the wrong impression - I think I get the utility of it now.

The whole of the file itself isn't Eraseable from the system - but the content is Eraseable/REwritable to zero and the FLASHED ONE bits at the end allow it to GROW to the end of the 'block_size of the sector' - or allocated area with zero's added in a meaningful way.

This allows keeping some type of 'Value Record' - where you (optionally zero) up to the last value as it changes and then place the new 'Last Value'. If you did this once an hour and wrote a 4 byte value in a 65KB sector - you could over time store 16KB values ( where none can be 0xFFFF ) - in the once an hour case you could log for 682 days - and never have to reflash that block.

Ideally it seems - somehow that individual block could be addressed and formatted for use without affecting the SerialFlash file system? Again this is what I expected when it was called "createErasable ".

BTW: I was looking to do exactly this on ESP8266: I used a GPIO BIT for ESTOP. So if you uploaded code that caused a CRASH/REBOOT/WDT loop - you just raise the ESTOP pin and the code checks it in setup and then disables new/questionable/user code. Given the SPIFFS on the ESP8266 this could be done like Windows does with the filesystem dirty bit. When the system boot it looks if the file system had a clean shutdown, or if it was shutdown with possible pending cached file write and then it knows to do a SCANDISK before allowing further use of the filesystem.

I'm picturing reading past all the ZERO DWORDS in the file. When you find a non-zero DWORD then ODD # of bits set means SAFE. even number means UNSAFE/ESTOP. Then setting to SAFE means find that DWORD and 0 a bit to make it ODD, setting to UNSAFE means read and remove a bit to 0 when needed to make an EVEN number. Of course 0xFFFF with 32 bits set would count as UNSAFE - versus 0x0 which would be the unusable state.
 
Last edited:
Status
Not open for further replies.
Back
Top