Need Help to Read and Write on SD Card - UNO

Hi, this is my first post in the forum, so if you need me to change something please let me know :slight_smile:

I am working with an Arduino UNO in Proteus. I want to record and playback (in a CSV file) the movement of two servos that I am controlling with a Joystick.

To select the SD file that I want to either Read or Write I use a few Pushbuttons and a LCD Display with an I2C Backpack.

But I am having problem with my Arduino Code, I cannot open any file of the SD Card to either Read or Write the servo data.

I discarded that the problem comes from Proteus since I was able to Read and Write in this other simulation.

And here is the code that worked:
(It is basically the Read and Write example from the library, but extended to create multiple files).

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

const int chipSelect = 4;

// Create the String that names each file with a unique name

String filename;

// Create multiple File Objects and put them in an array (Arduino Uno runs out of memory)

File myFile, myFile2, myFile3,myFile4, //Define files to open.
myFile5,myFile6,myFile7,myFile8,myFile9,
myFile10,myFile11,myFile12;

File myFiles[12] = {myFile, myFile2, myFile3,myFile4, //Create an array of files to open.
myFile5,myFile6,myFile7,myFile8,myFile9,
myFile10,myFile11,myFile12};  


void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  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);
  }
  Serial.println("card initialized.");



  //***** READ AND WRITE PROGRAM ****************
  for( int i = 0; i < 12; i ++){
   filename = "";
   filename = "File" + String(i) + ".txt";    
   myFiles[i] = SD.open(filename , FILE_WRITE);
   // if the file opened okay, write to it:
   if (myFiles[i]) {
     Serial.print("Writing to " + filename +"...");
     myFiles[i].println("testing 1,2,3...");
     // close the file:
     myFiles[i].close();
     Serial.println("done.");
   } 
   else {
     // if the file didn't open, print an error:
     Serial.println("error opening " + filename);
   }

   // re-open the file for reading:
   myFiles[i] = SD.open(filename);
   if (myFiles[i]) {
     Serial.println(filename + ": ");

     // read from the file until there's nothing else in it:
     while (myFiles[i].available()) {
       Serial.write(myFiles[i].read());
     }
     // close the file:
     myFiles[i].close();
   } 
   else {
     // if the file didn't open, print an error:
     Serial.println("error opening " + filename);
   }
         
  } //End for.
  
}

void loop() {
  // nothing happens after setup
}

And here are the results from the simulation:
(I was able to Read and Write in 12 files)

But when I try it in my project with the servos I cannot even open the SD files...
Since I am new I cannot upload my Arduino Code yet. But please take a look at the sections of my code that are supposed to open the SD file.

The code looks like this in my not working project:
First, let me show you the function I am using for Reading my CSV files:
(I cannot open the file, so anything below that line I have not tested)

