Using the SD card AND the Ethernet on sheild causes issues

Hi,

I have a really weird issue. I am using an uno with the Ethernet shield and the code I have written for the Ethernet and accessing the SD work separately but not together which I have no clue why?

Here is my code and to see what I mean comment out the initialization of the SD card and then the Ethernet and you can see how they do not work together

#include <SD.h>
#include <SPI.h>
#include <Ethernet.h>
#include <Time.h> 
#include <EthernetUdp.h>



const unsigned int LED_PIN = 13;
const unsigned int BAUD_RATE = 9600;
const unsigned int MAX_INPUT = 50;
char F1_FILE[] = "file1.txt";
char F2_FILE[] = "file2.txt";
byte mac[] = {
  0xDE, 0xAA, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,0,178);
EthernetClient client;

//Time sync
EthernetUDP Udp;
unsigned int localPort = 8886;  // local port to listen for UDP packets
const int timeZone = 1;     // Central European Time
IPAddress timeServer(132, 163, 4, 102); // time-a.timefreq.bldrdoc.gov
time_t prevDisplay = 0; // when the digital clock was displayed


void setup()
{
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(BAUD_RATE);

  Serial.println("Initializing...");

  Serial.println("Initializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default. 
  pinMode(10, OUTPUT);
  if (!SD.begin(4)) {
    Serial.println("initialization of SD failed!");
    delay(1000);
    return;
  }
  if(!f1FileCheck())
  {
    delay(1000);
    return;
  }
  if(!f2FileCheck())
  {
    delay(1000);
    return;
  }

  Serial.println(String(F1_FILE) + " exists");
  Serial.println(String(F2_FILE) + " exists");

  Serial.println("Initializing Ethernet...");
  // start the Ethernet connection:
  if(!ethernetInitialization())
  {
    delay(1000);
    return;
  }


  Serial.println("initialization done.");
  Serial.write("Begin terminal\n");
}

void loop()
{
  if(Serial.available() > 0)
  {
    //read incomming commands
    processIncomingByte(Serial.read());
  }
  if (timeStatus() != timeNotSet) {
    if (now() != prevDisplay) { //update the display only if time has changed
      prevDisplay = now();
      digitalClockDisplay();  
    }
  }
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.println(); 
}

void printDigits(int digits){
  // utility for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void processIncomingByte (const byte inByte)
{
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  switch (inByte)
  {

  case '\n':   // end of text
    input_line [input_pos] = 0;
    processData (input_line);
    input_pos = 0;  
    break;

  case '\r':
    break;

  default:
    if (input_pos < (MAX_INPUT - 1))
      input_line [input_pos++] = inByte;
    break;

  }
}

void processData (const char * data)
{
  String inData = data;
  if(inData.length() > 2)
  {

    if(inData.substring(0,2) == "-u") 
    {
      String uu = inData.substring(2,inData.length());
      digitalWrite(LED_PIN,HIGH); 
      Serial.println("uu is "+ uu);
      saveuu(uu);
    }
    if(inData.substring(0,2) == "-i") 
    {
      String ii = inData.substring(2,inData.length());
      digitalWrite(LED_PIN,HIGH); 
      Serial.println("ii is "+ ii);
      saveii(ii);
    }
    else if(inData == "off") 
    {
      digitalWrite(LED_PIN,LOW); 
      Serial.println("LED off");
    }
    else
    {
      Serial.print("Unknown command: ");
      Serial.println(inData);
    }
  }
}



void saveuu (String uu)
{
  Serial.println("Saving uu");
  char uuChar[uu.length()+1];
  uu.toCharArray(uuChar, uu.length()+1);
  Serial.println("char uuChar: " + String(uuChar));
  SD.remove(F1_FILE);
  File f1File = SD.open(F1_FILE, FILE_WRITE);
  f1File.write(uuChar);
  f1File.close();
  Serial.println("Written and close");
}

void saveii (String ii)
{
  Serial.println("Saving ii");
  char iiChar[ii.length()+1];
  ii.toCharArray(iiChar, ii.length()+1);
  Serial.println("char ii: " + String(iiChar));
  SD.remove(F2_FILE);
  File iiFile = SD.open(F2_FILE, FILE_WRITE);
  iiFile.write(iiChar);
  iiFile.close();
  Serial.println("Written and close");
}

boolean f1FileCheck()
{
  if(!SD.exists(F1_FILE))
  {
    Serial.println( String(F1_FILE)+ " does not exist");
    File uuFile = SD.open(F1_FILE, FILE_WRITE);
    uuFile.write("empty");
    uuFile.close();
    if(!SD.exists(F1_FILE))
    {
      Serial.println(String(F1_FILE) + " still does not exist");
      return false;
    }  
    Serial.println(String(F1_FILE) + " now exists");
  }  
  return true;
}
boolean f2FileCheck()
{
  if(!SD.exists(F2_FILE))
  {
    Serial.println( String(F2_FILE)+ " does not exist");
    File iiFile = SD.open(F2_FILE, FILE_WRITE);
    iiFile.write("empty");
    iiFile.close();
    if(!SD.exists(F2_FILE))
    {
      Serial.println(String(F2_FILE) + " still does not exist");
      return false;
    }  
    Serial.println(String(F2_FILE) + " now exists");
  }  
  return true;
}

boolean ethernetInitialization()
{
  delay(1000);  // give the Ethernet shield a second to initialize:
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    return false;
  }
  Serial.print("IP number assigned by DHCP is ");
  Serial.println(Ethernet.localIP());
  Serial.println("Syncing time");
  Udp.begin(localPort);
  Serial.println("waiting for sync");
  setSyncProvider(getNtpTime);

  return true; 
}



/*-------- NTP code ----------*/

const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

time_t getNtpTime()
{
  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  Serial.println("Transmit NTP Request");
  sendNTPpacket(timeServer);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      Serial.println("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  Serial.println("No NTP Response :-(");
  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:                 
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}

Thanks for any help

Your chip selects are not clear. Your comment says Ethernet chip select is 4 but your SD.begin uses 4 and you have this output config:

 pinMode(10, HIGH);

Please identify the SD and Ethernet chip selects.
Is it :
Ethernet=4
SD =10

?
PLEASE define ALL of you I/O using #define along with your other defnitions. We shouldn't have to search through your code to find your I/O definitions.

Pin 10 Has to be open for the SD card to work (SD - Arduino Reference). Hence why it is High and not used again!

I think your pinMode statement is wrong. You need to use

pinMode(10,OUTPUT);

Neither one of the tutorials above use the pinMode statement you are using please explain.

It works with either. I was looking at someone else who had an SD issue and they found that HIGH had the same effect. I have changed the code to be OUTPUT now

If you want to use multiple SPI devices. Disable all before starting any of them.

In setup, use this :
// disable SD SPI
pinMode(4,OUTPUT);
digitlWrite (4,HIGH);

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

// rest of setup code

I placed this code in my setup. It did not make any difference. I dont understand what it should do. Could you explain why this should work

The SPI chip select is ACTIVE LOW, thus this:

// disable SD SPI
pinMode(4,OUTPUT);
digitlWrite (4,HIGH);

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

// rest of setup code

DISABLES these two spi devices so the the individual code for each of them can run without conflict.

This statement doesn't seem to make sense , first because "open" does not denote any logical state. (such as HIGH or LOW)
"open" is most commonly used in electronics to denote "no connection" , hence it has no place in this discussion.

Additionally, the following statement seems to imply the chip select is active HIGH, which it is not.

See attached datasheet for a SPI device (PINOUT)

Pin 10 Has to be open for the SD card to work Hence why it is High and not used again!

and following link for correct active state for SPI chip select (LOW)

MCP4162-102-P.pdf (2.21 MB)

Which Arduino do you have the ethernet shield connected to? If you are using a Mega, this will cause a failure of the SD startup. It sets the w5100 SPI active before you start the SD. Bad news.

 Serial.println("Initializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default. 
  // this next call sets D10 as OUTPUT and LOW.
  pinMode(10, OUTPUT);
  if (!SD.begin(4)) {
    Serial.println("initialization of SD failed!");
    delay(1000);
    return;
  }

If you are using an Uno, it shouldn't matter. The SD.begin() call sets D10 (default SPI slave select) as OUTPUT and HIGH, so the w5100 is disabled by accident.

I am using the Uno with the Ethernet shield.

OK, let's try one device at a time. I'll start with the w5100. Compile and upload this code. What ip does the serial monitor show? It should be 192.168.2.2.

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

byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,2,2);

void setup() {
  Serial.begin(9600);

  // disable SD SPI
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);

  // Start ethernet
  Serial.println(F("Starting ethernet..."));
  Ethernet.begin(mac, ip);
  digitalWrite(10,HIGH);
  Serial.println(Ethernet.localIP());

  delay(2000);
  Serial.println(F("Ready"));
}

void loop() {
}

edit: I mean initialize one at a time. Leave the SD card in the slot for this test.

@SurferTim,

I think I have found the issue I have here: arduino - Ethernet.begin() only works with SD Card removed - why? - Electrical Engineering Stack Exchange

I have tested both sections individually as you have suggested and they do work. I didn't realise that I have to switch between them with the SPI. So to switch between the two what do I set to turn one of them off?

They will both work together. Try this sketch. It disables the SD while it starts the w5100, then starts the SD card. Does this show "Starting ethernet...192.168.2.2" and "Starting SD...ok"?

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

byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,2,2);

void setup() {
  Serial.begin(9600);

  // disable SD SPI
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);

  // Start ethernet
  Serial.print(F("Starting ethernet..."));
  Ethernet.begin(mac, ip);
  digitalWrite(10,HIGH);
  Serial.println(Ethernet.localIP());

  // starting SD
  Serial.print(F("Starting SD..."));
  if(SD.begin(4) == 0) Serial.println(F("failed"));
  else Serial.println(F("ok"));

  delay(2000);

  Serial.println(F("Ready"));
}

