Connect multiple Ethernet Shields to Arduino Uno using SPI

Hi,
I have a project in which I need to connect at least 2 ethernet shields to one arduino uno board. I have read a lot of similar topics, but there was no clear answer to this question.
I know that I need to connect the first eth shield to pin 10, cause it’s by deafult SS pin, and the second one to another not used pin for example to pin 9. Then I need to set pin 9 in the following way:

pinMode(9, OUTPUT);
digitalWrite(9, HIGH);

but what then? How to select shield connected to pin 10, when I want to do some action using it, and how to select pin 9 afterwards?

I already tried modyfyng Ethernet and w5100 libraries, so I could use

Ethernet.select(pin);

as it was said on other topic:

SurferTim:
OK. It works now. The new files are attached. I tried most of the sketches I have and all are running ok.

It should be compatible with older sketches now. If you do not call Ethernet.select(), it uses D10 by default.

Here is the DhcpAddressPrinter sketch from the ethernet library examples modified for D9 as the w5100 slave select. I bent D10 on the shield so it wouldn’t insert into my Mega, then jumpered D10 and D9 on the shield.

/*

DHCP-based IP printer

This sketch uses the DHCP extensions to the Ethernet library
to get an IP address via DHCP and print the address obtained.
using an Arduino Wiznet Ethernet shield.

Circuit:

  • Ethernet shield attached to pins 10, 11, 12, 13

created 12 April 2011
by Tom Igoe

*/

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

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;

int freeRam() {
  extern int __heap_start,*__brkval;
  int v;
  return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval); 
}

void setup() {
  // start the serial library:
  Serial.begin(115200);

pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);

Serial.print(F("SRAM left: "));
  Serial.println(freeRam());
 
  // start the Ethernet connection:
  Ethernet.select(9);
 
  Serial.println(“Starting ethernet”);
  while (Ethernet.begin(mac) == 0) {
    Serial.println(“Failed to configure Ethernet using DHCP”);
    delay(5000);

Serial.print(F("SRAM left: "));
  Serial.println(freeRam());

Serial.println(“trying DHCP again”);
  }
  // print your local IP address:
  Serial.print(“My IP address: “);
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(”.”);
  }
  Serial.println();
}

void loop() {
  byte updateVal = Ethernet.maintain();

if(updateVal) {
     
    Serial.print(F(“DHCP maintain…”));
 
    switch(updateVal) {
      case 0:  Serial.println(F(“no action”));
              break;

case 1:  Serial.println(F(“renew failed”));   
              break;
             
      case 2:  Serial.println(F(“renew success”));         
              break;

case 3:  Serial.println(F(“rebind failed”));         
              break;

case 4:  Serial.println(F(“rebind success”));         
              break;

default:  Serial.println(F(“unknown”));
    }     
  }

delay(1000);
}




edit: Use the files in reply #21.

this is from topic: Change SS pin on Ethernet Shield

I’m using Arduino 1.0.6 IDE, and I have arduino uno rev. 3 board and arduino ethernet shields rev. 3

You will have a couple problems right out of the gate.

The ethernet shields use the ICSP pins for the SPI data lines. Nothing is connected to D11 to D13 on the ethernet shields. Somehow you must jumper the ICSP pins through one shield to the other.

Also you may have a power problem. The w5100 ICs are a bit power hungry, and I don’t know if the 5v bus will support two w5100s.

If you think you can overcome these obstacles, I might be able to help you with the rest.

SurferTim thank you for such a quick response. I have already done this. It took me some time.. but I've connected two eth shields to arduino uno (on hardware layer) using breadboard and some cables. Of course I have checked if both of them works. I've connected the first one with RJ-45 to my PC, set the right mac address and checked if the basic example with the web server works and I did the same with the second one.

Ok. You need to replace your ethernet library files with new files. Insure you back up your original files first.
Click here for new files

And what about file pins_arduino.h, pin 10 is defined there as a default SS, should I change also this?

No other changes! That must stay D10. That is used to set the SPI bus to master mode.

Connect one shield SS (D10 on shield) to D10 on the Uno and the other shield SS (D10 on shield)to D9 on the Uno.

Give me a few minutes to get my other computer booted up that has the startup code (and finish dinner ;) )

Ok. Thank You :)

