Dual ethernet ports Due

Good day!

using the modified libraries GitHub - Wiznet/W5200_Arduino_Ethernet_Lib: Arduino Ethernet Library using W5200 from Wiznet for the wiz820io chip I found I am successfully able to connect with a single one to the google homepage download demo.

Now I am trying to add a second wiz820io to my Due, and having difficulty figuring out how to make a separate instance of the Ethernet library that can use another SS pin. It seems that the w5100.h file defines the SS_PIN so I'm not sure how to make another one and then tell the sketch that it needs to make another client using the different hardware.

The reason for all this: I have two other devices that need direct connections to and absolutely will not be able to use a switch.

Thanks!

#include <stdio.h>
#include <string.h>

#include "w5100.h"

// W5100 controller instance
W5100Class W5100;

#define SPI_CS 9

#define TX_RX_MAX_BUF_SIZE 2048
#define TX_BUF 0x1100
#define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE)

I took a quick look in the library that you linked to, but could not find SS_PIN being defined in the header or C files.

But perhaps I missed it.

Where is this defined, in your code or inside the library.

If its in the library, you have 2 options.

Either duplicate the library files and rename them, and rename the class files, and modify the class name in the c files etc
Which is probably 10 mins work using global search and replace in files.

Or

Modify the library so that rather than a define that the Ss_PIN is a variable or the class.

However this assumes that the class doesn't use any other static / global variables, in which case all of these would need to be modified to be instance variables.

Thanks, I think the dual library feature is the best way to go right now since that thing is all over the file. It was included in the w5100.cpp file

/*
 * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
 *
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of either the GNU General Public License version 2
 * or the GNU Lesser General Public License version 2.1, both as
 * published by the Free Software Foundation.
 */

#include <stdio.h>
#include <string.h>

#include "w5100.h"

// W5100 controller instance
W5100Class W5100;

#define SPI_CS 10

#define TX_RX_MAX_BUF_SIZE 2048
#define TX_BUF 0x1100
#define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE)

#ifdef W5200
#define TXBUF_BASE 0x8000
#define RXBUF_BASE 0xC000
#else
#define TXBUF_BASE 0x4000
#define RXBUF_BASE 0x6000
#endif

void W5100Class::init(void)
{
  delay(300);

  SPI.begin(SPI_CS);
  
  #ifdef W5200
  // should be ok with no divider, W5200 support 80Mhz and SAM3X8E is cadenced to 84Mhz..
  //have tried with webserver sample and it's ok but require more tests
  
  // Set clock to 42Mhz (W5200 should support up to 80Mhz)
  //SPI.setClockDivider(SPI_CS, 2);
  #else
  // Set clock to 4Mhz (W5100 should support up to 14Mhz)
  SPI.setClockDivider(SPI_CS, 21);
  #endif
  
  SPI.setDataMode(SPI_CS, SPI_MODE0);
  writeMR(1<<RST);
  
  #ifdef W5200
  for (int i=0; i<MAX_SOCK_NUM; i++) {
    write((0x4000 + i * 0x100 + 0x001F), 2);
    write((0x4000 + i * 0x100 + 0x001E), 2);
  }
  #else
  writeTMSR(0x55);
  writeRMSR(0x55);
  #endif

  for (int i=0; i<MAX_SOCK_NUM; i++) {
    SBASE[i] = TXBUF_BASE + SSIZE * i;
    RBASE[i] = RXBUF_BASE + RSIZE * i;
  }
}

uint16_t W5100Class::getTXFreeSize(SOCKET s)
{
  uint16_t val=0, val1=0;
  do {
    val1 = readSnTX_FSR(s);
    if (val1 != 0)
      val = readSnTX_FSR(s);
  } 
  while (val != val1);
  return val;
}

uint16_t W5100Class::getRXReceivedSize(SOCKET s)
{
  uint16_t val=0,val1=0;
  do {
    val1 = readSnRX_RSR(s);
    if (val1 != 0)
      val = readSnRX_RSR(s);
  } 
  while (val != val1);
  return val;
}


void W5100Class::send_data_processing(SOCKET s, const uint8_t *data, uint16_t len)
{
  // This is same as having no offset in a call to send_data_processing_offset
  send_data_processing_offset(s, 0, data, len);
}

void W5100Class::send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len)
{
  uint16_t ptr = readSnTX_WR(s);
  ptr += data_offset;
  uint16_t offset = ptr & SMASK;
  uint16_t dstAddr = offset + SBASE[s];

  if (offset + len > SSIZE) 
  {
    // Wrap around circular buffer
    uint16_t size = SSIZE - offset;
    write(dstAddr, data, size);
    write(SBASE[s], data + size, len - size);
  } 
  else {
    write(dstAddr, data, len);
  }

  ptr += len;
  writeSnTX_WR(s, ptr);
}


void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek)
{
  uint16_t ptr;
  ptr = readSnRX_RD(s);
  read_data(s, ptr, data, len);
  if (!peek)
  {
    ptr += len;
    writeSnRX_RD(s, ptr);
  }
}

void W5100Class::read_data(SOCKET s, volatile uint16_t src, volatile uint8_t *dst, uint16_t len)
{
  uint16_t size;
  uint16_t src_mask;
  uint16_t src_ptr;

  src_mask = src & RMASK;
  src_ptr = RBASE[s] + src_mask;

  if( (src_mask + len) > RSIZE ) 
  {
    size = RSIZE - src_mask;
    read(src_ptr, (uint8_t *)dst, size);
    dst += size;
    read(RBASE[s], (uint8_t *) dst, len - size);
  } 
  else
    read(src_ptr, (uint8_t *) dst, len);
}


uint8_t W5100Class::write(uint16_t _addr, uint8_t _data)
{
#ifdef W5200
  SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE);
  SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE);
  SPI.transfer(SPI_CS, 0x80, SPI_CONTINUE);
  SPI.transfer(SPI_CS, 0x01, SPI_CONTINUE);
#else	
  SPI.transfer(SPI_CS, 0xF0, SPI_CONTINUE);
  SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE);
  SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE);
#endif

  SPI.transfer(SPI_CS, _data);
  return 1;  
}

uint16_t W5100Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len)
{
#ifdef W5200
  SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE);
  SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE);
  SPI.transfer(SPI_CS, (0x80 | ((_len & 0x7F00) >> 8)), SPI_CONTINUE);
  SPI.transfer(SPI_CS, _len & 0x00FF, SPI_CONTINUE);

  for (uint16_t i=0; i<_len; i++)
  {
    SPI.transfer(SPI_CS, _buf[i], SPI_CONTINUE);

  }
#else	
  for (uint16_t i=0; i<_len; i++)
  {
	SPI.transfer(SPI_CS, 0xF0, SPI_CONTINUE);
	SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE);
	SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE);
	SPI.transfer(SPI_CS, _buf[i]);
    _addr++;
  }
#endif
  
  return _len;
}

uint8_t W5100Class::read(uint16_t _addr)
{  
#ifdef W5200
  SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE);
  SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE);
  SPI.transfer(SPI_CS, 0x00, SPI_CONTINUE);
  SPI.transfer(SPI_CS, 0x01, SPI_CONTINUE);
#else
  SPI.transfer(SPI_CS, 0x0F, SPI_CONTINUE);
  SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE);
  SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE);
#endif
  
  uint8_t _data = SPI.transfer(SPI_CS, 0);
  return _data;
}

uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len)
{
#ifdef W5200
  SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE);
  SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE);
  SPI.transfer(SPI_CS, (0x00 | ((_len & 0x7F00) >> 8)), SPI_CONTINUE);
  SPI.transfer(SPI_CS, _len & 0x00FF, SPI_CONTINUE);

  for (uint16_t i=0; i<_len; i++)
  {
    _buf[i] = SPI.transfer(SPI_CS, 0, SPI_CONTINUE);

  }
#else	
  for (uint16_t i=0; i<_len; i++)
  {
	SPI.transfer(SPI_CS, 0x0F, SPI_CONTINUE);
	SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE);
	SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE);
    _buf[i] = SPI.transfer(SPI_CS, 0);
    _addr++;
  }
#endif  
  return _len;
}

void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) {
  // Send command to socket
  writeSnCR(s, _cmd);
  // Wait for command to complete
  while (readSnCR(s))
    ;
}

I can't see anything in the code you posted about SS_PIN

Are you sure this is the actual text in the file

Or do you mean SPI_CS ?

Actually looking at the header file, it has this in it has some variables that are marked as static,some appears be constants, but you may need to change them, so I think duplicating and renaming is probably the easiest if not necessarily the neatest option

Sorry, yes SPI_CS

I've spent this time doing edits to files, and finding that I have to basically split the whole Ethernet library apart because all the functions are very linked. I was doing okay until I got to socket.h and then found that other classes were using virtual functions from it...

It seems it would actually be immensely easier to "just" figure out how to either

  1. add a new device support (all the files #include "utility/w5100.h"), might be nice if they somehow knew to "just" include my modified version w5100v2.h when it was appropriate
    OR
  2. pass an argument through and have that pin be selected from a local variable. I'm hoping it doesn't require a constant or something stupid is why it is pre defined. We'll see...

Also thank you VERY much for being interested and helping me on this!

Hi zabaat

umm OK

I'm surprised you needed to start changing socket.h etc why was that necessary ?

But making the CS pin a local var is ultimately the best way to do it.

Just add it as a property (var) of the class in the header file

BTW. Which folder of that library are you using the ? the AVR folder ? as both the cpp and h were in the AVR folder and the other folder (can't remember its name, but it began with an "s")

I took a quick look at the static vars in the header and they all look to me marked as CONST, so should not be an issue (but I didn't look in the CPP)

So perhaps just doing it the correct way is the easiest after all, however you probably won't know until you actually try it :wink:

I guess my confusion came from the example sketches with Ethernet
It appeared that to have two simultaneous clients I needed to have two instances of "Ethernet.h" since there doesn't appear to be a way to tell Ethernet.h / EthernetClient.h that you want to use a certain slave when you are trying to communicate...

a realization... do I just need to initialize both adapters and then manually control the SS pin from the sketch directly and hence pretend that it's the same interface?

At this time, I get both of my adapters configured, they now both respond to pings on the right addresses, but the loop part of the sketch is broken, I can't seem to get data from the interface.

I have reverted all files to original states except the below:
Here is my modification to Ethernet.cpp

void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet,int spiSetPin)
{
  W5100.init(spiSetPin);
  W5100.setMACAddress(mac);
  W5100.setIPAddress(local_ip._address);
  W5100.setGatewayIp(gateway._address);
  W5100.setSubnetMask(subnet._address);
  _dnsServerAddress = dns_server;
}

and my sketch which I added some more comments to, mainly the TODO, I don't really have an idea how to trigger the DUE to switch the CS pin correctly.

/*
  Web client

 This sketch connects to a website (http://www.google.com)
 using an Arduino Wiznet Ethernet shield.

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13

 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe, based on work by Adrian McEwen

 */


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

const int eth0Pin = 4;
const int eth1Pin = 10;


// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac1[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte mac2[] = { 0xBE, 0xEF, 0xBE, 0xEF, 0xFE, 0xED };
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
char server[] = "www.google.com";    // name address for Google (using DNS)

// Set the static IP address to use if the DHCP fails to assign
IPAddress ip1(10, 0, 0, 174);
IPAddress ip2(10, 0, 0, 175);

IPAddress dnsIPA(8, 8, 8, 8);
IPAddress gatewayIPA(10, 0, 0, 1);
IPAddress subnetIPA(10, 0, 0, 1);

// 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;

unsigned long lastConnectionTime = 0;             // last time you connected to the server, in milliseconds
const unsigned long postingInterval = 5L * 1000L; // delay between updates, in milliseconds

boolean interfaceToogle = false;
// the "L" is needed to use long type numbers

void setup() {
  // Open serial communications and wait for port to open:
  Serial1.begin(57600);
  while (!Serial1) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  delay(1000);    
  Serial1.println("**********SETUP ETHERNET 1 **************");
  Ethernet.begin(mac1, ip1, dnsIPA, gatewayIPA, subnetIPA, eth0Pin);
  Serial1.println("1 Skipping DHCP");

 
  delay(1000);
  Serial1.println("**********SETUP ETHERNET 2 **************");
  Ethernet.begin(mac2, ip2, dnsIPA, gatewayIPA, subnetIPA, eth1Pin);
  Serial1.println("2 Skipping DHCP");  
}


void loop() {
  // if there's incoming data from the net connection.
  // send it out the serial port.  This is for debugging
  // purposes only:
  if (interfaceToogle) 
  {
      ////TO DO figure this out?
  }
  
  if (client.available()) {
    char c = client.read();
    Serial.write(c);
  }

  // if ten seconds have passed since your last connection,
  // then connect again and send data:
  if (millis() - lastConnectionTime > postingInterval) {
    httpRequest();
    interfaceToogle =  !interfaceToogle;
  }

}

// this method makes a HTTP connection to the server:
void httpRequest() {
  // close any connection before send a new request.
  // This will free the socket on the WiFi shield
  client.stop();

  // if there's a successful connection:
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    // send the HTTP PUT request:
    client.println("GET /latest.txt HTTP/1.1");
    client.println("Host: www.arduino.cc");
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();

    // note the time that the connection was made:
    lastConnectionTime = millis();
  }
  else {
    // if you couldn't make a connection:
    Serial.println("connection failed");
  }
}

edit: sorry about edits, I've been refining the code and found some compile errors.

Look at you code the thing that concerns me are the lines

Ethernet.begin(mac1, ip1, dnsIPA, gatewayIPA, subnetIPA, eth0Pin);

and

  Ethernet.begin(mac2, ip2, dnsIPA, gatewayIPA, subnetIPA, eth1Pin);

Basically you can't do this.

because Ethernet.cpp (or Ethernet.h) only seems to have one instance of W5100

You will need to change this, so that it has 2 of them.

I'm not that familiar with the Ethernet library

I think you may be better off posting a new thread about this specific issue ( as I don't think you can ask the moderator to move your own thread)

I stated a new topic in networking.
http://forum.arduino.cc/index.php?topic=253330.msg1793013#msg1793013