the code stopped writing to the SD card

hello! first off, a big thank you to the helpful people on this forum as it’s been an invaluable resource over the years.

i’m building a pretty standard datalogger for some solar panels: SD card, RTC, current sensor, voltage divider, temperature sensor, and an LCD screen. i had it all working great on a breadboard and recently moved it all to perfboard.

now the SD card doesn’t write from that project anymore. the strange thing is that other code works. with the exact same hardware i can use the SD library sample code, and it works even when i stripped out everything but the SD code. my project seems to be able to read the card to see if a file exists, but it can’t write.

i’ve looked around and the usual problem here seems to be that people are using 3.3V SD cards with a 5V board, but i’m using a little board with integrated level shifter and regulator (i’ve verified it’s putting out 3.3V) and it still works with other code.

some general notes:

  • i’ve tried it with two different Pro Minis.
  • on the breadboard i was using a hacked-up SD adapter and level shifter board, but now i’m using an integrated module.
  • the proto board has its own 5V regulator, so i’m sure there’s no dropout.
  • i’ve checked for good connections and shorts (and it still works with other code).
  • the RTC and LCD are over I2C, the SD card is on the standard SD pins.
    see attachment solarLogger.ino for the code (i’m certainly no professional, but i am happy to have used derefs and structs - just saying “deref’d struct” gets me tingly). it’s the “if (logFile)” in updateLogFile() that seems to fail.

attachment filetest.ino is the stripped-out code that seems to work.

- emilio

solarLogger.ino (7.8 KB)

filetest.ino (1.53 KB)

First, let me state my objections to using the String data type. It has never failed to disappoint me by eventually crashing my sketches. I use character arrays.

Maybe you are running out of SRAM? I show you have a serial port for debugging, so add this function and call it just before attempting to open the file. The SD open requires 512 bytes available to open a file. Does it show that much remaining?

// add this function to your sketch.
int freeRam() {
  extern int __heap_start,*__brkval;
  int v;
  return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval);  
}

// call it like this.
Serial.print(F("SRAM left: "));
Serial.println(freeRam());

ooh, yeah, i was wondering about memory usage when i rolled out my struct...

SRAM left: 238

yup.

i'd rolled out my "decadent" Strings in hopes there wouldn't be problems, mostly because assembling them is so easy, but i should switch up to save memory.

strange thing is, i thought i'd tested this out with the structs and smoothing function on all sensors before moving to the proto board, but maybe not! thus the case for version control even on personal projects.

besides killing Strings, do you have any other suggestions for saving that precious 2KB?

thanks!
- emilio

That is why the SD.open() call is failing.

The F() macro for all your static strings helps. Reuse arrays for multiple purposes, or declare them in functions where they are used locally to allow for the memory release when the function exits.

wow, before even touching the Strings i went and F'd all my static strings and recovered enough RAM (now 440 bytes free) to get file writing working!

i hadn't used F() before, but now i've noticed it in a bit of sample code i've used. it's surprising, since i would have guessed all static strings would be used from program memory versus getting loaded into dynamic.

i'm still going to convert my Strings as i would like to have the memory to add another sensor or two. i do need to look into how to do char array handling in ways that aren't too cumbersome, since that's why i used Strings in the first place. i also wish there was something 2 byte, signed, and of only 2-3 points of precision to replace my floats

thanks a bunch for that memory troubleshooting!
- emilio