void loop() {
}

The only bug I have discovered is the Ethernet.begin() call returns with the w5100 SPI active. That is a bug. It should return with the SPI disabled, as do all other ethernet functions. That is why the "digitalWrite(10,HIGH)" after the Ethernet begin() call. After that, all other functions of both devices work fine. There is no need to manipulate the slave selects after the setup function.

@SurferTim

Sorry I have been away and just got back. I tried this and it worked fine....

With my sketch why do you think I am seeing the issue that I am?

If that test sketch worked fine, then incorporate my setup from that test sketch into your code.

Why for the prints are you using F()?

I have been integrating my previous code with yours and slowly but surely. It is really strange as it all works and then I add in extra bit and it will suddenly stop. I think it could be a space issue as I need a few libs, The SPI, SD, Ethernet and also VirtualWire. This means that my sketch is the upper 20k's (27+) and so I think this could be the reason I am getting wrong outputs and freezing. I removed some text processing stuff I had in there and it works and always the ethernet initializes. I add it in (I know it works as it is from another sketch I use) and it does not work and it is all loop code nothing in setup

I have been integrating my previous code with yours and slowly but surely. It is really strange as it all works and then I add in extra bit and it will suddenly stop.

This is a common problem. Normally it is because your Arduino has run out of SRAM. That is what the F() function helps with. It keeps those static strings in program memory instead of importing them into SRAM before using them. You have 2K of SRAM in an Uno, so you must use it wisely.

Fantastic. Atleast I know what the issue is now. Also I know this is probably stupid but is the Flash memory like the EEPROM and have a certain amount of reads and writes?.

wishywashy:
Fantastic. Atleast I know what the issue is now. Also I know this is probably stupid but is the Flash memory like the EEPROM and have a certain amount of reads and writes?.

Writes? Yes. But this shouldn't be an issue because the only time you are writing to the Flash memory is when you program the chip. A bug in a sketch that writes to the EEPROM might accidentally use up it's lifetime fairly quickly, so that is why the lifetime of the EEPROM (which, incidentally is actually longer than the lifetime of the Flash memory) is stressed so much. A tight loop that writes to memory location 0 of the EEPROM every 1ms will run through the life of that memory cell in less than 2 minutes...

Reads? No, for both EEPROM and Flash memory.