I'm making some kind of remotely controlled MP3 player for my daughter with NodeMCU (esp8266). I’m using the latest Arduino IDE and default SD library though.
I faced a problem reading files from a folder. It takes more time to open and read every next file. I prepared a short example: I just open file, print its name to serial, close and move on to the next file. There are 200 identical copies of the same file in the folder.
My code:
#include <SPI.h>
#include <SD.h>
void scanSD(String path); //scans SD for MP3
void setup() {
Serial.begin(74880);
SD.begin(SS);
scanSD("/MP3/MUSIC/");
}
void loop() {
delay(1000);
}
void scanSD(String path) {
unsigned long lastmillis = 0;
File myDir; //working folder
File myFile; // current file
myDir = SD.open(path);
if (!myDir) return;
Serial.print("Folder: " + path + "\n");
for (int i=0; i<1000; i++) { //going thru all the files but not over 1000
lastmillis = millis();
ESP.wdtFeed();
myFile = myDir.openNextFile();
if (!myFile) { //stop if no more files
myFile.close();
break;
}
Serial.print(String(myFile.name())+"\t");
myFile.close();
Serial.print(" /"+String(millis() - lastmillis)+"ms\n");
}
Serial.print("Finished\n");
}
As you can see it takes less than 1ms to read the first file but it takes over 20ms to open the same file at the end. When I add function to read ID3 tag from MP3 files (increasing the number of reads) the effect is even more dramatic.
I tried using file object declared outside the scanSD function – it didn’t help.
Any ideas what is the problem and how to fix it would be greatly appreciated
PaulS:
Shouldn't you be closing the directory if there are no more files?
Get the String crap out of your code. There is NOTHING it is doing that needs Strings. Strings are ssslllooowww.
Sure I need to close myDir before leaving the fucntion. I forgot to put it in my expample. But closing myDir will only happen after all files are read and the promlem seems to happen DURING reading files and not after the reading is done.
Yeah, I'm weak-willed and still using strings )
But strings are always the same slow, they are not slowing down in progress... I mean, I've just got rid of strings and the problem is still there.
I tried using file object declared outside the scanSD function - it didn't help.
Any ideas what is the problem and how to fix it would be greatly appreciated
SD.h is a wrapper for a version of SdFat that I wrote over six years ago. openNextFile() is implemented in the wrapper by finding the next file in the directory, getting the file name then doing a standard open. This means scanning the entire directory again from the beginning.
Modern versions of SdFat are much faster.
Here is a test program that can be used for SdFat and SD.h.
#define SD_CS_PIN SS
#define TEST_DIR "testdir"
#include <SPI.h>
// use next line to test SD.h
#include <SD.h>
// use next two lines to test SdFat
//#include "SdFat.h"
//SdFat SD;
File dir;
File file;
char name[25];
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
}
Serial.println("Type any character to start");
while (Serial.read() < 0) {
yield();
}
if (!SD.begin(SD_CS_PIN)) {
Serial.println("SD.begin failed!");
return;
}
if (!SD.exists(TEST_DIR)) {
if (!SD.mkdir(TEST_DIR)) {
Serial.println("mkdir failed");
return;
}
for (int i = 1; i <= 200; i++) {
sprintf(name, "%s/%08d.tst", TEST_DIR, i);
file = SD.open(name, FILE_WRITE);
if (!file) {
Serial.print("create failed: ");
Serial.println(name);
return;
}
}
file.close();
}
dir = SD.open(TEST_DIR);
if (!dir) {
Serial.println("open dir failed");
return;
}
while(1) {
uint32_t ms = millis();
file = dir.openNextFile();
if (!file) {
break;
}
ms = millis() - ms;
#ifdef SD_FAT_VERSION
file.printName();
#else
Serial.print(file.name());
#endif
Serial.print(" /");
Serial.print(ms);
Serial.println("ms");
file.close();
}
dir.close();
Serial.println("done");
}
void loop() {
// nothing happens after setup
}
SdFat does not have file.name() since SdFat supports long file names and this feature would require 256 extra bytes of RAM for each open file.
fat16lib:
Try SdFat-beta It may work on your board.
Oh yeah! It does! And it works really fast and with constant speed.
And even has a long file names support - it a very nice bonus.
Thank you very much, I'm happy now