On Wio Terminal, I am unable to open the root directory on an SD card

Ultimately I want to count the files on an SD card.

I have taken an example from the Arduino SD library and adapted it for the Wio Terminal.

#include <SPI.h>
#include <Seeed_FS.h>
#include "SD/Seeed_SD.h"
#include "TFT_eSPI.h"

void setup() {
  // Try to open USB serial communications
  Serial.begin(115200);

  String build = String(__DATE__) + " " + String(__TIME__);

  //Wait up to 2 seconds for for USB serial port to open
  unsigned long endtime = millis() + 2000;
  while ((millis() < endtime) && !Serial) {}

  bool USBOK = Serial;
  // Flush serial output buffers
  if (USBOK) Serial.flush();

  if (USBOK) {
    Serial.print("\r\n\nSD Test Build: ");
    Serial.println(build);
  }
  delay(1000);

  if (USBOK) Serial.println("Initializing SD card");
  if (!SD.begin(SDCARD_SS_PIN, SDCARD_SPI)) {
    if (USBOK) Serial.println("SD init failed!");
    while (1);
  }
  if (USBOK) Serial.println("SD card OK");

  if (USBOK) {
    File testFile = SD.open("testfile.cfg", FILE_WRITE);                // open new file
    Serial.print("testFile Open Status: ");
    Serial.println(testFile);
    if (!testFile) {
      Serial.println("testfile.cfg could not be opened");
    }
    testFile.write('%');                                         // write a character to the file.
    testFile.close();

// Now try to open the root directory to list the files present (from Arduino sample code)

    File root = SD.open("/");
    Serial.print("root Open Status: ");
    Serial.println(root);
    printDirectory(root, 0);
    Serial.println();

    Serial.println("PRINT AGAIN");
    Serial.println("-----------");
    root.rewindDirectory();  // Return to the first file in the directory
    printDirectory(root, 0);

    Serial.println("Done!");
  }

}

//Start Readings
void loop() { // run over and over//

}

void printDirectory(File dir, int numTabs) {
  while (true) {
    File entry = dir.openNextFile();
    Serial.print("entry Open Status: ");
    Serial.println(entry);
    if (!entry) {
      // No more files
      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);
    }
  }
}

When this is run, the testfile is successfully created but the call to SD.open("/") fails.
The output looks like this:

SD Test Build: Feb 22 2024 13:07:25
Initializing SD card
SD card OK
testFile Open Status: 1
root Open Status: 0
entry Open Status: 0

PRINT AGAIN
-----------
entry Open Status: 0
Done!

How can I open the root directory on the SD card so that I can use the openNextFile() function to count files?

Thanks

1 Like

Hi there,
try this?

root = SD.open("/");

printDirectory(root, 0);

Serial.println("done!");
}

HtH
GL :slight_smile: PJ
from this tutorial…

If you review the code above, you will note that, with the exception of a couple of debug print statements, that is exactly the code I am testing.

Seeed has created their own version of the SD and FS libraries so maybe there is an issue there.

Apparently the SD.open("/") call does not work and consequently neither do the subsequent calls to
root.openNextFile().

Mark

2 Likes

Having the same problem. Did you find a solution ?

Seeed’s other examples programs work (SD_Test and ReadWrite), but not their listfiles example (uses same .open code as yours).

Hi there,
Albeit NOT directly related, I was able to use this test on the Xiao ESP32C3 for read the SD card in the Expansion Base, It does read the DIR’s. Maybe there is something to be gleaned from it FWIW.
HTH
GL :slight_smile: PJ

// adapted from Raui Shanchez
// Xiao Esp32C3 , 32 gig SD , formatted Fat 32 with 32k sector size.
//
//
#include "FS.h"
#include "SD.h"
#include "SPI.h"
#define SS D2


void setup(){
  Serial.begin(9600);
  delay (2000);
  Serial.println(); // only for mbed 2.9.x
  Serial.println("Power ON \n ");  // Let's BEGIN!!
  Serial.println("Test program compiled on " __DATE__ " at " __TIME__);
  Serial.println();
  Serial.println("Processor came out of reset.");
  Serial.println();

 // pinMode(fspi->pinSS(), OUTPUT); //VSPI SS
 // pinMode(hspi->pinSS(), OUTPUT); //HSPI SS

 digitalWrite(SS, HIGH); // <-- Set CS pin HIGH to deselect
  Serial.println("--------------");
  Serial.println(SS);
  Serial.println(MOSI); // master out, slave in
  Serial.println(MISO); // master in, slave out
  Serial.println(SCK);  // clock
  Serial.println("--------------");

  if(!SD.begin(SS)){
    Serial.println("Card Mount Failed");
    return;
  }
  uint8_t cardType = SD.cardType();

  if(cardType == CARD_NONE){
    Serial.println("No SD card attached");
    return;
  }

  Serial.print("SD Card Type: ");
  if(cardType == CARD_MMC){
    Serial.println("MMC");
  } else if(cardType == CARD_SD){
    Serial.println("SDSC");
  } else if(cardType == CARD_SDHC){
    Serial.println("SDHC");
  } else {
    Serial.println("UNKNOWN");
  }

  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);

  listDir(SD, "/", 0);
  createDir(SD, "/mydir");
  listDir(SD, "/", 0);
  removeDir(SD, "/mydir");
  listDir(SD, "/", 2);
  writeFile(SD, "/hello.txt", "Hello ");
  appendFile(SD, "/hello.txt", "World!\n");
  readFile(SD, "/hello.txt");
  deleteFile(SD, "/foo.txt");
  renameFile(SD, "/hello.txt", "/foo.txt");
  readFile(SD, "/foo.txt");
  testFileIO(SD, "/test.txt");
  Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
  Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}