/* ----------------------FUNCTION 2------------------------------*/
// PLAY AUTOMATIC SERVO CONTROL FROM SD FILE (just one row)
void playloopCode() {
  Serial.println ("Playing...");                       //SERIAL PRINT
  fileFlag=false;



  //****** READ SD FILE PROGRAM ************//

  // String to hold one line of text
  char servoData[8]; // it will hold:  VRX_angle,VRY_angle 
 
  char* servo1; // it will hold VRX
  char* servo2; // it will hold VRY
  
  // Create File Name Char Array
  char filename[10];
  int i = menu-1; 
  char buf [sizeof(uint8_t)*8+1];
  itoa (i,buf,10);
  strcpy (filename,"File");
  strcat (filename,buf);
  strcat (filename,".txt ");
  Serial.println(filename);                              //SERIAL PRINT

  // Test if there file exists
  if (!SD.exists(filename)){
    Serial.println("File DOES NOT Exist");               //SERIAL PRINT
    fileFlag=true;
    return;
  }
  else{
    Serial.println("File Exists");                       //SERIAL PRINT
    fileFlag=false;
  }

  // Open File with filename
  myFiles[i] = SD.open(filename);                       //-----------------------SD OPEN FILE (NOT WORKING) ---------------------------------//
  
  // If the file is available, read it
  if (myFiles[i]) {
    while (myFiles[i].available()) {
      // Get one char from .txt
      char letter = myFiles[i].read();
      // Write one line to buffer
      while (letter!='\n'){
        strcat (servoData,letter);        
      }
      
      // ************ PARSE CSV PROGRAM ****************//
      
    servo1=strtok(servoData, ",");
    //Serial.println(servo1);
    servo2=strtok(NULL, "\n");
    //Serial.println(servo2);       
  
    VRX_angle = atoi(servo1); 
    VRY_angle = atoi(servo2); 
    Serial.println(VRX_angle); 
    Serial.println(VRY_angle); 

    // ************** SERVO PROGRAM ***************************//
    
    servoAngleLeft = VRY_angle+(SW_flag)*VRX_angle;
    servoAngleRight = VRY_angle-(SW_flag)*VRX_angle;
  
    // MAX LEFT SERVO LIMIT
    if (servoAngleLeft>180) {
    servoAngleLeft =180;
    }
    if (servoAngleLeft<0) {
    servoAngleLeft =0;
    }  
    // MAX RIGHT SERVO LIMIT
    if (servoAngleRight>180) {
    servoAngleRight =180;
    }
    if (servoAngleRight<0) {
    servoAngleRight =0;
    }
    
    myservoLeft.write(servoAngleLeft);
    myservoRight.write(servoAngleRight);
    delay(15);
   
      
    }
    // close the file:
   myFile.close();
  } 
  else {                                                        //-----------------------ERROR OPENING SD FILE ---------------------------------//
   // if the file didn't open, print an error:
   lcd.setCursor(0, 1);                                         //LCD PRINT
   lcd.print(F("Open File Error!"));
   Serial.print("error opening ");                              //SERIAL PRINT
   Serial.println(filename);
   delay(100);                                                  //DELAY 0.1 SEC
  }
  
}// END of playloopCode();

And here is the code for writting in the SD Card:
(same problem, I cannot open the file)

/* ----------------------FUNCTION 3------------------------------*/
// RECORD JOYSTICK IN SD CARD (one row at a time) - NOTE: SERVOS ALSO MOVE!
void recordCode() {
  Serial.println ("Recording...");                              //SERIAL PRINT

  //****** JOYSTICK PROGRAM ************//
 
  // JOYSTICK VALUES
  VRX_angle = map(analogRead(A0), 0, 1023, -60, 60);
  VRY_angle = map(analogRead(A1), 0, 1023, 0, 180);

  SW_value = digitalRead(SWPin);  // read Button state [0,1]
  if (!SW_value){
    SW_flag*=-1;
    delay(100);
    while (!digitalRead(SWPin));
  }

  // ************** SERVO PROGRAM ***************************//
  
  servoAngleLeft = VRY_angle+(SW_flag)*VRX_angle;
  servoAngleRight = VRY_angle-(SW_flag)*VRX_angle;

  // MAX LEFT SERVO LIMIT
  if (servoAngleLeft>180) {
  servoAngleLeft =180;
  }
  if (servoAngleLeft<0) {
  servoAngleLeft =0;
  }  
  // MAX RIGHT SERVO LIMIT
  if (servoAngleRight>180) {
  servoAngleRight =180;
  }
  if (servoAngleRight<0) {
  servoAngleRight =0;
  }
  
  myservoLeft.write(servoAngleLeft);
  myservoRight.write(servoAngleRight);
  delay(15);

  //****** WRITE IN SD FILE PROGRAM ************//
  
  // Create File Name Char Array
  char filename[10];
  int i = menu-1; 
  char buf [sizeof(uint8_t)*8+1];
  itoa (i,buf,10);
  strcpy (filename,"File");
  strcat (filename,buf);
  strcat (filename,".txt ");
  Serial.println(filename);                            //SERIAL PRINT  
  
  //Delete File before creating a new one
  if (SD.exists(filename)){
    SD.remove(filename);
    delay(100);
  }

  //Creating a New File
  myFiles[i] = SD.open(filename , FILE_WRITE);          //-----------------------SD OPEN FILE (NOT WORKING) ---------------------------------//
  
  // if the file opened okay, write to it:
  if (myFiles[i]) {
    Serial.println("Writing to file...");               //SERIAL PRINT
    // ******* WRITE JOYSTICK DATA (only one row)*******
    myFiles[i].print(VRX_angle);
    myFiles[i].print(",");
    myFiles[i].println(VRY_angle);
        
    // close the file:
    myFiles[i].close();
    Serial.println("done.");                            //SERIAL PRINT
  } 
  else {                                                //-----------------------ERROR OPENING SD FILE ---------------------------------//
    // if the file didn't open, print an error:
    lcd.setCursor(0, 1);                                //LCD PRINT
    lcd.print(F("Open File Error!"));
    Serial.print("error opening ");                     //SERIAL PRINT
    Serial.println(filename);
    delay(100);                                        //DELAY 0.1 SEC
  }
}//END of recordCode();

