#include <LittleFS.h>
//#define TEST_RAM
#define TEST_SPI
//#define TEST_QSPI
#ifdef TEST_RAM
LittleFS_RAM myfs;
DMAMEM char buf[400000]; // USE DMAMEM for more memory than ITCM allows - or remove
char szDiskMem[] = "RAM_DISK";
#elif defined(TEST_SPI)
const int FlashChipSelect = 6; // digital pin for flash chip CS pin
//const int FlashChipSelect = 21; // Arduino 101 built-in SPI Flash
#define FORMATSPI
//#define FORMATSPI2
LittleFS_SPIFlash myfs;
char szDiskMem[] = "SPI_DISK";
#else
LittleFS_QSPIFlash myfs;
char szDiskMem[] = "QSPI_DISK";
#endif
File file3;
#define SUBADD 10 // bytes added each pass (*times file number)
#define BIGADD 1 // bytes added each pass - bigger will quickly consume more space
#define MAXNUM 26 // ALPHA A-Z is 26, less for fewer files
#define DELDELAY 100 // delay before DEL files
#define ADDDELAY 10 // delay on ADD FILE
uint8_t offsetPr[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113 };
void setup() {
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
while (!Serial) ; // wait
Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
Serial.println("LittleFS Test : File Integrity"); delay(5);
#ifdef TEST_RAM
if (!myfs.begin(buf, sizeof(buf))) {
#elif defined(TEST_SPI)
#ifdef FORMATSPI
if (!myfs.begin( FlashChipSelect )) {
#elif defined(FORMATSPI2)
pinMode(FlashChipSelect, OUTPUT);
digitalWriteFast(FlashChipSelect, LOW);
SPI2.setMOSI(50);
SPI2.setMISO(54);
SPI2.setSCK(49);
SPI2.begin();
if (!myfs.begin(51, SPI2)) {
#endif
#else
if (!myfs.begin()) {
#endif
Serial.printf("Error starting %s\n", szDiskMem);
checkInput( 1 );
}
printDirectory();
parseCmd( '?' );
char szDir[16];
for ( int ii = 0; ii < 10; ii++ ) {
sprintf( szDir, "/%c_dir", '0' + ii );
myfs.mkdir( szDir );
}
checkInput( 1 );
printDirectory();
}
int loopLimit = 0; // -1 continuous, otherwise # to count down to 0
bool pauseDir = false;
bool showDir = false;
void loop() {
char szDir[16];
uint32_t chStep;
if ( loopLimit != 0 ) {
if ( loopLimit > 0 )
loopLimit--;
for ( int ii = 0; ii < 11; ii++ ) {
if ( ii == 10 )
sprintf( szDir, "/" );
else
sprintf( szDir, "/%c_dir", '0' + ii );
chStep = fileCycle(szDir);
while ( chStep != fileCycle(szDir) ) checkInput( 0 );
}
checkInput( 0 );
}
else
checkInput( 1 );
}
char szInputs[] = "0123456789rdchkfvp?";
void checkInput( int step ) { // prompt for input without user input with step != 0
char retVal = 0, temp;
char *pTemp;
if ( step != 0 ) {
Serial.printf( "Awaiting input %s loops left %d\n", szInputs, loopLimit );
}
else {
if ( !Serial.available() ) return;
Serial.printf( "Awaiting input %s loops left %d\n", szInputs, loopLimit );
while ( Serial.available() ) {
temp = Serial.read( );
if ( (pTemp = strchr(szInputs, temp)) ) {
retVal = pTemp[0];
parseCmd( retVal );
}
}
}
while ( !Serial.available() );
while ( Serial.available() ) {
temp = Serial.read();
if ( (pTemp = strchr(szInputs, temp)) ) {
retVal = pTemp[0];
parseCmd( retVal );
}
}
if ( '?' == retVal ) checkInput( 1 ); // recurse on '?' to allow command show and response
return;
}
void parseCmd( char chIn ) { // pass chIn == '?' for help
switch (chIn ) {
case '?':
Serial.printf( "%s\n", " 0, 1-9 '#' passes continue loop before Pause\n\
'r' Restart Teensy\n\
'd' Directory of LittleFS\n\
'c' Continuous Loop\n\
'h' Hundred loops\n\
'k' Thousand loops\n\
'f' Format then Restart : 'SPI EraseEverything'\n\
'v' Verbose All Dir Prints - TOGGLE\n\
'p' Pause after all Dir prints - TOGGLE\n\
'?' Help list" );
break;
case 'r':
SCB_AIRCR = 0x05FA0004;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
loopLimit = chIn - '0';
break;
case 'c':
loopLimit = -1;
break;
case 'd':
printDirectory();
checkInput( 1 );
break;
case 'h':
loopLimit = 100;
break;
case 'k':
loopLimit = 1000;
break;
case 'f': // format
#ifdef TEST_RAM
parseCmd( 'r' );
#elif defined(TEST_SPI)
FormatSPI();
parseCmd( 'r' );
#else
Serial.println( "TBD format QSPI_DISK" );
#endif
break;
case 'v': // verbose dir
showDir = !showDir;
showDir ? Serial.print(" Verbose on\n") : Serial.print(" Verbose off\n");
break;
case 'p': // pause on dirs
pauseDir = !pauseDir;
pauseDir ? Serial.print(" Pause on\n") : Serial.print(" Pause off\n");
break;
default:
Serial.println( chIn ); // never see without unhandled char in szInputs[]
break;
}
}
#include <SerialFlash.h>
#include <SPI.h>
SerialFlashFile file;
const unsigned long testIncrement = 4096;
void FormatSPI() {
//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
//uncomment these if you have other SPI chips connected
//to keep them disabled while using only SerialFlash
//pinMode(4, INPUT_PULLUP);
//pinMode(10, INPUT_PULLUP);
Serial.begin(9600);
// wait up to 10 seconds for Arduino Serial Monitor
unsigned long startMillis = millis();
while (!Serial && (millis() - startMillis < 10000)) ;
delay(100);
if (!SerialFlash.begin(FlashChipSelect)) {
while (1) {
Serial.println("Unable to access SPI Flash chip");
delay(1000);
}
}
unsigned char id[5];
SerialFlash.readID(id);
unsigned long size = SerialFlash.capacity(id);
if (size > 0) {
Serial.print("Flash Memory has ");
Serial.print(size);
Serial.println(" bytes.");
Serial.println("Erasing ALL Flash Memory: ");
// Estimate the (lengthy) wait time.
Serial.print(" estimated wait: ");
int seconds = (float)size / eraseBytesPerSecond(id) + 0.5;
Serial.print(seconds);
Serial.println(" seconds.");
Serial.println(" Yes, full chip erase is SLOW!");
SerialFlash.eraseAll();
unsigned long dotMillis = millis();
unsigned char dotcount = 0;
while (SerialFlash.ready() == false) {
if (millis() - dotMillis > 1000) {
dotMillis = dotMillis + 1000;
Serial.print(".");
dotcount = dotcount + 1;
if (dotcount >= 60) {
Serial.println();
dotcount = 0;
}
}
}
if (dotcount > 0) Serial.println();
Serial.println("Erase completed");
unsigned long elapsed = millis() - startMillis;
Serial.print(" actual wait: ");
Serial.print(elapsed / 1000ul);
Serial.println(" seconds.");
}
}
float eraseBytesPerSecond(const unsigned char *id) {
if (id[0] == 0x20) return 152000.0; // Micron
if (id[0] == 0x01) return 500000.0; // Spansion
if (id[0] == 0xEF) return 419430.0; // Winbond
if (id[0] == 0xC2) return 279620.0; // Macronix
return 320000.0; // guess?
}
void printDirectory() {
Serial.printf("printDirectory %s\n--------------", szDiskMem);
printDirectory(myfs.open("/"), 0);
Serial.println();
}
void printDirectory(File dir, int numTabs) {
//dir.whoami();
while (true) {
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");
delayMicroseconds( 8 );
} 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;
uint32_t fileCycle(const char *dir) {
static char szFile[] = "_file.txt";
char szPath[150];
digitalToggleFast(13);
int ii;
lCnt++;
byte nNum = lCnt % MAXNUM;
char chNow = 'A' + lCnt % MAXNUM;
lfs_ssize_t res = 1;
if ( dir[1] == 0 ) // catch root
sprintf( szPath, "/%c%s", chNow, szFile );
else
sprintf( szPath, "%s/%c%s", dir, chNow, szFile );
Serial.printf( ":: %s ", szPath );
if ( cCnt >= 3 && myfs.exists(szPath) ) { // DELETE ALL KNOWN FILES
if ( nNum == 1 ) {
Serial.print( " == == == DELETE PASS START == == == = \n");
printDirectory();
Serial.print( " == == == DELETE PASS START == == == = \n");
delay(DELDELAY);
}
file3 = myfs.open(szPath);
ii = 0;
char mm;
while ( file3.available() ) {
file3.read( &mm , 1 );
if ( chNow != mm ) {
Serial.printf( "Bad Byte! %c! = %c\n", chNow, mm );
while (1);
}
}
file3.close();
myfs.remove(szPath);
Serial.printf("printDirectory %s ----DEL------ -", szDiskMem);
Serial.printf(" -- %c\n", chNow);
if ( showDir ) {
Serial.print("\n");
printDirectory(myfs.open(dir), 1);
}
if ( pauseDir ) checkInput( 1 );
Serial.println();
}
else {
if ( nNum == 0 ) {
nNum = 10;
cCnt++;
if ( cCnt >= 5 ) cCnt = 0;
}
file3 = myfs.open(szPath, FILE_WRITE);
delay(ADDDELAY);
char mm = chNow;
for ( ii = 0; ii < (nNum * SUBADD + BIGADD ) && res > 0; ii++ ) {
res = file3.write( &mm , 1 );
// if ( lCnt%1000 == 500 ) mm='x'; // GENERATE ERROR to detect on DELETE read verify
}
file3.close();
Serial.printf("printDirectory %s --Add----", szDiskMem);
Serial.printf(" ++ %c ", chNow);
if ( showDir ) {
Serial.print("\n");
printDirectory(myfs.open(dir), 1);
}
if ( pauseDir ) checkInput( 1 );
if (res < 0) Serial.printf( "write fail %i", res );
Serial.print("\n");
delay(ADDDELAY);
}
return cCnt;
}