void loop(){
delay (500);
}

//

void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
  Serial.printf("Listing directory: %s\n", dirname);

  File root = fs.open(dirname);
  if(!root){
    Serial.println("Failed to open directory");
    return;
  }
  if(!root.isDirectory()){
    Serial.println("Not a directory");
    return;
  }

  File file = root.openNextFile();
  while(file){
    if(file.isDirectory()){
      Serial.print("  DIR : ");
      Serial.println(file.name());
      if(levels){
        listDir(fs, file.name(), levels -1);
      }
    } else {
      Serial.print("  FILE: ");
      Serial.print(file.name());
      Serial.print("  SIZE: ");
      Serial.println(file.size());
    }
    file = root.openNextFile();
  }
}

void createDir(fs::FS &fs, const char * path){
  Serial.printf("Creating Dir: %s\n", path);
  if(fs.mkdir(path)){
    Serial.println("Dir created");
  } else {
    Serial.println("mkdir failed");
  }
}

void removeDir(fs::FS &fs, const char * path){
  Serial.printf("Removing Dir: %s\n", path);
  if(fs.rmdir(path)){
    Serial.println("Dir removed");
  } else {
    Serial.println("rmdir failed");
  }
}

void readFile(fs::FS &fs, const char * path){
  Serial.printf("Reading file: %s\n", path);

  File file = fs.open(path);
  if(!file){
    Serial.println("Failed to open file for reading");
    return;
  }

  Serial.print("Read from file: ");
  while(file.available()){
    Serial.write(file.read());
  }
  file.close();
}

void writeFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Writing file: %s\n", path);

  File file = fs.open(path, FILE_WRITE);
  if(!file){
    Serial.println("Failed to open file for writing");
    return;
  }
  if(file.print(message)){
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}

void appendFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Appending to file: %s\n", path);

  File file = fs.open(path, FILE_APPEND);
  if(!file){
    Serial.println("Failed to open file for appending");
    return;
  }
  if(file.print(message)){
      Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

void renameFile(fs::FS &fs, const char * path1, const char * path2){
  Serial.printf("Renaming file %s to %s\n", path1, path2);
  if (fs.rename(path1, path2)) {
    Serial.println("File renamed");
  } else {
    Serial.println("Rename failed");
  }
}

void deleteFile(fs::FS &fs, const char * path){
  Serial.printf("Deleting file: %s\n", path);
  if(fs.remove(path)){
    Serial.println("File deleted");
  } else {
    Serial.println("Delete failed");
  }
}

void testFileIO(fs::FS &fs, const char * path){
  File file = fs.open(path);
  static uint8_t buf[512];
  size_t len = 0;
  uint32_t start = millis();
  uint32_t end = start;
  if(file){
    len = file.size();
    size_t flen = len;
    start = millis();
    while(len){
      size_t toRead = len;
      if(toRead > 512){
        toRead = 512;
      }
      file.read(buf, toRead);
      len -= toRead;
    }
    end = millis() - start;
    Serial.printf("%u bytes read for %u ms\n", flen, end);
    file.close();
  } else {
    Serial.println("Failed to open file for reading");
  }


  file = fs.open(path, FILE_WRITE);
  if(!file){
    Serial.println("Failed to open file for writing");
    return;
  }

  size_t i;
  start = millis();
  for(i=0; i<2048; i++){
    file.write(buf, 512);
  }
  end = millis() - start;
  Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
  file.close();
}

1 Like

I have not been able to resolve the problem. My workaround is to move everything that was in the file system root into a directory.

root = SD.open("/MYDIR"); seems to work fine.

Mark

1 Like

Thanks PJ!
As noted, I have a work-around for now but it would be nice to figure it out. I wonder if it has something to do with the Seeed versions of the SD library.
Mark

1 Like

Thanks PJ. Tried it (with library changes to seeed_FS, etc).
Same issue on fs.open("/"). Comes back empty.
But works on any dir created on root as suggested by MarkD, like fs.open("/testdir").
Really looks to me like a library issue.

1 Like

Great tip, Mark. You’re right it actually worked on a directory created in root. But fs.open always returns empty if targeting root.

Since the directory test succesfully returned “0://TestDir”, instead of just “/” for root I also tried “0”, “0:”, “0:/”, “0://”, “root”, “dev0”, etc. No success.

The weird thing is that targeting files on root actually works. Can see, create, delete, etc. But can’t do open or openNextFile on root.

It also contradicts Seeed Studio’s own guidelines where in some FS examples for the WIO Terminal they say to keep files at root level for a more robust experience. That’s why I hadn’t even tried created directories initially.

Anyway, feels like a library implementation issue.

1 Like