LittleFS port to Teensy/SPIFlash

Added this test for removing directories and files. But did notice that all files have to be removed in the directory for the directory can be removed.
Code:
  //next test
  //lets make a few files and directories.
  Serial.println();
  file1 = myfs.open("file1", FILE_WRITE);
  file2 = myfs.open("file2", FILE_WRITE);
  file3 = myfs.open("file3", FILE_WRITE);
  file1.println("this is a test");
  file2.println("this is a test");
  file3.println("this is a test");
  file1.close();
  file2.close();
  file3.close();

  myfs.mkdir("test1");
  myfs.mkdir("test2");
  myfs.mkdir("test3");
  printDirectory();
  file1 = myfs.open("/test1/file1", FILE_WRITE);
  file2 = myfs.open("/test2/file2", FILE_WRITE);
  file3 = myfs.open("/test3/file3", FILE_WRITE);
  file1.println("this is a test");
  file2.println("this is a test");
  file3.println("this is a test");
  file1.close();
  file2.close();
  file3.close();

  printDirectory();

  //now lets remove them
  if(myfs.remove("/test3/file3") == true) 
          Serial.println("file /test3/file3 removed!");
  if(myfs.rmdir("test3") == true)
          Serial.println("directory /test3 removed!");
  myfs.remove("/test2/file2");
  myfs.rmdir("test2");

  printDirectory();

Code:
printDirectory
--------------
FILE	PRINTOUTPUT1.txt		628
FILE	PRINTOUTPUT2.txt		630
FILE	file1		16
FILE	file2		16
FILE	file3		16
DIR	structuredData / 
	FILE	logger.txt		480
DIR	test1 / 
	FILE	file1		16
DIR	test2 / 
	FILE	file2		16
DIR	test3 / 
	FILE	file3		16

file /test3/file3 removed!
directory /test3 removed!
printDirectory
--------------
FILE	PRINTOUTPUT1.txt		628
FILE	PRINTOUTPUT2.txt		630
FILE	file1		16
FILE	file2		16
FILE	file3		16
DIR	structuredData / 
	FILE	logger.txt		480
DIR	test1 / 
	FILE	file1		16
 
Sounds like you are making good progress.

Wondering about other stressy things. I was wondering about access to multiple files at same time, which looks like you have.

Like wondering if it is at all sort of thread safe?
What about reading and writing to multiple files using IntervalTimers? And main sketch. Or TimerTool with different types of interrupts maybe at different priorities?

Guess that's some more test cases. If you want to join the fray :) First was trying to verify the new functions.

Then only thing haven't tested yet is seek, peek, position is in there and seems to work. Never played with those functions before so if you have a good example.

Not sure about it being thread safe. Might wind up with some race conditions if trying to write files at the same time? But not an expert on that - usually figure it out by testing it.
 
I added support for SPI flash chips.

https://github.com/PaulStoffregen/LittleFS/commit/5ba30a05e53234bc803fe15a132fba33f21b96db

Or chip (singular), as only Winbond W25Q64JVSSIQ is configured so far in the list of known chips.

You create an instance of LittleFS_SPIFlash, then call begin(csPin) or begin(csPin, port), where "port" is SPI, SPI1 or SPI2. So far SPI1 and SPI2 are untested, but theoretically they ought to work.


Here's a test program.

Code:
#include <LittleFS.h>

LittleFS_RAM myfs;
char buf[200000];

LittleFS_SPIFlash myflash;

void setup() {
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
  while (!Serial) ; // wait
  Serial.println("LittleFS Test"); delay(5);
  if (!myfs.begin(buf, sizeof(buf))) {
    Serial.println("Error starting ramdisk");
    while (1) ;
  }
  Serial.println("started");
  File f = myfs.open("test.txt", FILE_WRITE);
  Serial.println("opened test.txt");
  f.println("This is a test....");
  Serial.println("wrote to file");
  //f.whoami();
  f.close();
  Serial.println();

  File in = myfs.open("test.txt");
  if (in) Serial.println("opened file for read");
  char buf[256];
  int n = in.read(buf, 256);
  Serial.printf("read %d bytes\n", n);
  if (n > 255) n = 255;
  buf[n] = 0;
  Serial.println(buf);
  Serial.println("done printing, now close the file");
  in.close();
  Serial.println();

  Serial.println("try writing more");
  f = myfs.open("test.txt", FILE_WRITE);
  if (f) Serial.println("opened test.txt again for writing");
  f.println("another test");
  Serial.println("after write");
  //f.whoami();
  f.close();
  Serial.println();

  in = myfs.open("test.txt");
  if (in) Serial.println("opened file for read");
  char buf2[256];
  n = in.read(buf2, 256);
  Serial.printf("read %d bytes\n", n);
  if (n > 255) n = 255;
  buf2[n] = 0;
  Serial.println(buf2);
  in.close();

  delay(10);
  printDirectory();

  Serial.println("create folder");
  if (myfs.mkdir("myfolder")) {
    Serial.println("  success");
  } else {
    Serial.println("  failed");
  }
  Serial.println();

  printDirectory();

  Serial.println("write to file in folder");
  f = myfs.open("/myfolder/morestuff.txt", FILE_WRITE);
  if (f) Serial.println("opened myfolder/morestuff.txt for write");
  f.println("some more text to write into 2nd file");
  f.close();
  Serial.println();

  printDirectory();

  Serial.println("**************************************\n");

  Serial.println("SPI Flash");
  if (!myflash.begin(4)) {
    Serial.println("error initializing");
    while (1) ; // stop here
  }
  Serial.println("started ok\n");

  Serial.println("try to read a file already stored on the flash");
  in = myflash.open("test.txt");
  if (in) {
    Serial.println("opened file for read");
    n = in.read(buf, 256);
    Serial.printf("read %d bytes\n", n);
    if (n > 255) n = 255;
    buf[n] = 0;
    Serial.println(buf);
    in.close();
  } else {
    Serial.printf("couldn't open file - normal for virgin flash");
  }
  Serial.println();

  printDirectoryFlash();

  Serial.println("write some more data to the file");
  f = myflash.open("test.txt", FILE_WRITE);
  if (f) {
    Serial.println("adding to file");
    f.println("adding more to the file");
    f.close();
  } else {
    Serial.println("couldn't open file for writing");
  }
  Serial.println();
  
  printDirectoryFlash();

  Serial.println("read the file again from the flash");
  in = myflash.open("test.txt");
  if (in) {
    Serial.println("opened file for read");
    n = in.read(buf, 256);
    Serial.printf("read %d bytes\n", n);
    if (n > 255) n = 255;
    buf[n] = 0;
    Serial.println(buf);
    in.close();
  } else {
    Serial.printf("couldn't open file - not good");
  }
  Serial.println();






}