OK, AFAIK, you will be the first to test this with two ethernet shields. It only initialises both w5100s. You can change the two IPs and the gateway to your network settings, insure the IPs are different. Let me know if this part works.

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

// this must be unique
byte macOne[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEC };
byte macTwo[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// change to your network settings
IPAddress ipOne(192,168,2,2);
IPAddress ipTwo(192,168,2,3);

IPAddress gateway(192, 168, 2, 1);
IPAddress subnet(255, 255, 255, 0);

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

  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);

  pinMode(9,OUTPUT);
  digitalWrite(9,HIGH);
   
  Serial.println(F("Starting ethernet..."));

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

void loop()
{
}

void startOne() {
  Serial.print(F("Starting One..."));
  Ethernet.select(10);
  Ethernet.begin(macOne, ipOne, gateway, gateway, subnet);
  Serial.println(Ethernet.localIP());
}

void startTwo() {
  Serial.print(F("Starting Two..."));
  Ethernet.select(9);
  Ethernet.begin(macTwo, ipTwo, gateway, gateway, subnet);
  Serial.println(Ethernet.localIP());
}

edit: I use 115200 for the serial. Insure you set that in the serial monitor (or change the baud rate in this code).

It seems this is working. This is the output on the serial monitor:

Starting ethernet...
Starting One...192.168.137.2
Starting Two...192.168.137.3
Ready

Wow.. I don't know how to thank you...

It looks like it works! Can you ping both IP addresses?

Only one connected to pin 10 (to the board) is responding.

edit: But maybe it's a OS/configuration isse. I'' check it

I have only one ethernet shield, so I switched it back and forth from D10 to D9 as the SS, and both respond to a ping. During the initialization, only one shows the correct ip, and the other shows 0.0.0.0.

That's weird it's an OS issue. On one laptop I have win8 and on the other one there is an old ubuntu version. Firstly I have connected D10 to win8, and D9 to ubuntu. D10 responded, D9 didn't. Then I switched PC's. D10 is connected to ubuntu and D9 is connected to win8. D9 is responding, D10 isn't. But anyways, IT'S WORKING :D

Good deal. I have both tests connected to the same router with the 192.168.2.1/24 network.

Hi,
so I tried to go to the next step of my project. On the first eth shield I need to run a server. But it doesn’t work.
This is my code:

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

byte macOne[] = {0x90, 0xA2, 0xDA, 0x0f, 0x15, 0x81};
byte macTwo[] = {0x90, 0xA2, 0xDA, 0x0f, 0x15, 0x4C};

IPAddress ipOne(192,168,137,2);
IPAddress ipTwo(192,168,0,11);

EthernetServer server(80);
boolean currentLineIsBlank = true;
char c;

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

  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);

  pinMode(9,OUTPUT);
  digitalWrite(9,HIGH);

  Serial.println(F("Starting ethernet..."));

  startOne();
  startTwo();

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

void loop()
{
  startOne();
  Serial.print(F("Board with IP address: "));
  Serial.print(Ethernet.localIP());
  Serial.print(F(" is selected\n"));
  startServer();
  Serial.println(F("The server is running."));
}

void startOne()
{
  Serial.print(F("Starting One..."));
  Ethernet.select(10);
  Ethernet.begin(macOne, ipOne);
  Serial.println(Ethernet.localIP());
}

void startTwo()
{
  Serial.print(F("Starting Two..."));
  Ethernet.select(9);
  Ethernet.begin(macTwo, ipTwo);
  Serial.println(Ethernet.localIP());
}

void startServer()
{
  server.begin();
  EthernetClient client = server.available();
  currentLineIsBlank = true;
  
  if(client)
  {
    while(client.connected())
    {
      if(client.available())
      {
        c = client.read();
        if(c == '\n' && currentLineIsBlank)
        {
          client.println("HTTP/1.1 200 OK");
          client.println("Content_type: text/html");
          client.println("Connection: close");
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.println("<meta http-equiv=\"refresh\" content=\"5\">");
          client.print("Hello world!");
          client.println("</html>");
          break;
        }
        if(c == '\n')
          currentLineIsBlank = true;
        else if(c != '\r')
          currentLineIsBlank = false;
      }
    }
    delay(1);
    client.stop();
  }
}

If I comment the line startTwo() in the setup function, everything is fine - it works. But when the code is as here then the output on the serial monitor looks fine, but the server doesn’t work.

Good question! :slight_smile:

You don’t call startOne or startTwo in loop(), only in setup. If you want to start a server on each shield, do it in startOne or startTwo. After that, you need only call Ethernet.select() to select the ethernet shield you want to communicate with.

I modified your code to start two servers, one on each ethernet shield. That happens in the startOne() and startTwo() functions.

Then I added checkServerOne() and checkServerTwo() functions and call them in the loop() function. You must call Ethernet.select() each time you want to change ethernet shields.

I also included the F() macro on each of your client.println() calls to keep those static strings in program memory. Otherwise you will run out of SRAM quickly.

I apologize in advance if there are any typos.

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

byte macOne[] = {0x90, 0xA2, 0xDA, 0x0f, 0x15, 0x81};
byte macTwo[] = {0x90, 0xA2, 0xDA, 0x0f, 0x15, 0x4C};

IPAddress ipOne(192,168,137,2);
IPAddress ipTwo(192,168,0,11);

EthernetServer serverOne(80);
EthernetServer serverTwo(80);

boolean currentLineIsBlank = true;
char c;

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

  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);

  pinMode(9,OUTPUT);
  digitalWrite(9,HIGH);

  Serial.println(F("Starting ethernet..."));

  startOne();
  startTwo();

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

void loop()
{
  checkServerOne();
  checkServerTwo();
}

void startOne()
{
  Serial.print(F("Starting One..."));
  Ethernet.select(10);
  Ethernet.begin(macOne, ipOne);
  Serial.println(Ethernet.localIP());
  
  serverOne.begin();
}

void startTwo()
{
  Serial.print(F("Starting Two..."));
  Ethernet.select(9);
  Ethernet.begin(macTwo, ipTwo);
  Serial.println(Ethernet.localIP());

  serverTwo.begin();
}

void checkServerOne()
{
  // select ethernet one
  Ethernet.select(10);

  EthernetClient client = serverOne.available();
  currentLineIsBlank = true;
  
  if(client)
  {
    while(client.connected())
    {
      if(client.available())
      {
        c = client.read();
        if(c == '\n' && currentLineIsBlank)
        {
          client.println(F("HTTP/1.1 200 OK"));
          client.println(F("Content-Type: text/html"));
          client.println(F("Connection: close"));
          client.println();
          client.println(F("<!DOCTYPE HTML>"));
          client.println(F("<html><head>"));
          client.println(F("<meta http-equiv=\"refresh\" content=\"5\">"));
          client.print(F("</head><body>Hello world from ethernet one!</body>"));
          client.println(F("</html>"));
          break;
        }
        if(c == '\n')
          currentLineIsBlank = true;
        else if(c != '\r')
          currentLineIsBlank = false;
      }
    }
    client.stop();
  }
}

void checkServerTwo()
{
  // select ethernet two
  Ethernet.select(9);

  EthernetClient client = serverTwo.available();
  currentLineIsBlank = true;
  
  if(client)
  {
    while(client.connected())
    {
      if(client.available())
      {
        c = client.read();
        if(c == '\n' && currentLineIsBlank)
        {
          client.println(F("HTTP/1.1 200 OK"));
          client.println(F("Content-Type: text/html"));
          client.println(F("Connection: close"));
          client.println();
          client.println(F("<!DOCTYPE HTML>"));
          client.println(F("<html><head>"));
          client.println(F("<meta http-equiv=\"refresh\" content=\"5\">"));
          client.print(F("</head><body>Hello world from ethernet two!</body>"));
          client.println(F("</html>"));
          break;
        }
        if(c == '\n')
          currentLineIsBlank = true;
        else if(c != '\r')
          currentLineIsBlank = false;
      }
    }
    client.stop();
  }
}

edit: My bad! I had a wrong variable name for the servers. It should have been serverOne.available() and serverTwo.available().

Thank you. I'll try this in the evening and I'll let you know :)

I tested it with my ethernet shield by changing the SS pin, and it seems to work. There was some errors in your html code in the sketch, but i have corrected those now.

edit: I also changed the message sent to the client so you can tell which is which. Shield one: "Hello World from ethernet one" Shield two: "Hello World from ethernet two"

It works perfectly! And the solution was really easy. Thank you very much and I hope I won’t have any more problems with this project :slight_smile: