next SD read takes more time

Hi!

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");
}

Serial window:

Folder: /MP3/MUSIC/
00000025.MP3	 /1ms
00000027.MP3	 /1ms
00000029.MP3	 /0ms
00000031.MP3	 /0ms
00000033.MP3	 /0ms
00000003.MP3	 /0ms
00000005.MP3	 /0ms
00000007.MP3	 /0ms
00000011.MP3	 /0ms
00000013.MP3	 /1ms
00000015.MP3	 /0ms
00000017.MP3	 /0ms
00000019.MP3	 /0ms
00000021.MP3	 /0ms
00000041.MP3	 /5ms
00000043.MP3	 /4ms
00000045.MP3	 /3ms
00000047.MP3	 /4ms
00000049.MP3	 /3ms
00000145.MP3	 /3ms
00000147.MP3	 /4ms
00000149.MP3	 /3ms
00000151.MP3	 /4ms
00000153.MP3	 /3ms
00000131.MP3	 /3ms
00000133.MP3	 /4ms
00000135.MP3	 /3ms
00000137.MP3	 /4ms
00000139.MP3	 /3ms
00000155.MP3	 /3ms
00000157.MP3	 /6ms
00000159.MP3	 /5ms
00000161.MP3	 /6ms
00000163.MP3	 /5ms
00000165.MP3	 /5ms
00000167.MP3	 /5ms
00000169.MP3	 /5ms
00000171.MP3	 /5ms
00000053.MP3	 /5ms
00000055.MP3	 /6ms
00000057.MP3	 /5ms
00000059.MP3	 /5ms
00000061.MP3	 /5ms
00000035.MP3	 /5ms
00000037.MP3	 /5ms
00000039.MP3	 /6ms
00000051.MP3	 /8ms
00000063.MP3	 /7ms
00000023.MP3	 /7ms
00000065.MP3	 /7ms
00000067.MP3	 /7ms
00000069.MP3	 /7ms
00000071.MP3	 /7ms
00000073.MP3	 /7ms
00000075.MP3	 /6ms
00000077.MP3	 /7ms
00000079.MP3	 /7ms
00000081.MP3	 /7ms
00000083.MP3	 /7ms
00000085.MP3	 /7ms
00000087.MP3	 /7ms
00000089.MP3	 /7ms
00000091.MP3	 /10ms
00000093.MP3	 /9ms
00000095.MP3	 /9ms
00000097.MP3	 /8ms
00000099.MP3	 /9ms
00000101.MP3	 /9ms
00000103.MP3	 /8ms
00000105.MP3	 /9ms
00000107.MP3	 /9ms
00000109.MP3	 /8ms
00000111.MP3	 /9ms
00000113.MP3	 /9ms
00000115.MP3	 /8ms
00000117.MP3	 /9ms
00000119.MP3	 /9ms
00000121.MP3	 /8ms
00000123.MP3	 /13ms
00000125.MP3	 /11ms
00000127.MP3	 /10ms
00000129.MP3	 /11ms
00000173.MP3	 /10ms
00000175.MP3	 /11ms
00000177.MP3	 /10ms
00000179.MP3	 /10ms
00000181.MP3	 /11ms
00000183.MP3	 /10ms
00000185.MP3	 /11ms
00000187.MP3	 /10ms
00000189.MP3	 /11ms
00000191.MP3	 /10ms
00000141.MP3	 /10ms
00000143.MP3	 /10ms
00000193.MP3	 /14ms
00000195.MP3	 /12ms
00000197.MP3	 /12ms
00000199.MP3	 /12ms
00000004.MP3	 /12ms
00000006.MP3	 /12ms
00000008.MP3	 /13ms
00000010.MP3	 /12ms
00000012.MP3	 /12ms
00000014.MP3	 /12ms
00000016.MP3	 /12ms
00000018.MP3	 /12ms
00000020.MP3	 /13ms
00000022.MP3	 /12ms
00000024.MP3	 /12ms
00000026.MP3	 /12ms
00000028.MP3	 /16ms
00000030.MP3	 /14ms
00000032.MP3	 /13ms
00000034.MP3	 /14ms
00000036.MP3	 /14ms
00000038.MP3	 /14ms
00000040.MP3	 /14ms
00000042.MP3	 /14ms
00000044.MP3	 /14ms
00000046.MP3	 /14ms
00000048.MP3	 /14ms
00000050.MP3	 /13ms
00000052.MP3	 /14ms
00000054.MP3	 /14ms
00000056.MP3	 /14ms
00000058.MP3	 /14ms
00000060.MP3	 /17ms
00000062.MP3	 /16ms
00000064.MP3	 /16ms
00000066.MP3	 /15ms
00000068.MP3	 /16ms
00000070.MP3	 /15ms
00000072.MP3	 /16ms
00000074.MP3	 /16ms
00000076.MP3	 /15ms
00000078.MP3	 /16ms
00000080.MP3	 /15ms
00000082.MP3	 /16ms
00000084.MP3	 /16ms
00000086.MP3	 /15ms
00000088.MP3	 /16ms
00000090.MP3	 /16ms
00000092.MP3	 /18ms
00000094.MP3	 /18ms
00000096.MP3	 /17ms
00000098.MP3	 /17ms
00000100.MP3	 /18ms
00000102.MP3	 /17ms
00000104.MP3	 /17ms
00000106.MP3	 /18ms
00000108.MP3	 /17ms
00000110.MP3	 /17ms
00000112.MP3	 /18ms
00000114.MP3	 /17ms
00000116.MP3	 /17ms
00000118.MP3	 /18ms
00000120.MP3	 /17ms
00000122.MP3	 /17ms
00000124.MP3	 /21ms
00000126.MP3	 /19ms
00000128.MP3	 /19ms
00000130.MP3	 /19ms
00000132.MP3	 /19ms
00000134.MP3	 /19ms
00000136.MP3	 /19ms
00000138.MP3	 /19ms
00000140.MP3	 /19ms
00000142.MP3	 /19ms
00000144.MP3	 /19ms
00000146.MP3	 /19ms
00000148.MP3	 /19ms
00000150.MP3	 /19ms
00000152.MP3	 /19ms
00000154.MP3	 /19ms
00000156.MP3	 /22ms
00000158.MP3	 /20ms
00000160.MP3	 /21ms
00000162.MP3	 /21ms
00000164.MP3	 /20ms
00000166.MP3	 /21ms
00000168.MP3	 /21ms
00000170.MP3	 /20ms
00000172.MP3	 /21ms
00000174.MP3	 /21ms
00000176.MP3	 /20ms
00000178.MP3	 /21ms
00000180.MP3	 /21ms
00000182.MP3	 /21ms
00000184.MP3	 /21ms
00000186.MP3	 /21ms
00000188.MP3	 /24ms
00000190.MP3	 /22ms
00000192.MP3	 /23ms
00000194.MP3	 /22ms
00000196.MP3	 /22ms
00000198.MP3	 /23ms
00000200.MP3	 /22ms
00000002.MP3	 /69ms
00000001.MP3	 /64ms
00000009.MP3	 /55ms
Finished

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 :slight_smile:

    myFile = myDir.openNextFile();
    if (!myFile) { //stop if no more files
      myFile.close();
      break;
    }

