Problem with Ethernet reads then an SDFat file operation

Combining the power of the ATmega2560 MCU with onboard Ethernet, a microSD card slot, an efficient switchmode power supply, and a small prototyping area. [Product page]
Post Reply
advsoftware
Posts: 2
Joined: Mon Jul 15, 2013 1:33 am

Problem with Ethernet reads then an SDFat file operation

Post by advsoftware » Mon Jul 15, 2013 1:37 am

Hi,

I need to know if this is a bug or a hardware related issue.

I am programming a sketch for the Mega (onbaord SD and ethernet) and have an issue after I call the ethernet client.read function more than once and then do an SDFat file operation.

It appears that if you call the ethernet client.read() more than once the SD card is not longer available.

Not matter what file operation I do I get :

Can't access SD card. Do not reformat.
No card, wrong chip select pin, or SPI problem?
SD errorCode: 0X1,0XFF

Error will occur after you connect with telnet to 10.1.1.25 and type READ

Code below reproduces the problem and I have included the output from the sketch below the code.

The loop will call the ReadWriteTCPIP function that will read the incoming ethernet characters and store them in a global string. When the string contains the letters "READ" the SD file operation will occur. It fails on the if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();. But it can be any file operation.

#include <String.h>
#include <SPI.h>
#include <Ethernet.h>
#include <SdFat.h>


//// set up variables using the SD utility library functions:
Sd2Card card;
SdFat sd;
SdVolume volume;
SdBaseFile root;
SdFile currfile;

// change this to match your SD shield or module;
const int chipSelect = 53;

byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEF};
int TcpipPort = 23;//2189;
EthernetServer server1(TcpipPort);
byte TcpipAddress[] = {
10,1,1,10};
// 192,168,253,3};
byte ServerIPAddress[] = {
10,1,1,25};
// 192,168,253,50};
byte GatewayIPAddress[] = {
10,1,1,1};
// 192,168,253,1};
EthernetClient client1;

String inbuffer(512);
String TCPinput = "";
boolean bTCPClient;

void setup() {
//Debug to serial monitor
Serial.begin(115200);

// Setup SD Card
SDCardSetup();

//InitializeTCPIP
InitializeTCPIP();

}

void loop() {

ReadWriteTCPIP();
}

//
void InitializeTCPIP()
{
// Setup IP address of the server you're connecting to:
bTCPClient = false;
Serial.println("Configuring TcpipAddress");
IPAddress remoteserver(TcpipAddress);
Serial.println("Configuring ServerIPAddress");
Ethernet.begin(mac, ServerIPAddress);
Serial.println("Starting TCPIP Server");
server1.begin();
Serial.println("...Started");
Serial.println("Now Telnet 10.1.1.25 and type in capitals READ");
}

// SD Card Setup
void SDCardSetup()
{
pinMode(53, OUTPUT); // change this to 53 on a mega

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
//if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();

// we'll use the initialization code from the utility libraries
// since we're just testing if the card is working!
if (!card.init(SPI_HALF_SPEED, chipSelect)) {
Serial.println("initialization failed. Things to check:");
Serial.println("* is a card is inserted?");
Serial.println("* Is your wiring correct?");
Serial.println("* did you change the chipSelect pin to match your shield or module?");
return;
}
else {
Serial.println("Wiring is correct and a card is present.");
}

// print the type of card
Serial.print("\nCard type: ");
switch(card.type()) {
case SD_CARD_TYPE_SD1:
Serial.println("SD1");
break;
case SD_CARD_TYPE_SD2:
Serial.println("SD2");
break;
case SD_CARD_TYPE_SDHC:
Serial.println("SDHC");
break;
default:
Serial.println("Unknown");
break;
}

// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
if (!volume.init(&card)) {
Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
return;
}

// print the type and size of the first FAT-type volume
uint32_t volumesize;
Serial.print("\nVolume type is FAT");
Serial.println(volume.fatType(), DEC);
Serial.println();

volumesize = volume.blocksPerCluster(); // clusters are collections of blocks
volumesize *= volume.clusterCount(); // we'll have a lot of clusters
if (volumesize < 0X800000) {
volumesize *= 512; // SD card blocks are always 512 bytes
Serial.print("Volume size (bytes): ");
Serial.println(volumesize);
volumesize /= 1024;
}
else {
volumesize /= 2;
}
Serial.print("Volume size (Kbytes): ");
Serial.println(volumesize);
Serial.print("Volume size (Mbytes): ");
volumesize /= 1024;
Serial.println(volumesize);

root.openRoot(&volume);

// list all files in the card with date and size
Serial.println("\nFiles found on the card (name, date and size in bytes): ");
root.ls(LS_R | LS_DATE | LS_SIZE);
}