I have no idea why it works in the Example and not in my Project. So I would appreciate any ideas and comments. All I have as a beginner is the Read and Write Example and the DataLogger Example. Also, I used this tutorial: https://dronebotworkshop.com/sd-card-arduino/

The Version of my Libraries are:
Wire -1.0
LiquidCrystal_I2C-master 1.1.4
SPI - 1.0
SD - 1.2.3
Servo - 1.1.5

And the storage is:
57% of program storage
72% of dynamic memory

Any help or comment is appreciated, thanks :slight_smile:

Okey... so I've been working a little bit more and I found out that if I write a "constant or fixed" name in SD.open(), the code works. I can write a .txt file in my SD card. (I still have to debug the reading part, but at least it opens the file)

So I think the problem comes from the way I am naming my files.
Here is the code:
(this is for writing in the SD card)

// Create File Name Char Array
  char filename[10];
  int i = menu-1; 
  char buf [sizeof(uint8_t)*8+1];
  itoa (i,buf,10);
  strcpy (filename,"File");
  strcat (filename,buf);
  strcat (filename,".txt ");
  Serial.println(filename);                            //SERIAL PRINT  
// /*  
  //Delete File before creating a new one
  if (SD.exists(filename)){
    SD.remove(filename);
    Serial.println("Deleting Existing File...");
    delay(1000);
  }
// */
  Serial.println("Opening File...");
  delay(1000); //only for testing
  //Creating a New File
  //myFiles[i] = SD.open(filename , FILE_WRITE);  //  <---- it doesn't work here...
  myFiles[i] = SD.open("test.txt" , FILE_WRITE); //  <---- it works here !!!

Why is this happening? Can't I use a Char array to name my files?

"File" is 4 chars ".txt" is 4 chars. one char for terminating 0 and one char is left for the number. but I see you have File10.txt

Nevermind... the problem was a "space" I did not see here:
(now Read and Write works)

  // Create File Name Char Array
  char filename[10];
  int i = menu-1; 
  char buf [sizeof(uint8_t)*8+1];
  itoa (i,buf,10);
  strcpy (filename,"File");
  strcat (filename,buf);
  strcat (filename,".txt"); //<--------- I had a space at the end of .txt
  Serial.println(filename);

Well, now I just have to debug the Playing Mode. This is the new one:
(It is only reading the first line of the .txt file, and it should read all of them)