Shouldn't you be closing the directory if there are no more files?

    Serial.print(String(myFile.name())+"\t");

Get the String crap out of your code. There is NOTHING it is doing that needs Strings. Strings are ssslllooowww.

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.

So maybe you have any thoughts on the matter?

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.

Here is the SD.h result:

Type any character to start
00000001.TST  /2ms
00000002.TST  /0ms
00000003.TST  /1ms
00000004.TST  /1ms
00000005.TST  /0ms
00000006.TST  /1ms
00000007.TST  /1ms
00000008.TST  /0ms
00000009.TST  /1ms
00000010.TST  /1ms
00000011.TST  /1ms
00000012.TST  /1ms
00000013.TST  /1ms
00000014.TST  /1ms
00000015.TST  /7ms
00000016.TST  /5ms
00000017.TST  /6ms
00000018.TST  /5ms
00000019.TST  /5ms
00000020.TST  /7ms
00000021.TST  /5ms
00000022.TST  /7ms
00000023.TST  /6ms
00000024.TST  /6ms
00000025.TST  /6ms
00000026.TST  /7ms
00000027.TST  /6ms
00000028.TST  /7ms
00000029.TST  /6ms
00000030.TST  /6ms
00000031.TST  /10ms
00000032.TST  /9ms
00000033.TST  /9ms
00000034.TST  /9ms
00000035.TST  /8ms
00000036.TST  /10ms
00000037.TST  /8ms
00000038.TST  /9ms
00000039.TST  /9ms
00000040.TST  /8ms
00000041.TST  /9ms
00000042.TST  /9ms
00000043.TST  /8ms
00000044.TST  /9ms
00000045.TST  /9ms
00000046.TST  /9ms
00000047.TST  /13ms
00000048.TST  /11ms
00000049.TST  /12ms
00000050.TST  /12ms

100 lines deleted so I can post message