void ReadWriteTCPIP()
{
// Serial.println("ReadWriteTCPIP");
SdFile currfile;
String tagdata = "";

// listen for incoming clients
client1 = server1.available();

if (client1)
{
// If client is connected.
if(client1.connected())
{
Serial.println("Client Connected");
int Count = 0;
int x = 0;
if (client1.available())
{
Serial.println("Receiving for incoming data (1st Time SD Works");
Serial.println("Second time through here reading a char the next SD operation will fail.");
char c = client1.read();
TCPinput.concat(c);

Serial.println(TCPinput);
if (TCPinput.indexOf("READ") >= 0) //")
{
Serial.println("Do File Operation that will fail");
//Find Oldest SDRam Queue File
// open next file in root. The volume working directory, vwd, is root
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();


if (currfile.openNext(sd.vwd(), O_READ ))
{
Serial.println("Sending File");
tagdata = "";
if ((currfile.isOpen() != true) && (currfile.isFile()==true) ) //&& (TCPinput.indexOf("READ POLL") >= 0)
{
//while (currfile.available()) AND (input != "")
while (((tagdata += currfile.read())>=0) && (TCPinput != ""));

tagdata.concat("<OK>");

client1.println(tagdata);
Serial.println("Sent OK");
//Serial.println("Removing File");
//currfile.remove();
currfile.close();
Serial.println("Closed File");
}
else
{
Serial.println("Close File Dir of non file");
currfile.close();
}
}
else// NoFiles so Nothing to send to server
Serial.println("TCPIP Nothing to send");
}
}
}
}
}


Output from the test sketch:

Wiring is correct and a card is present.

Card type: SD2

Volume type is FAT16

Volume size (bytes): 2030960640
Volume size (Kbytes): 1983360
Volume size (Mbytes): 1936

Files found on the card (name, date and size in bytes):
13164620.TXT 2000-01-01 01:00:00 17145
13164826.TXT 2000-01-01 01:00:00 7
13164929.TXT 2000-01-01 01:00:00 7
13171646.TXT 2000-01-01 01:00:00 9
Configuring TcpipAddress
Configuring ServerIPAddress
Starting TCPIP Server
...Started
Now Telnet 10.1.1.25 and type in capitals READ
Client Connected
Receiving for incoming data (1st Time SD Works
Second time through here reading a char the next SD operation will fail.
R
Client Connected
Receiving for incoming data (1st Time SD Works
Second time through here reading a char the next SD operation will fail.
RE
Client Connected
Receiving for incoming data (1st Time SD Works
Second time through here reading a char the next SD operation will fail.
REA
Client Connected
Receiving for incoming data (1st Time SD Works
Second time through here reading a char the next SD operation will fail.
READ
Do File Operation that will fail
Can't access SD card. Do not reformat.
No card, wrong chip select pin, or SPI problem?
SD errorCode: 0X1,0XFF

Thanks in advance.

advsoftware
Posts: 2
Joined: Mon Jul 15, 2013 1:33 am

Re: Problem with Ethernet reads then an SDFat file operation

Post by advsoftware » Mon Jul 15, 2013 1:44 pm

Problem solved.

You need to use the digitalWrite to set pin 4 low on the Mega with the freetronics ethernet when you want to use the SD card and set the ethernet pin 10 high. Then the opposite before using the ethernet. I created a couple of functions to do this and call them where required.

Also very important to set the PIN modes for both to OUTPUT before doing any intialization of the SD or the Ethernet.

I hope this helps someone, and avoids the 3 days of searching spent on this problem.

pinMode(10,OUTPUT); // Ethernet Pin select must be set to OUTPUT
pinMode(4, OUTPUT); // SD Pin select must be set to OUTPUT

void SetTCPIPMode()
{
//set its SS pin (10) Low, and the SD card's SS (4) pin High
digitalWrite(10, LOW); // select ethernet mode
digitalWrite(4, HIGH); // deselect SD mode
}

void SetSDCardMode()
{
//set its SS pin (10) HIGH, and the SD card's SS (4) pin LOW
digitalWrite(4, LOW); // select SD mode
digitalWrite(10, HIGH); // deselect ethernet mode
}

angusgr
Freetronics Staff
Freetronics Staff
Posts: 853
Joined: Tue Apr 09, 2013 11:19 pm
Location: Melbourne, Australia
Contact:

Re: Problem with Ethernet reads then an SDFat file operation

Post by angusgr » Tue Jul 16, 2013 11:41 pm

Hi advsoft,

Glad you got it working.

For what it's worth, it actually shouldn't be necessary to explicitly manage the CS lines on pin 4 and 10 like this, the SdFile and Ethernet libraries you're using should be able to automatically manage them for you.

In your original example, I noticed "chipSelect = 53" near the top. The sets the SD card CS line to pin 53. 53 is the EtherMega SPI "slave select" line, and not actually the line you want to toggle. I think if change this to pin 4 it will help.

SPI is confusing like that, you still need to set 53 to an output (which happens elsewhere in the example), but it's not actually necessary to assign it as a CS line.

Also I noticed that near where you were seeing the error you're calling sd.begin() again. You should only have to do this once in the setup() method, not multiple times. I'm guessing it was added as a debugging step, but you should be able to remove it.

I suspect if you change these two things, your original program should work without any other additions.

Here's a link to an example I just put together to check my own understanding, it's a mashup of the Arduino Ethernet WebServer sketch and the SD DumpFile sketch.

https://gist.github.com/projectgus/6016 ... tfile1-ino

It's a lot simpler than the example you posted because it justs uses the simpler (and less powerful) Arduino SD library not the underlying SdFile library that you're using, however the former is mostly just a thin wrapper around the latter so your more complex usage should work much the same.

Cheers,

Angus

Post Reply