void printDirectoryFlash() {
  Serial.println("printDirectory\n--------------");
  printDirectory(myflash.open("/"), 0);
  Serial.println();
}

void printDirectory() {
  Serial.println("printDirectory\n--------------");
  printDirectory(myfs.open("/"), 0);
  Serial.println();
}

void printDirectory(File dir, int numTabs) {
  //dir.whoami();
  while (true) {

    static int count = 0;
    if (++count > 20) while (1) ;

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      //Serial.println("**nomorefiles**");
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println(" / ");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

void loop() {
}

Next I'm going to work on QSPI / FlexSPI support for the memory expansion on Teensy 4.1...
 
@KurtE - your timer test using callbacks from TimerTool example:
Code:
#include "TeensyTimerTool.h"

using namespace TeensyTimerTool;

Timer t1(TCK);  // Tick-Timer does not use any hardware timer (20 32bit channels)
Timer t2(TMR1); // First channel on TMR1 aka QUAD timer module. (TMR1 - TMR4, four 16bit channels each)
Timer t3(GPT1); // GPT1 module (one 32bit channel per module)
Timer t4(TMR1); // Second channel on TMR1

#include <LittleFS.h>

LittleFS_RAM myfs;
char buf[200000];


File pulse200, pulse400;
elapsedMicros my_us;
elapsedMillis my_ms;
elapsedMillis timer;


// Callbacks ===================================================================================

void callback_200()  // this callback has context, i.e. parameter
{
    pulse200.println(my_ms);
}

void callback_400()  // this callback has context, i.e. parameter
{
    pulse400.println(my_us);
}


void LED_ON()
{
    digitalWriteFast(LED_BUILTIN, HIGH); // LED On
    t4.trigger(10'000);                  // trigger t4 to switch of after 10ms
}

void LED_OFF()
{
    digitalWriteFast(LED_BUILTIN, LOW);
}

//================================================================================================

void setup()
{
  while (!Serial) ; // wait
    Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  Serial.println("LittleFS Timer Test"); delay(5);
  
  if (!myfs.begin(buf, sizeof(buf))) {
    Serial.println("Error starting ramdisk");
    while (1) ;
  }

  Serial.println("create pulse200 and pulse400 files");
  pulse200 = myfs.open("pulse200.txt", FILE_WRITE);
  pulse400 = myfs.open("pulse400.txt", FILE_WRITE);

    for(unsigned pin = 0; pin <=13; pin++) pinMode(pin,OUTPUT);    

    t1.beginPeriodic([] { callback_200(); }, 50'000); // 200ns pulse every 500 ms
    t2.beginPeriodic([] { callback_400(); },      100); // 400ns pulse every 100 µs  
    t3.beginPeriodic(LED_ON,    1'000'000); // Switch LED on every second
    t4.beginOneShot(LED_OFF);               // One shot timer to switch LED Off
  
}

void printDirectory() {
  Serial.println("printDirectory\n--------------");
  printDirectory(myfs.open("/"), 0);
  Serial.println();
}

void printDirectory(File dir, int numTabs) {
  //dir.whoami();
  while (true) {

    static int count=0;
    if (++count > 100) while (1) ;
    
    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      //Serial.println("**nomorefiles**");
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }

    if(entry.isDirectory()) {
      Serial.print("DIR\t");
    } else {
      Serial.print("FILE\t");
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println(" / ");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}



void loop()
{

  if(timer > 2000) {
    pulse200.close();
    pulse400.close();
    printDirectory();

  Serial.println("PULSE200.txt dump of time");
  pulse200 = myfs.open("pulse200.txt");
  for(uint8_t i = 0; i <100; i++){
      char buf[256];
      int n = pulse200.read(buf, 256);
      if (n > 255) n = 255;
      buf[n] = 0;
      Serial.println(buf);
      if(pulse200.available() == 0) break;
  }
  pulse200.close();

  Serial.println("PULSE400.txt dump of time");
  pulse400 = myfs.open("pulse400.txt");
  for(uint8_t i = 0; i <100; i++){
      char buf[256];
      int n = pulse400.read(buf, 256);
      if (n > 255) n = 255;
      buf[n] = 0;
      Serial.println(buf);
      if(pulse400.available() == 0) break;
  }
  pulse400.close();
    Serial.println("FINISHED");
    Serial.flush();
    while(1){};
  }
}
Output:
Code:
D:\Users\Merli\Documents\Arduino\litteFS_MoreTimers_test\litteFS_MoreTimers_test.ino Nov  6 2020 09:26:00
LittleFS Timer Test
create pulse200 and pulse400 files
printDirectory
--------------
FILE	pulse200.txt		60
FILE	pulse400.txt		48474

PULSE200.txt dump of time
1513
1563
1613
1663
1713
1763
1813
1863
1913
1963

PULSE400.txt dump of time
1462881
1462980
1463080
1463180
1463280
1463380
1463480
1463579
1463679
1463779
1463879
1463979
1464079
1464179
1464278
1464378
1464478
1464578
1464678
1464778
1464877
1464977
1465077
1465177
1465277
1465377
1465476
1465576
146
676
1465776
1465876
1465976
1466075
1466175
1466275
1466375
1466475
1466575
1466675
1466774
1466874
1466974
1467074
1467174
1467274
1467373
1467473
1467573
1467673
1467773
1467873
1467972
1468072
1468172
1468272
1468372
1468472

1468571
1468671
1468771
1468871
1468971
1469071
1469171
1469270
1469370
1469470
1469570
1469670
1469770
1469869
1469969
1470069
1470169
1470269
1470369
1470468
1470568
1470668
1470768
1470868
1470968
1471067
1471167
1471267
14
1367
1471467
1471567
1471667
1471766
1471866
1471966
1472066
1472166
1472266
1472365
1472465
1472565
1472665
1472765
1472865
1472964
1473064
1473164
1473264
1473364
1473464
1473563
1473663
1473763
1473863
1473963
1474063
147416

1474262
1474362
1474462
1474562
1474662
1474762
1474861
1474961
1475061
1475161
1475261
1475361
1475460
1475560
1475660
1475760
1475860
1475960
1476059
1476159
1476259
1476359
1476459
1476559
1476659
1476758
1476858
1476958
1
77058
1477158
1477258
1477357
1477457
1477557
1477657
1477757
1477857
1477956
1478056
1478156
1478256
1478356
1478456
1478555
1478655
1478755
1478855
1478955
1479055
1479155
1479254
1479354
1479454
1479554
1479654
1479754
14798


FINISHED
Only prints first 100 records of each file

on the 100ns writes it does loose data - probably too fast a fast.
 
I added more of the common Winbond flash chips.

Just tried it with a W25Q128JVSIM and does seem to initializing or returning any chip ID.
Code:
**************************************


SPI Flash

flash begin

Flash ID: 00 00 00
error initializing
 
Prior '\n' hang with loop() code went to WORKING with updated LittleFS! Still RAMDISK - but using the multi Flash update code from 6AM.

@mjs513 it should work for you now - as it was ... and below with exception.

Did a minor Mod to write to not delete file EVERY set of 10 files so it cycles adding bytes to the files 3 times, that looked okay until printDirectory was added.

Pulled updated @mjs513 FOX code not printing NULL, and updated loop() code is here.

It does not (always) HANG requiring button press now - but stalls printing unless the lines #222 and #244 are commented out.

It RUNS up to and including the first printDirectory() - then fails to continue?

Code:
#include <LittleFS.h>

LittleFS_RAM myfs;
char buf[200000];

File file1, file2, file3;

char fname[32] = "my_file1";
int szLen = strlen( buf );
elapsedMicros my_us;

//define a struct of various data types
struct MYDATA_t {
	bool data_0;
	float data_1;
	long data_2;
	int data_3;
	char data_4[32];
};

//define a struct joining MYDATA_t to an array of bytes to be stored
union MYDATA4RAM_t {
	MYDATA_t datastruct;
	char Packet[sizeof(MYDATA_t)];
};

MYDATA4RAM_t mydata; //data to be written in memory
MYDATA4RAM_t readdata; //data read from memory


void setup() {
	pinMode(13, OUTPUT);
	digitalWrite(13, HIGH);
	while (!Serial) ; // wait
	Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
	Serial.println("LittleFS Test"); delay(5);

	if (!myfs.begin(buf, sizeof(buf))) {
		Serial.println("Error starting ramdisk");
		while (1) ;
	}

	printDirectory();

	//test of print
	Serial.println("Using println and printf to printoutput file");
	file1 = myfs.open("PRINTOUTPUT1.txt", FILE_WRITE);
	Serial.println("opened PRINTOUTPUT1.txt");
	file2 = myfs.open("PRINTOUTPUT2.txt", FILE_WRITE);
	Serial.println("opened PRINTOUTPUT2.txt");

	for (uint8_t i = 0; i < 10; i++) {
		file1.println("abcdefghijklmnopqrstuvwxyz");
		file1.printf("Rec: %d, Float: %f, Int: %d\n", i, i + 26.4, i + 98);
		file2.println("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
		//eRAM.println("THIS IS A TEST");
		file2.printf("Rec: %d, Float: %f, Int: %d\n", i, i + 56.4, i + 198);
	}

	file1.close();
	file2.close();

	printDirectory();

	Serial.println("-------------------------------");
	Serial.println("File1 contents:");
	Serial.println("-------------------------------");

	file1 = myfs.open("PRINTOUTPUT1.txt");
	Serial.printf("File1 size: %d\n", file1.size());
	int filesize = file1.size();
	for (uint8_t i = 0; i < 30; i++) {
		char buf[256];
		int n = file1.read(buf, 256);
		//Serial.printf("read %d bytes\n", n);
		if (n > 255) n = 255;
		buf[n] = 0;
		Serial.println(buf);
		//Used this in place of a file1.eof() function
		//if((file1.position()+1) > filesize) break;
		if (file1.available() == 0) break;
	}
	file1.close();

	structuredWrite();

}

void structuredWrite() {
	Serial.println("-------------------------------");
	Serial.println("File3 byte conversion test:");
	Serial.println("-------------------------------");
	Serial.println();

	uint32_t arraySize = sizeof(MYDATA_t);

	//---------init data - load array
	mydata.datastruct.data_0 = true;
	Serial.print("Data_0: ");
	if (mydata.datastruct.data_0) Serial.println("true");
	if (!mydata.datastruct.data_0) Serial.println("false");
	mydata.datastruct.data_1 = 1.3575;
	Serial.print("Data_1: ");
	Serial.println(mydata.datastruct.data_1, DEC);
	mydata.datastruct.data_2 = 314159L;
	Serial.print("Data_2: ");
	Serial.println(mydata.datastruct.data_2, DEC);
	mydata.datastruct.data_3 = 142;
	Serial.print("Data_3: ");
	Serial.println(mydata.datastruct.data_3, DEC);
	//string test
	String string_test = "The Quick Brown Fox";
	int stringLen = string_test.length();
	Serial.println(stringLen);
	string_test.toCharArray(mydata.datastruct.data_4, stringLen + 1);
	Serial.println(string_test);

	Serial.println("Init Done - array loaded");
	Serial.println("...... ...... ......");

	Serial.println("create folder");
	if (myfs.mkdir("structuredData")) {
		Serial.println("  success");
	} else {
		Serial.println("  failed");
	}
	Serial.println();

	//lets try something more interesting and complicated
	file3 = myfs.open("/structuredData/logger.txt", FILE_WRITE);
	for (int32_t i = 0; i < 10; i++) {
		file3.write(mydata.Packet, arraySize);
	}
	file3.close();

	Serial.println();
	Serial.println("2nd Directory contents:");
	printDirectory();
	Serial.println();

	file3 = myfs.open("/structuredData/logger.txt");
	for (uint8_t i = 0; i < 30; i++) {
		//if(eRAM.f_eof(file3)) //break loop on EOF
		//    break;
		int n = file3.read(readdata.Packet, arraySize);
		//Used this in place of a file1.eof() function

		//---------Send data to serial
		if (readdata.datastruct.data_0) Serial.print("true");
		if (!readdata.datastruct.data_0) Serial.print("false");
		Serial.print(", ");
		Serial.print(readdata.datastruct.data_1, DEC);
		Serial.print(", ");
		Serial.print(readdata.datastruct.data_2, DEC);
		Serial.print(", ");
		Serial.print(readdata.datastruct.data_3, DEC);
		Serial.print(", ");
		for (uint8_t j = 0; j < stringLen; j++) {
			Serial.print(readdata.datastruct.data_4[j]);
		}
		Serial.println();
		if ((file3.position() + 1) > file3.size()) break;
		//if(file3.available() == 0) break;
	}

	file3.close();
}


void printDirectory() {
	Serial.println("printDirectory\n--------------");
	printDirectory(myfs.open("/"), 0);
	Serial.println();
}

void printDirectory(File dir, int numTabs) {
	//dir.whoami();
	while (true) {

		static int count = 0;
		if (++count > 20) while (1) ;

		File entry =  dir.openNextFile();
		if (! entry) {
			// no more files
			//Serial.println("**nomorefiles**");
			break;
		}
		for (uint8_t i = 0; i < numTabs; i++) {
			Serial.print('\t');
		}

		if (entry.isDirectory()) {
			Serial.print("DIR\t");
		} else {
			Serial.print("FILE\t");
		}
		Serial.print(entry.name());
		if (entry.isDirectory()) {
			Serial.println(" / ");
			printDirectory(entry, numTabs + 1);
		} else {
			// files have sizes, directories do not
			Serial.print("\t\t");
			Serial.println(entry.size(), DEC);
		}
		entry.close();
	}
}

uint32_t lCnt = 0;
uint32_t cCnt = 0;
char szLoop[] = "#_file.txt";
void loop() {
	lCnt++;
	int ii;
	byte nNum = lCnt % 10;
	szLoop[0] = '0' + nNum;
	if ( cCnt >= 3 && myfs.exists(szLoop) ) {
		if ( nNum == 1 ) {
			Serial.print('\n');
	printDirectory(myfs.open("/"), 0);
		}
		file3 = myfs.open(szLoop);
		ii = 0;
		char mm;
		while ( file3.available() ) {
			file3.read( &mm , 1 );
			ii++;
			if ( '@' != mm ) Serial.print( "Bad Byte!\n");
		}
		Serial.printf( " file %s had %u bytes\n", szLoop, ii );
		file3.close();
		myfs.remove(szLoop);
	}
	else {
//		file3 = myfs.open(szLoop, FILE_WRITE);
		if ( nNum == 0 ) {
			nNum = 10;
			cCnt++;
			if ( cCnt >= 5 ) {
				cCnt = 0;
				Serial.print('\n');
	[B]printDirectory(myfs.open("/"), 0);[/B]
				delay(2000);
			}
		}
		char mm = '@';
		file3 = myfs.open(szLoop, FILE_WRITE); // Moving this after printDir doesn't matter
		for ( ii = 0; ii < nNum * 100; ii++ ) {
			file3.write( &mm , 1 );
		}
		file3.close();
		Serial.print('.');
		delay(100);
	}
}
 
Last edited:
Right now I am not finding any of my flash chips, I know I have a few around here somewhere. I do have a couple on the T4.1s...

So will do some more searching, and then may have to order some.
 
Right now I am not finding any of my flash chips, I know I have a few around here somewhere. I do have a couple on the T4.1s...

So will do some more searching, and then may have to order some.

These are the SPI flash chips like on an Audio card correct? Any of those populated Audio boards handy Kurt?

That reminds me I have a T_4.0 Beta Breakout with Audio w/Flash.
 
Though - getting FAIL using T_4.0 breakout using supplied Rev B Audio board socket with Winbond 2SQ128FVSG

That indicates MEMCS on #6 and MOSI on pin #7

Seeing failure with above Paul FLASH sketch:
Code:
**************************************

SPI Flash
flash begin
Flash ID: FF FF FF
error initializing
 
These are the SPI flash chips like on an Audio card correct? Any of those populated Audio boards handy Kurt?

That reminds me I have a T_4.0 Beta Breakout with Audio w/Flash.

I don't think so, I don't think I ever populated any of them. I did find one of the 1G flash chips I populated a T4.1 (W25NO1GVZEIG) or thereabout that was from a different thread. Not sure I want to populate with this one...
I think there were a few others around as well.. But so far have not found them

Thought about doing an order to PJRC... But I don't see any on the site...

Will keep looking.
 
SUCCESS !!!!!

I have Two REV D boards with that Flash - one bottom female header on a T_4.0 Top Pin:

Code:
...
**************************************

SPI Flash
flash begin
Flash ID: EF 40 18
Flash size is 16.00 Mbyte
attemping to mount existing media
couldn't mount media, attemping to format
  waited 82307 us
  waited 165 us
  waited 82468 us
  waited 164 us
attemping to mount freshly formatted media
success
started ok

try to read a file already stored on the flash
couldn't open file - normal for virgin flash
printDirectory
--------------

write some more data to the file
  waited 146 us
adding to file
  waited 155 us

printDirectory
--------------
test.txt		25

read the file again from the flash
opened file for read
read 25 bytes
adding more to the file
 
I did find one of the 1G flash chips I populated a T4.1 (W25NO1GVZEIG)

FWIW, I just found the 1Gbit NAND chips I bought earlier this year.

w25n01gv.jpg

I was reading the datasheet again this morning. While these chips do have amazing capacity, the page & sector sizes are much larger. They'll probably be much more useful for large files.

Earlier I had planned to memory map these. Now I'm reconsidering whether that is really a good idea. Apparently 2Gbit and 4Gbit parts are on the horizon (8Gbit might be too - info isn't as clear), and we just don't have enough FlexSPI address space to support them that way. But we might be able to use the full capacity of those future chips if I write the code to use the other interface which isn't memory mapped. Difficult decisions....
 
Modified setup to end with :: for ( int ii=0; ii<60; ii++ ) loopTest();

Where loopTest() is prior RAMDISK loop() code just called 60 times and modified to use "myflash."

It worked ONCE until it did print :: printDirectoryFlash();

BEING STATIC ( not seeing FORMAT ) ... Now it is dying running the initial PAUL code:
Code:
adding more to the file

printDirectory
--------------
0_file.txt		3000
1_file.txt		300
2_file.txt		600
3_file.txt		900
4_file.txt		1200
5_file.txt		1500
6_file.txt		1800
7_file.txt		2100
8_file.txt		2400

here is the edited code - I removed printDirectoryFlash() in loopTest() after it failed - but now it doesn't get that far:
Code:
#include <LittleFS.h>

LittleFS_RAM myfs;
char buf[200000];

LittleFS_SPIFlash myflash;

void setup() {
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
  while (!Serial) ; // wait
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  Serial.println("LittleFS Test"); delay(5);
  if (!myfs.begin(buf, sizeof(buf))) {
    Serial.println("Error starting ramdisk");
    while (1) ;
  }
  Serial.println("started");
  File f = myfs.open("test.txt", FILE_WRITE);
  Serial.println("opened test.txt");
  f.println("This is a test....");
  Serial.println("wrote to file");
  //f.whoami();
  f.close();
  Serial.println();

  File in = myfs.open("test.txt");
  if (in) Serial.println("opened file for read");
  char buf[256];
  int n = in.read(buf, 256);
  Serial.printf("read %d bytes\n", n);
  if (n > 255) n = 255;
  buf[n] = 0;
  Serial.println(buf);
  Serial.println("done printing, now close the file");
  in.close();
  Serial.println();

  Serial.println("try writing more");
  f = myfs.open("test.txt", FILE_WRITE);
  if (f) Serial.println("opened test.txt again for writing");
  f.println("another test");
  Serial.println("after write");
  //f.whoami();
  f.close();
  Serial.println();

  in = myfs.open("test.txt");
  if (in) Serial.println("opened file for read");
  char buf2[256];
  n = in.read(buf2, 256);
  Serial.printf("read %d bytes\n", n);
  if (n > 255) n = 255;
  buf2[n] = 0;
  Serial.println(buf2);
  in.close();

  delay(10);
  printDirectory();

  Serial.println("create folder");
  if (myfs.mkdir("myfolder")) {
    Serial.println("  success");
  } else {
    Serial.println("  failed");
  }
  Serial.println();

  printDirectory();

  Serial.println("write to file in folder");
  f = myfs.open("/myfolder/morestuff.txt", FILE_WRITE);
  if (f) Serial.println("opened myfolder/morestuff.txt for write");
  f.println("some more text to write into 2nd file");
  f.close();
  Serial.println();

  printDirectory();

  Serial.println("**************************************\n");

  Serial.println("SPI Flash");
  if (!myflash.begin(6)) {
    Serial.println("error initializing");
    while (1) ; // stop here
  }
  Serial.println("started ok\n");

  Serial.println("try to read a file already stored on the flash");
  in = myflash.open("test.txt");
  if (in) {
    Serial.println("opened file for read");
    n = in.read(buf, 256);
    Serial.printf("read %d bytes\n", n);
    if (n > 255) n = 255;
    buf[n] = 0;
    Serial.println(buf);
    in.close();
  } else {
    Serial.printf("couldn't open file - normal for virgin flash");
  }
  Serial.println();

  printDirectoryFlash();

  Serial.println("write some more data to the file");
  f = myflash.open("test.txt", FILE_WRITE);
  if (f) {
    Serial.println("adding to file");
    f.println("adding more to the file");
    f.close();
  } else {
    Serial.println("couldn't open file for writing");
  }
  Serial.println();
  
  printDirectoryFlash();

  Serial.println("read the file again from the flash");
  in = myflash.open("test.txt");
  if (in) {
    Serial.println("opened file for read");
    n = in.read(buf, 256);
    Serial.printf("read %d bytes\n", n);
    if (n > 255) n = 255;
    buf[n] = 0;
    Serial.println(buf);
    in.close();
  } else {
    Serial.printf("couldn't open file - not good");
  }
  Serial.println();

[B]  for ( int ii = 0; ii < 20; ii++ ) loopTest();  [COLOR="#FF0000"]// EDITED THIS CODE TO REPRO FLASH dir print fail[/COLOR][/B] // 20 not 21 for valid counts
  Serial.printf("loopTest() COMPLETED !!!!");

}




void printDirectoryFlash() {
  Serial.println("printDirectory\n--------------");
  printDirectory(myflash.open("/"), 0);
  Serial.println();
}

void printDirectory() {
  Serial.println("printDirectory\n--------------");
  printDirectory(myfs.open("/"), 0);
  Serial.println();
}

void printDirectory(File dir, int numTabs) {
  //dir.whoami();
  while (true) {

    static int count = 0;
    if (++count > 20) while (1) ;

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      //Serial.println("**nomorefiles**");
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println(" / ");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

void loop() {
}

uint32_t lCnt = 0;
uint32_t cCnt = 0;
File file3;
char szLoop[] = "#_file.txt";
void loopTest() {
	lCnt++;
	int ii;
	byte nNum = lCnt % 10;
	szLoop[0] = '0' + nNum;
	if ( cCnt >= 3 && myflash.exists(szLoop) ) {
		if ( nNum == 1 ) {
			Serial.print('\n');
//  printDirectoryFlash();
		}
		file3 = myflash.open(szLoop);
		ii = 0;
		char mm;
		while ( file3.available() ) {
			file3.read( &mm , 1 );
			ii++;
			if ( '@' != mm ) Serial.print( "Bad Byte!\n");
		}
		Serial.printf( " file %s had %u bytes\n", szLoop, ii );
		file3.close();
		myflash.remove(szLoop);
	}
	else {
//		file3 = myflash.open(szLoop, FILE_WRITE);
		if ( nNum == 0 ) {
			nNum = 10;
			cCnt++;
			if ( cCnt >= 5 ) {
				cCnt = 0;
				Serial.print('\n');
//  printDirectoryFlash();
				delay(2000);
			}
		}
		char mm = '@';
		file3 = myflash.open(szLoop, FILE_WRITE); // Moving this after printDir doesn't matter
		for ( ii = 0; ii < nNum * 100; ii++ ) {
			file3.write( &mm , 1 );
		}
		file3.close();
		Serial.print('.');
		delay(100);
	}
}
 
Last edited:
Actually I may have found some with Propshield. Just pulled out a new Propshield LC.. Probably need to solder some pins on it. First a quick search for ones already with pins...
 
Question is this supposed to be T4.x only?

Since I found a propshield with a T3.2, I thought I would try to compile for it... and the build fails:
Code:
C:\Users\kurte\Documents\Arduino\libraries\LittleFS\src\LittleFS.cpp: In member function 'int LittleFS_SPIFlash::prog(lfs_block_t, lfs_off_t, const void*, lfs_size_t)':
C:\Users\kurte\Documents\Arduino\libraries\LittleFS\src\LittleFS.cpp:158:22: error: 'delayNanoseconds' was not declared in this scope
  delayNanoseconds(250);
                      ^
C:\Users\kurte\Documents\Arduino\libraries\LittleFS\src\LittleFS.cpp: In member function 'int LittleFS_SPIFlash::erase(lfs_block_t)':
C:\Users\kurte\Documents\Arduino\libraries\LittleFS\src\LittleFS.cpp:179:22: error: 'delayNanoseconds' was not declared in this scope
  delayNanoseconds(250);
                      ^
Using library LittleFS at version 1.0.0 in folder: C:\Users\kurte\Documents\Arduino\libraries\LittleFS 
Using library SPI at version 1.0 in folder: C:\arduino-1.8.13\hardware\teensy\avr\libraries\SPI 
Error compiling for board Teensy 3.2 / 3.1.
Will probably plug in T4. instead. But wonder
 
I anyone wants to buy some of those 1Gbit chips, Digikey as plenty in stock for about $2 each. Part number is W25N01GVZEIGCT-ND.

https://www.digikey.com/en/products/detail/winbond-electronics/W25N01GVZEIG-TR/5803931

Looks like I already got 4 of those - and soldered two I just touched!

Went back to the Audio and did a FORMAT everything - then Ran sketch post #65
Only change {end of setup()} was this to show it finished - which it did:
Code:
  for ( int ii = 0; ii < 60; ii++ ) loopTest();
  Serial.printf("loopTest() COMPLETED !!!!");
}

I can now run it repeatedly without failure - BUT the early PAUL call to printDirectoryFlash(); does not show my files now???
Code:
Flash Memory has 16777216 bytes.
Erasing ALL Flash Memory:
  estimated wait: 40 seconds.
  Yes, full chip erase is SLOW!
............................................
Erase completed
  actual wait: 44 seconds.

T:\tCode\littleFS\lfsFLASHspi\lfsFLASHspi.ino Nov  6 2020 11:51:08
LittleFS Test
started
opened test.txt
wrote to file

opened file for read
read 20 bytes
This is a test....

done printing, now close the file

try writing more
opened test.txt again for writing
after write

opened file for read
read 34 bytes
This is a test....
another test

printDirectory
--------------
test.txt		34

create folder
  success

printDirectory
--------------
myfolder / 
test.txt		34

write to file in folder
opened myfolder/morestuff.txt for write

printDirectory
--------------
myfolder / 
	morestuff.txt		39
test.txt		34

**************************************

SPI Flash
flash begin
Flash ID: EF 40 18
Flash size is 16.00 Mbyte
attemping to mount existing media
couldn't mount media, attemping to format
  waited 85736 us
  waited 165 us
  waited 81405 us
  waited 166 us
attemping to mount freshly formatted media
success
started ok

try to read a file already stored on the flash
couldn't open file - normal for virgin flash
printDirectory
--------------

write some more data to the file
  waited 146 us
adding to file
  waited 154 us

printDirectory
--------------
test.txt		25

read the file again from the flash
opened file for read
read 25 bytes
adding more to the file


  waited 148 us
  waited 227 us
.  waited 148 us
  waited 325 us
.  waited 148 us
  waited 82631 us
  waited 367 us
  waited 161 us
  waited 138 us
.  waited 148 us
  waited 82614 us
  waited 367 us
  waited 259 us
  waited 138 us
.  waited 147 us
  waited 82677 us
  waited 367 us
  waited 356 us
  waited 138 us
.  waited 146 us
  waited 86135 us
  waited 367 us
  waited 367 us
  waited 204 us
  waited 138 us
.  waited 148 us
  waited 89524 us
  waited 367 us
  waited 367 us
  waited 301 us
  waited 83168 us
  waited 364 us
  waited 367 us
  waited 165 us
.  waited 148 us
  waited 86167 us
  waited 367 us
  waited 367 us
  waited 368 us
  waited 150 us
  waited 138 us
.  waited 148 us
  waited 82771 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 248 us
  waited 138 us
.  waited 147 us
  waited 82715 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 344 us
  waited 138 us
.  waited 325 us
.  waited 82760 us
  waited 367 us
  waited 259 us
  waited 138 us
.  waited 82707 us
  waited 367 us
  waited 368 us
  waited 204 us
  waited 138 us
.  waited 86188 us
  waited 367 us
  waited 368 us
  waited 367 us
  waited 151 us
  waited 138 us
.  waited 82712 us
  waited 368 us
  waited 367 us
  waited 367 us
  waited 344 us
  waited 138 us
.  waited 82768 us
  waited 367 us
  waited 367 us
  waited 368 us
  waited 368 us
  waited 290 us
  waited 137 us
.  waited 82783 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 367 us
  waited 236 us
  waited 138 us
.  waited 82754 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 368 us
  waited 181 us
  waited 81428 us
  waited 364 us
  waited 367 us
  waited 151 us
.  waited 82776 us
  waited 367 us
  waited 368 us
  waited 368 us
  waited 367 us
  waited 367 us
  waited 368 us
  waited 367 us
  waited 127 us
  waited 137 us
.  waited 82653 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 368 us
  waited 368 us
  waited 367 us
  waited 367 us
  waited 321 us
  waited 137 us
.  waited 82703 us
  waited 367 us
  waited 162 us
  waited 138 us
.  waited 82568 us
  waited 368 us
  waited 367 us
  waited 204 us
  waited 138 us
.  waited 82657 us
  waited 368 us
  waited 367 us
  waited 367 us
  waited 247 us
  waited 138 us
.  waited 82480 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 290 us
  waited 138 us
.  waited 82448 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 367 us
  waited 333 us
  waited 138 us
.  waited 86280 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 368 us
  waited 367 us
  waited 126 us
  waited 137 us
.  waited 82714 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 170 us
  waited 138 us
.  waited 82560 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 367 us
  waited 368 us
  waited 367 us
  waited 367 us
  waited 211 us
  waited 137 us
.  waited 82545 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 367 us
  waited 367 us
  waited 254 us
  waited 138 us
.  waited 82382 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 368 us
  waited 367 us
  waited 367 us
  waited 368 us
  waited 367 us
  waited 367 us
  waited 297 us
  waited 138 us
.
 file 1_file.txt had 300 bytes
  waited 129 us
 file 2_file.txt had 600 bytes
  waited 83127 us
  waited 364 us
  waited 163 us
 file 3_file.txt had 900 bytes
  waited 129 us
 file 4_file.txt had 1200 bytes
  waited 129 us
 file 5_file.txt had 1500 bytes
  waited 129 us
 file 6_file.txt had 1800 bytes
  waited 129 us
 file 7_file.txt had 2100 bytes
  waited 129 us
 file 8_file.txt had 2400 bytes
  waited 129 us
 file 9_file.txt had 2700 bytes
  waited 129 us
 file 0_file.txt had 3000 bytes
  waited 128 us
  waited 148 us
  waited 228 us
.  waited 147 us
  waited 325 us
.  waited 147 us
  waited 82296 us
  waited 367 us
  waited 161 us
  waited 138 us
.  waited 83419 us
  waited 364 us
  waited 329 us
  waited 82071 us
  waited 367 us
  waited 259 us
  waited 85415 us
  waited 364 us
  waited 337 us
.  waited 148 us
  waited 81996 us
  waited 367 us
  waited 356 us
  waited 138 us
.  waited 147 us
  waited 86940 us
  waited 367 us
  waited 368 us
  waited 204 us
  waited 138 us
.  waited 148 us
  waited 84007 us
  waited 367 us
  waited 368 us
  waited 301 us
  waited 138 us
.  waited 148 us
  waited 83221 us
  waited 368 us
  waited 367 us
  waited 368 us
  waited 150 us
  waited 137 us
.  waited 147 us
  waited 85406 us
  waited 368 us
  waited 367 us
  waited 368 us
  waited 247 us
  waited 137 us
.  waited 147 us
  waited 81837 us
  waited 367 us
  waited 368 us
  waited 367 us
  waited 343 us
  waited 137 us
.
 file 1_file.txt had 100 bytes
  waited 129 us
 file 2_file.txt had 200 bytes
  waited 129 us
 file 3_file.txt had 300 bytes
  waited 83325 us
  waited 363 us
  waited 137 us
 file 4_file.txt had 400 bytes
  waited 128 us
 file 5_file.txt had 500 bytes
  waited 129 us
 file 6_file.txt had 600 bytes
  waited 128 us
 file 7_file.txt had 700 bytes
  waited 128 us
 file 8_file.txt had 800 bytes
  waited 129 us
 file 9_file.txt had 900 bytes
  waited 128 us
 file 0_file.txt had 1000 bytes
  waited 129 us
loopTest() COMPLETED !!!!
 
re post #69 - to assure loopTest had not removed the files I changed the 60 to 61 {should have made it 71 as it groups in 10} - still not present.

So I changed end of setup() to #20 - and these sizes agree with two write iterations:
Code:
  for ( int ii = 0; ii < 20; ii++ ) loopTest();
  Serial.printf("loopTest() COMPLETED !!!!");
}

The files are now present for sure on RESET as again the initial PAUL code hangs printing the directory as before:
Code:
...
adding more to the file
adding more to the file


printDirectory
--------------
0_file.txt		2000
1_file.txt		400
2_file.txt		400
3_file.txt		600
4_file.txt		800
5_file.txt		1000
6_file.txt		1200
7_file.txt		1400
8_file.txt		1600
 
Last edited:
@Paul - is there a way to manually trigger lfs_format() without doing Flash EraseEverything?

Note - edited above to 20's for accurate file write iterations where it hangs:
Code:
printDirectory
--------------
0_file.txt		2000
1_file.txt		200
2_file.txt		400
3_file.txt		600
4_file.txt		800
5_file.txt		1000
6_file.txt		1200
7_file.txt		1400
8_file.txt		1600
 
FWIW, I just found the 1Gbit NAND chips I bought earlier this year.

View attachment 22344

I was reading the datasheet again this morning. While these chips do have amazing capacity, the page & sector sizes are much larger. They'll probably be much more useful for large files.

Earlier I had planned to memory map these. Now I'm reconsidering whether that is really a good idea. Apparently 2Gbit and 4Gbit parts are on the horizon (8Gbit might be too - info isn't as clear), and we just don't have enough FlexSPI address space to support them that way. But we might be able to use the full capacity of those future chips if I write the code to use the other interface which isn't memory mapped. Difficult decisions....

Way back when we did get the 1GB chip working on a T4.1 with some success. You might want to check this thread out: https://forum.pjrc.com/threads/61566-NAND-flash-support-in-1-54?highlight=nand

The example code and lib is posted on github if you decided you want to play with it: https://github.com/PaulStoffregen/teensy41_extram (https://github.com/PaulStoffregen/teensy41_extram/tree/master/extNAND_t41/w25n01g_t4). Don't think you are going to be able to memory map this chip the way you want to anyway - chip kind of works differently.

Now to read the other posts and see what I missed.

Probably will solder up another breakout with a Flash chip - not sure the one I have is working anymore - checked it with SErialFlash and it does show the JEDEC but then the tests failed.
Code:
Raw SerialFlash Hardware Test



Read Chip Identification:

  JEDEC ID:     EF 70 18

  Part Nummber: (unknown chip)

  Memory Size:  16777216 bytes

  Block Size:   65536 bytes



Reading Chip...

  Previous data found at address 16384

  You must fully erase the chip before this test

  found this: 00 00 00 00 15 F5 95 4B 

     correct: 00 00 40 00 D5 5A F7 CA 



Tests Failed  :{
 
Quick FYI - The flash worked for the Prop shield:
Code:
LittleFS Test

flash begin

Flash ID: EF 40 17
Flash size is 8.00 Mbyte
attemping to mount existing media

couldn't mount media, attemping to format

  waited 44089 us
  waited 185 us
  waited 50385 us
  waited 185 us
attemping to mount freshly formatted media

success

started

  waited 164 us
opened test.txt

wrote to file

  waited 168 us

opened file for read

read 20 bytes
This is a test....

done printing, now close the file

try writing more

opened test.txt again for writing

after write
  File    this=2006fdbc, f=202036f8
  LittleFSFile this=202036f8, refcount=1
  waited 183 us
opened file for read
read 34 bytes
This is a test....

another test

printDirectory
--------------
test.txt		34

create folder
  waited 46844 us
  waited 145 us
  waited 184 us
  success

printDirectory
--------------
myfolder / 
test.txt		34


write to file in folder

  waited 169 us
opened myfolder/morestuff.txt for write

  waited 188 us


printDirectory
--------------

myfolder / 
	morestuff.txt		39
test.txt		34
Not sure if I edited out all of he extra lines or not ;) But worked...

Wondering can we read those flash chips soldered to bottom of T4.1 using SPI?
Something like: if (!myfs.begin(51, SPI2)) ?
 
Back
Top