00000151.TST  /29ms
00000152.TST  /29ms
00000153.TST  /30ms
00000154.TST  /29ms
00000155.TST  /28ms
00000156.TST  /29ms
00000157.TST  /29ms
00000158.TST  /28ms
00000159.TST  /34ms
00000160.TST  /32ms
00000161.TST  /32ms
00000162.TST  /31ms
00000163.TST  /32ms
00000164.TST  /32ms
00000165.TST  /32ms
00000166.TST  /31ms
00000167.TST  /32ms
00000168.TST  /32ms
00000169.TST  /32ms
00000170.TST  /33ms
00000171.TST  /31ms
00000172.TST  /32ms
00000173.TST  /32ms
00000174.TST  /33ms
00000175.TST  /36ms
00000176.TST  /35ms
00000177.TST  /35ms
00000178.TST  /34ms
00000179.TST  /35ms
00000180.TST  /35ms
00000181.TST  /34ms
00000182.TST  /35ms
00000183.TST  /35ms
00000184.TST  /35ms
00000185.TST  /35ms
00000186.TST  /34ms
00000187.TST  /35ms
00000188.TST  /36ms
00000189.TST  /35ms
00000190.TST  /35ms
00000191.TST  /40ms
00000192.TST  /38ms
00000193.TST  /38ms
00000194.TST  /37ms
00000195.TST  /38ms
00000196.TST  /38ms
00000197.TST  /38ms
00000198.TST  /38ms
00000199.TST  /38ms
00000200.TST  /38ms
done

The SdFat result:

Type any character to start
00000001.tst  /1ms
00000002.tst  /1ms
00000003.tst  /0ms
00000004.tst  /0ms
00000005.tst  /1ms
00000006.tst  /0ms
00000007.tst  /0ms
00000008.tst  /0ms
00000009.tst  /0ms
00000010.tst  /0ms
00000011.tst  /0ms
00000012.tst  /0ms
00000013.tst  /0ms
00000014.tst  /0ms
00000015.tst  /1ms
00000016.tst  /0ms
00000017.tst  /0ms
00000018.tst  /0ms
00000019.tst  /0ms
00000020.tst  /0ms
00000021.tst  /1ms
00000022.tst  /0ms
00000023.tst  /0ms
00000024.tst  /0ms
00000025.tst  /0ms
00000026.tst  /0ms
00000027.tst  /0ms
00000028.tst  /0ms
00000029.tst  /0ms
00000030.tst  /0ms
00000031.tst  /1ms
00000032.tst  /0ms
00000033.tst  /0ms
00000034.tst  /0ms
00000035.tst  /0ms
00000036.tst  /0ms
00000037.tst  /1ms
00000038.tst  /0ms
00000039.tst  /0ms
00000040.tst  /0ms
00000041.tst  /0ms
00000042.tst  /0ms
00000043.tst  /0ms
00000044.tst  /0ms
00000045.tst  /0ms
00000046.tst  /0ms
00000047.tst  /1ms
00000048.tst  /0ms
00000049.tst  /0ms
00000050.tst  /0ms

100 lines deleted so I can post message

00000151.tst  /0ms
00000152.tst  /0ms
00000153.tst  /0ms
00000154.tst  /0ms
00000155.tst  /0ms
00000156.tst  /0ms
00000157.tst  /0ms
00000158.tst  /0ms
00000159.tst  /1ms
00000160.tst  /0ms
00000161.tst  /0ms
00000162.tst  /0ms
00000163.tst  /0ms
00000164.tst  /0ms
00000165.tst  /1ms
00000166.tst  /0ms
00000167.tst  /0ms
00000168.tst  /0ms
00000169.tst  /0ms
00000170.tst  /0ms
00000171.tst  /0ms
00000172.tst  /0ms
00000173.tst  /0ms
00000174.tst  /0ms
00000175.tst  /1ms
00000176.tst  /0ms
00000177.tst  /0ms
00000178.tst  /0ms
00000179.tst  /0ms
00000180.tst  /0ms
00000181.tst  /1ms
00000182.tst  /0ms
00000183.tst  /0ms
00000184.tst  /0ms
00000185.tst  /0ms
00000186.tst  /0ms
00000187.tst  /0ms
00000188.tst  /0ms
00000189.tst  /0ms
00000190.tst  /0ms
00000191.tst  /1ms
00000192.tst  /0ms
00000193.tst  /0ms
00000194.tst  /0ms
00000195.tst  /0ms
00000196.tst  /0ms
00000197.tst  /1ms
00000198.tst  /0ms
00000199.tst  /0ms
00000200.tst  /0ms

Try SdFat-beta It may work on your board.

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 :slight_smile: