Go Down

Topic: I am stuck...SD card file read/write Ethernet shield (Read 8102 times) previous topic - next topic

FrankenPC

I have the Arduino ethernet shield R3 that supposedly works with the Mega 2560 R3.   I HAVE a Mega 2560 R3.
I've created test code to prove I can read/write to the SD shield.  I can  only read the micro sd card type/capacity (SdVolume),  Any attempts to do a SD.exists, or open a file for writing or reading yield nothing.  No errors, it just doesn't work.
I've made sure my file names are 8.3.  I'm using a 2GB SD card formatted FAT (also tried SDHC 4GB formatted FAT).  I'm at a loss.  For one, I can't understand why SPI is working to read the SD card type/size, but nothing else. 

Also, I'm new to Arduino and admittedly have only a rudimentary idea of what is going on.  It's safe to assume I'm doing something stupid with object assignments, constructors, etc.  Help...

Here's my test harness.  LogInit() works up until it calls LogWriteLog().  That's where the File object begins and fails.

Code: [Select]

#include "SD.h"

const int chipSelect = 4;

Sd2Card card;
SdVolume volume;
SdFile root;

String CurrentFile = "";

File DataFile;

void LogInit()
{

  pinMode(53, OUTPUT);
 
  // see if the card is present and can be initialized:
  //SPI_HALF_SPEED, SPI_QUARTER_SPEED, SPI_FULL_SPEED
  if (!card.init(SPI_HALF_SPEED,chipSelect)) {
    LogDumpLn("SD Card failed");
    // don't do anything more:
delay (1000);
    return;
  }
  LogDumpLn("SD Card Initialized");
  // print the type of card
  LogDump("Card type: ");
  switch(card.type()) {
    case SD_CARD_TYPE_SD1:
      LogDumpLn("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      LogDumpLn("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      LogDumpLn("SDHC");
      break;
    default:
      LogDumpLn("Unknown");
  }

  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(card)) {
    LogDumpLn("SD VOL READ FAIL");
delay (4000);
    return;
  }

  // print the type and size of the first FAT-type volume
  uint32_t volumesize;
  LogDump("Vol type FAT");
  LCDPrint(volume.fatType(), DEC);
  LCDCRLF();
 
  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
  volumesize *= 512;                            // SD card blocks are always 512 bytes
  volumesize /= 1024;
  LogDump("Size (Mbytes): ");
  volumesize /= 1024;
  LogDumpLn(volumesize);

  LogWriteLog("AquaLog.txt",LogTimeStamp());
  //LogReadLog("SensLog.txt");
  delay(4000);
}

String LogTimeStamp()
{
String text = "";
text += "TS:";
text += TimeReadSmall();
return text;
}

void LogWriteLog(String file, String text)
{
LogOpenFile(file);

//DataFile.println(text);
if (DataFile)
{
DataFile.println(text);
LogDumpLn("Log Written");
}
DataFile.close();
//LogFileFlush();
}

void LogReadLog(String file)
{
LogOpenFile(file);
while (DataFile.available()) {
    //LogDumpChar(DataFile.read());
    }
}

void LogOpenFile(String file)
{
if (CurrentFile != file)
{
if (file == "AquaLog.txt") {LogDumpLn("AquaLog.txt opened"); DataFile = SD.open("AquaLog.txt", FILE_WRITE);}
if (file == "ErrorLog.txt") {LogDumpLn("ErrorLog.txt opened"); DataFile = SD.open("ErrorLog.txt", FILE_WRITE);}
if (file == "NetLog.txt") {LogDumpLn("NetLog.txt opened"); DataFile = SD.open("NetLog.txt", FILE_WRITE);}
if (file == "SensLog.txt") {LogDumpLn("SensLog.txt opened"); DataFile = SD.open("SensLog.txt", FILE_WRITE);}

CurrentFile = file;
}
}
void LogFileFlush()
{
DataFile.flush();
LogDumpLn("Flushing data file");
}



//redirect or do nothing.  For debugging.
void LogDump(String text)
{
LCDPrint(text);
}
void LogDump(int val, int format)
{
LCDPrint(val,format);
}
void LogDumpLn(String text)
{
LCDPrint(text);
LCDCRLF();
}
void LogDumpLn(int val)
{
LCDPrint(val);
LCDCRLF();
}




SurferTim

Where is the setup() and loop() functions? You should post all your code. The w5100 and SD must be initialized correctly or they will cause fails in the other device. If you are testing the SD, then disable the w5100 during your test. Use something like this:
Code: [Select]
void setup() {
  Serial.begin(9600);

  // disable w5100 SPI
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);

  // rest of your setup
}


FrankenPC

Setup() and Loop() are in the main ino file.  I'm trying to keep some separation of concerns.  I added your pin 10 output high code to my LogInit() routine and tested it.  Still no go.

Considering the Ethernet port works fine and the SD card volume data is read fine, I'm convinced it's a hardware malfunction on the shield.  So I ordered a 10$ Chinese shield to test.  I'll laugh if the cheap one works where the expensive Arduino shield doesn't.

PaulS

Quote
Considering the Ethernet port works fine and the SD card volume data is read fine, I'm convinced it's a hardware malfunction on the shield.

I'm able to read and write to the SD card while clients connect to the Arduino-as-server. So, unless you've fried the SD reader/write part of the card, it's more likely a software issue.
The art of getting good answers lies in asking good questions.

FrankenPC

That's what I'm saying.  It's fried.  There is no software/hardware permutation I haven't tried at this point.  I'm hoping someone can look at my code and say "Dope!  You forgot {insert x here}" 

OR, maybe shed light on WHY the volume info can be read but files can't be read or written.  How are those two actions fundamentally different?  I would think I'm talking to the micro SD card for both operations using the same pins and protocol.  Another option is my SD libraries are confused.  Can someone upload their SD library sub-directory from a code base that has been SD card tested?

fat16lib

I am the author of SdFat but I do not maintain the Arduino SD library or the version of SdFat used by the Arduino company.

SD.h is a wrapper for a very old version of SdFat and user code should not use the SD object in the same sketch as these objects.
Code: [Select]

Sd2Card card;
SdVolume volume;
SdFile root;


They are also defined in the class for SD:
Code: [Select]

class SDClass {

private:
  // These are required for initialisation and use of sdfatlib
  Sd2Card card;
  SdVolume volume;
  SdFile root;
 
  // my quick&dirty iterator, should be replaced
  SdFile getParentDir(const char *filepath, int *indx);
public:
  // This needs to be called to set up the connection to the SD card
  // before other methods are used.
  boolean begin(uint8_t csPin = SD_CHIP_SELECT_PIN);
 
  // Open the specified file/directory with the supplied mode (e.g. read or
  // write, etc). Returns a File object for interacting with the file.
  // Note that currently only one file can be open at a time.
  File open(const char *filename, uint8_t mode = FILE_READ);

  // Methods to determine if the requested file path exists.
  boolean exists(char *filepath);

  // Create the requested directory heirarchy--if intermediate directories
  // do not exist they will be created.
  boolean mkdir(char *filepath);
 
  // Delete the file.
  boolean remove(char *filepath);
 
  boolean rmdir(char *filepath);

private:

  // This is used to determine the mode used to open a file
  // it's here because it's the easiest place to pass the
  // information through the directory walking function. But
  // it's probably not the best place for it.
  // It shouldn't be set directly--it is set via the parameters to `open`.
  int fileOpenMode;
 
  friend class File;
  friend boolean callback_openPath(SdFile&, char *, boolean, void *);
};


The CardInfo example works because it does not use the SD object.

You must insert this code when you use the Ethernet shield on a Mega.  It must be inserted before the SD.begin call.
Code: [Select]

  // disable w5100 SPI
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);


Try other examples in the SD library, they should work.

Some examples only have the pinMode(10, OUTPUT) call.

Try the ReadWrite example after adding digitalWrite as described above.

FrankenPC

The pin 10,high thing has no relevance.  It works either way.  You DID answer my plea for help though.  I wasn't using SD.begin(chipSelect).  I was using card.init thinking it was sharing the same base objects.  Like you said, they are not the same.  So, you saved me!  Thanks!

fat16lib

Quote
The pin 10,high thing has no relevance.  It works either way.


This is luck.  When you have multiple SPI devices there can be interference when you initialize the libraries.  You should disable devices that have not been initialized before accessing the first device.

I get loads of mail about this issue.  If the Ethernet controller is not disabled, some SD cards may work and some may not.

For reliability disable the Ethernet controller if you initialize the SD first.  It happens to be done on Uno by the SD libraries but not on the Mega.  So do this:
Code: [Select]

  // Disable Ethernet by setting chip select high.
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
  // initialize SD here


If you initialize the Ethernet first do this:
Code: [Select]

  // Disable SD by setting chip select high.
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);
  // initialize Ethernet here


There are dozens of posts in this forum about this issue.

afreisinger

SD.begin(chipSelect) is the key ! I solved the same problem.  what is the difference with card.init() ?

Go Up