SdFat writes weird stuff to binary on SD

I had a code that ran with standard SD library fine, which would write all binary bytes read on serial to a file on sd. The sketch for the function was:

//SDcounter is the number of bytes stored in buffer
byte SDbuffer[512];//Buffer to be saved on SD
int sdloop=0;
    while (sdloop < SDcounter){
    myFile.write(SDbuffer[sdloop]);
   sdloop++;
    }

Then i upgraded to SdFat and tried with the same function, but it writes the file with the correct size, but the data in it is completely wrong.

And if i try this:

myFile.write(SDbuffer, SDcounter);

it will print a file full of "0x00, 0x33, 0x00, 0x33.......".

Could someone please give a hand to let me know what am i doing wrong?

BR

Could someone please give a hand to let me know what am i doing wrong?

Sorry, no. Perhaps you could take those snippets over to snippets-r-us.com. Here, we need to see all of your code.

original code:

byte SDbuffer[512];//Buffer to be saved on SD
word SDcounter=0;//counter to know how many bytes will be written to the SD
#include <SD.h>
File myFile;
byte c;

void error_P(const char* str) {   
  PgmPrint("error: ");   
  SerialPrintln_P(str);   
  if (card.errorCode()) 
    {     
      PgmPrint("SD error: ");     
      Serial.print(card.errorCode(), HEX);     
      Serial.print(',');     
      Serial.println(card.errorData(), HEX);   
    }   
  while(1); 
} 

void setup()
{
Serial.begin(115200);
Serial2.begin(9600);
pinMode(53, OUTPUT);
  Serial.println("Initializing SD card...");
  if (!SD.begin(4)) 
    {
      Serial.println("initialization failed!");
      Serial.println("Please check that SD card is inserted and formatted as FAT16");
      fail=1;
       while (fail){}
    }
 myFile = SD.open("log.bin", O_CREAT | O_WRITE);//We do it the fast way
Serial.println("starting to log...");
}

void loop()
{

  while (SDcounter<513)
  {
   while (Serial2.available() < 1)
   {}
   c = Serial2.read(); 
   SDbuffer[SDcounter]=c;
  SDcounter++;
  }
  int sdloop=0;
  myFile= SD.open("log.bin", FILE_READ); 
if (!myFile){
    // if the file didn't open, print an error:
    Serial.println("Error writing to SD card, please check it is not write protected");
    return;
  }

    while (sdloop < SDcounter){
    myFile.write(SDbuffer[sdloop]);
   sdloop++;
    }
    SDcounter=0;
myFile.close();
}

new code:

byte SDbuffer[512];//Buffer to be saved on SD
word SDcounter=0;//counter to know how many bytes will be written to the SD
#include <SdFat.h>
#include <SdFatUtil.h>
SdFat SD;
Sd2Card card; 
SdVolume volume; 
SdFile root; 
const uint8_t SD_CHIP_SELECT = 53;
SdFile myFile;
byte SDbufferFlag;
// store error strings in flash to save RAM 
#define error(s) error_P(PSTR(s))

byte c;

void error_P(const char* str) {   
  PgmPrint("error: ");   
  SerialPrintln_P(str);   
  if (card.errorCode()) 
    {     
      PgmPrint("SD error: ");     
      Serial.print(card.errorCode(), HEX);     
      Serial.print(',');     
      Serial.println(card.errorData(), HEX);   
    }   
  while(1); 
} 

void setup()
{
Serial.begin(115200);
Serial2.begin(9600);
  Serial.print("Initializing SD card...");
  //SD card INIT
  if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
  // initialize a FAT volume   
  if (!volume.init(&card)) error("volume.init failed");   
  // open the root directory   
  if (!root.openRoot(&volume)) error("openRoot failed");
  Serial.println("Done!");
}

void loop()
{

  while (SDcounter<513)
  {
   while (Serial2.available() < 1)
   {}
   c = Serial2.read(); 
   SDbuffer[SDcounter]=c;
  SDcounter++;
  }
  int sdloop=0;
  if (!myFile.open(&root,"log.bin", O_RDWR | O_CREAT)) {
    // if the file didn't open, print an error:
    Serial.println("Error writing to SD card, please check it is not write protected");
    return;
  }

    while (sdloop < SDcounter){
    myFile.write(SDbuffer[sdloop]);
   sdloop++;
    }
    SDcounter=0;
myFile.close();
}

BR

One thing I'd like to introduce you to is the for statement. The while statement is meant to loop a variable number of times, until some condition becomes true. The for loop is meant to loop a fixed number of times.

There are places you are using a while loop to iterate a fixed number of times. Those would be more intuitive as for loops.

The two blocks of code do not open the file the same way.

In the first code, you open the file in setup(). Then, without closing the file, you try to open the file again in loop (read-only). Then, you write to the file (that you tried to open read-only).

The whole purpose of doing buffered writes to the file is because writing one byte at a time is slow. Writing an entire array at once is faster. You are defeating the purpose of collecting the data in an array if you then write one element of the array to the file at a time.

It was a hardware fault. I just fixed it, and now both codes posted work perfectly with the fix you mention aswell.

Anyway, i am interested on what you mention in writing a byte at a time.

I would really appreciate if you could let me know the correct syntax to write the entire buffer at a time.

BR

Ok, just changed the loop for a myFile.write(SDbuffer, SDcounter); and it speeded up a 80secs operation to become a 59secs operation.

BIG thanks for your help PaulS! :slight_smile:

BR

Ok, just changed the loop for a myFile.write(SDbuffer, SDcounter); and it speeded up a 80secs operation to become a 59secs operation.

I'm surprised that it still takes almost a minute to write the data to the file. Reading 512 characters from the serial port AND writing them to the file I could see taking that long. I could see shaving 20 seconds off that time writing all 512 characters at once.

How are you measuring the time?

BIG thanks for your help PaulS!

You are quite welcome.

it reads 512kb of data in blocks of 512bytes, but since the buffer is 512bytes, it will just loop until the data stream is done. i believe that 59 seconds is a really really fast operation time, but if you think something could be improved, please let me know.

I measure the time by a inittime=millis() at the beginning, and endtime=(millis()-inittime)/1000) at the end.

The full code for the project is at this point 2347 lines, so i just extracted the SD routines into the sketch that i have posted earlier.

BR

it reads 512kb of data in blocks of 512bytes, but since the buffer is 512bytes, it will just loop until the data stream is done. i believe that 59 seconds is a really really fast operation time, but if you think something could be improved, please let me know.

If that 59 seconds is the time to read all 1000 blocks of 513 bytes, and write them to the SD card, then I agree that is impressive.

I was under the impression that the 59 seconds you were referring to was just the time to write one 512 byte file to the SD card.

yes, i didnt pretty much explain myself here about the time thing, my bad :cold_sweat:

Hey @Bi0H4z4rD can you clarify what your hardware problem was?

I've converted a program from SD to SdFat and the reading of a file is just fine, but always getting errors on the write... Just wondering if it might be related to your issue.

Thanks!