/* ----------------------FUNCTION 2------------------------------*/
// PLAY AUTOMATIC SERVO CONTROL FROM SD FILE (just one row)
void playloopCode() {
  Serial.println ("Playing...");                       //SERIAL PRINT
  fileFlag=false;



  //****** READ SD FILE PROGRAM ************//

  // String to hold one line of text
  char servoData[8]; // it will hold:  VRX_angle,VRY_angle[NULL] 
 
  char* servo1; // it will hold VRX
  char* servo2; // it will hold VRY
  
  // Create File Name Char Array
  char filename[10];
  int i = menu-1; 
  char buf [sizeof(uint8_t)*8+1];
  itoa (i,buf,10);
  strcpy (filename,"File");
  strcat (filename,buf);
  strcat (filename,".txt");
  Serial.println(filename);                              //SERIAL PRINT

  // Test if there file exists
  if (!SD.exists(filename)){
  //if (!SD.exists("test.txt")){ // ----------------------------------------------------test---------------
    Serial.println("File DOES NOT Exist");               //SERIAL PRINT
    fileFlag=true;
    return;
  }
  else{
    Serial.println("File Exists");                       //SERIAL PRINT
    fileFlag=false;
  }

  // Open File with filename
  myFiles[i] = SD.open(filename);                       //-----------------------SD OPEN FILE (READING) ---------------------------------//
    //myFiles[i] = SD.open("test.txt");// ----------------------------------------------------test---------------

  bool newLine=false;
  // If the file is available, read it
  if (myFiles[i]) {
  //char lineOne[80]; // Assumes that a line contains no more than 79 characters
  byte index = 0;
  
  while(myFiles[i].available() > 0)
  {
     char nextChar = myFiles[i].read();
     if(nextChar != '\n')
     {
        servoData[index++] = nextChar;
        servoData[index] = '\0'; // Keep array NULL terminated
     }
     else
     {
         //Serial.print("servoData: ");
         //Serial.println(servoData);
         break;
     }
  }
     //Serial.println("I made it out of the loop!!!!!!!!!!!");
     //delay(1000);
  
      
      // ************ PARSE CSV PROGRAM ****************//
      
    servo1=strtok(servoData, ",");
    //Serial.println(servo1);
    servo2=strtok(NULL, "\n");
    //Serial.println(servo2);       
  
    VRX_angle = atoi(servo1); 
    VRY_angle = atoi(servo2); 
    Serial.print("VRX: ");
    Serial.println(VRX_angle);
    Serial.print("VRY: "); 
    Serial.println(VRY_angle); 

    // ************** SERVO PROGRAM ***************************//
    
    servoAngleLeft = VRY_angle+(SW_flag)*VRX_angle;
    servoAngleRight = VRY_angle-(SW_flag)*VRX_angle;
    //Serial.print("LeftServo: ");
    //Serial.println(servoAngleLeft);
    //Serial.print("RightServo: "); 
    //Serial.println(servoAngleRight); 
  
    // MAX LEFT SERVO LIMIT
    if (servoAngleLeft>180) {
    servoAngleLeft =180;
    }
    if (servoAngleLeft<0) {
    servoAngleLeft =0;
    }  
    // MAX RIGHT SERVO LIMIT
    if (servoAngleRight>180) {
    servoAngleRight =180;
    }
    if (servoAngleRight<0) {
    servoAngleRight =0;
    }
    
    myservoLeft.write(servoAngleLeft);
    myservoRight.write(servoAngleRight);
    delay(15);
   
    // close the file:
   myFiles[i].close();
  } 
  else {                                                        //-----------------------ERROR OPENING SD FILE ---------------------------------//
   // if the file didn't open, print an error:
   lcd.setCursor(0, 1);                                         //LCD PRINT
   lcd.print(F("Open File Error!"));
   Serial.print("error opening ");                              //SERIAL PRINT
   Serial.println(filename);
   //Serial.println("test.txt"); // ------------------------ -------------------  test
   delay(100);                                                  //DELAY 0.1 SEC
  }
  
}// END of playloopCode();

you still write out of 10 chars reserved for filename

Hi, thank you for replying

Is having 10 chars reserved for filename wrong?

I wrote 10 because "File" has 4.

1 more for the file number (I won't have 2 digit numbers because the Arduino is running out of dynamic memory)

and ".txt" has 4 plus 1 more for the Null char

So the total for my char array is 10, right? Or am I confussing it with string (with small s) ?

on you sreenshot I see File11.txt

Yes, that was the code I used to verify that the problem did not come from Proteus. In that code I used the example ReadWrite from the SD library. That code uses String objects to name the files, but I don't like it because it uses a lot of Dynamic Memory.
See here:

That is why I changed it to char array.
See here: