SD.mkdir() just create a file, if insert SD card before turn on the board

I used the edited official example (shown below) to test creating a folder and creating files under that folder.

#include <SPI.h>
#include <SD.h>

#define DATA_DIR "SENSOR" // limit 8 characters (8.3 filenmae)
#define RECORD_FILE_EXT ".CSV"

#define SERIAL_PRINTLN(x) (Serial.println(F(x))) // for decrease RAM usage

const int chipSelect = 10; // 4

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    while (1);
  }else {
    Serial.println("card initialized.");
    
    if (SD.mkdir(DATA_DIR))
    {
      SERIAL_PRINTLN("dir is created.");
    }
    else
    {
      SERIAL_PRINTLN("1.dir is exist, or");
      SERIAL_PRINTLN("2. dir name is invalid, or");
      SERIAL_PRINTLN("3. parent is not dir, or");
      SERIAL_PRINTLN("4. parent is already open");
    }
  }
}

void loop() {
  String dataString = String(random(1000));

  char str[32] = "";
  strcat(str, DATA_DIR);
  strcat(str, "/");
  strcat(str, "20191213");
  strcat(str, RECORD_FILE_EXT);

  File dataFile = SD.open(str, FILE_WRITE);

  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  } else {
    SERIAL_PRINTLN("error opening dataFile");
  }
  delay(1000);
}

The problem I encountered was this:

  • If I insert a blank SD card first and let Arduino boot, the folder I want to create will be written as a file.
  • I have to start arduino first, then insert a blank SD card, and then reset Arduino. In this way, folders and files can be created normally.

What causes this problem?

I use Arduino Nano ATmega328P, and SD card has been formatted to FAT32, SD library version is 1.2.4

In setup(), SD.mkdir("SENSOR") will create the dir on root and current path will become that one (SENSOR). If the same dir already exists, it will just become current. Further there is no need to explicitly set path for the filename, otherwise it will actually try to write in "SENSOR/filename.CVS", the full path with filename becomes "/SENSOR/SENSOR/filename.CVS". Certainly '/SENSOR/SENSOR' dir doesn't exists, if lib itself even can parse such long string...

Just use filename instead, since current path is already set:

  char str[32] = "";
  //strcat(str, DATA_DIR);
  //strcat(str, "/");
  strcat(str, "20191213");
  strcat(str, RECORD_FILE_EXT);

When use SD lib, I'm usually doing something as follows:

bool SDExists; 

void setup() {
  SDExists = SD.begin(10);   
  ...
}

void loop() {
  if (SDExists) 
  {
     //do something on SD card
  }
}

Since there is no SD.end() method for the SD lib, card must be inserted before firmware start to execute and must not be ejected until power is turned off.

Ans since many SD card modules do not have pin which can indicate to MCU that SD card is physically inserted or ejected, inside loop() any operation with SD card must fail if it is physically ejected after setup() and non of further actions should be possible with SD card.

I have made altered SD lib with SD.end() method which correctly flush existed data, release instance of the class, thus it will be able to eject and switch SD cards whenever explicitly ordered by firmware itself.

Thanks reply. I finally solve the problem . Just put delay(1000) before SD.begin().

Below is my another testing example .

/*
 * Simple data logger.
 */
#include <SPI.h>
#include "SdFat.h" // https://github.com/adafruit/SdFat

#define DATA_DIR "SENSOR"
#define RECORD_FILE_EXT ".CSV"
#define sd_error(msg) sd.errorHalt(F(msg))

// SD chip select pin.  Be sure to disable any other SPI devices such as Enet.
const uint8_t chipSelect = 10;



//------------------------------------------------------------------------------
// File system object.
SdFat sd;

// Log file.
SdFile file;

//==============================================================================
// Error messages stored in flash.

//------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  delay(1000); // needed delay for SD card creating directory correctly
  
  // Initialize at the highest speed supported by the board that is
  // not over 50 MHz. Try a lower speed if SPI errors occur.
  if (!sd.begin(chipSelect)) {
    sd.initErrorHalt();
  }
  
  if(!sd.exists(DATA_DIR)) {
    if(!sd.mkdir(DATA_DIR)) {
      sd_error("Create DATA_DIR failed");
    }
  }

  if (!sd.chdir(DATA_DIR)) {
    sd_error("chdir failed for DATA_DIR.\n");
  }
}
//------------------------------------------------------------------------------
void loop() {

  char fileName[32] = "";
  strcat(fileName, "20191213");
  strcat(fileName, RECORD_FILE_EXT);
  
  if (!file.open(fileName, FILE_WRITE)) {
    sd_error("file.open");
  }

  String s = String(random(1000));
  file.println(s);
  Serial.println(s);
  

  // Force data to SD and update the directory entry to avoid data loss.
  if (!file.sync() || file.getWriteError()) {
    sd_error("write error");
  }

  file.close();

  delay(1000);
}

"delay(1000); // needed delay for SD card creating directory correctly"

I do not think that require 1000ms delay...

It may be a problem to stabilize voltage on power on, i.e. until capacitors where charged, but that is few ms only. If you have a need for 1000ms, something may be really wrong with SD card or voltage stability.

In some sketches I have seen something like this:

void setup() {
  delay(10); // Voltage stabilization delay
  ....
}

As well this after serial port initialization:

  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }