Ethernet for Teensy3

Status
Not open for further replies.

tochinet

Member
Did anyone manage to get a web server on Teensy3 ? Which HW would you recommended ?
I was thinking of using a WiFi dongle, as the simplest solution and most elegant as well. Any thoughts ?
 
If you're talking about a USB WiFi dongle, first you would need USB Host functionality, which is expected sometime next year. You could use a SPI module, eg. one using the Microchip ENC26J60 chip but would need to port the software from Arduino also.
 
I made this adaptor recently, but haven't had time to test it yet....

thumb_i.png
 
Not really an old topic, @JBeale !

Paul, this looks an uSD + 3V regulator to me, not Ethernet, right ? Any PCB available ?
 
It's both a SD card and socket for the Wiz820 module.

Those 2 groups of 6 pins on the top and bottom are for the Wiz820.

wiz820.jpg

Edit: the 3.3 volt regulator is needed because the Wiz820 is right at Teensy 3.0's output limit (perhaps more depending on the ethernet magnetics and cable), so using the SD card or even a few LEDs pushes the current too high for the internal regulator.
 
I ordered some PCBs yesterday to build a RFM12B wireless to Ethernet bridge. There is also a 3.3V regulator included as I'm clearly above the 100mA. The board is 5x5cm but I love your idea to put the wiz820io on top of the Teensy. Maybe an idea for rev 2 but first I'll have to locate a enclosure.

Bildschirmfoto 2013-01-02 um 14.12.48.png

Btw, my RFM12B to Ethernet bridge is already working reliable on breadboard. I'm currently pushing received wireless data to a Redis server over Ethernet. Look like I'll have to order some more Teensy 3.0's soon ;-)
 
Btw, my RFM12B to Ethernet bridge is already working reliable on breadboard. I'm currently pushing received wireless data to a Redis server over Ethernet. Look like I'll have to order some more Teensy 3.0's soon ;-)

That sounds like a pretty interesting project - are you documenting it anywhere?
 
I will as soon as I receive the PCBs. Currently time is an issue too but I'll come back to this.
 
I don't use Eagle, so no, sorry, no Eagle files.

Here is a newer version via OSH Park design sharing.

http://oshpark.com/shared_projects/LOt9A5hs

That first board lacked a way to reset the W5200, which really turned out to be necessary. This newer one connects the reset to pin 9. If you order some of these from OSH Park, please let me know when they arrive. I'll try to gid up the experimental code for it...
 
I don't use Eagle, so no, sorry, no Eagle files.

Here is a newer version via OSH Park design sharing.

http://oshpark.com/shared_projects/LOt9A5hs

That first board lacked a way to reset the W5200, which really turned out to be necessary. This newer one connects the reset to pin 9. If you order some of these from OSH Park, please let me know when they arrive. I'll try to gid up the experimental code for it...

Had them for about a week now, just waiting for the WIZ820io boards to arrive. There's no part numbers on the boards, so I'm not sure what other devices I need to populate your boards.
 
I looked at the LM3940 datasheet. It's the same pinout, but it has this more difficult capacitor requirement:

The minimum output capacitance required to maintain stability is 33 uF (this value may be increased without
limit). Larger values of output capacitance will give improved transient response.
ESR LIMITS:
The ESR of the output capacitor will cause loop instability if it is too high or too low. The acceptable range of
ESR plotted versus load current is shown in Figure 19. It is essential that the output capacitor meet these
requirements, or oscillations can result.

lp3949_figure19.png

As long as you add the right capacitor, instead of the 1uF ceramic the MCP1825 uses, I believe the LM3940 can work.
 
OK got the regulators and caps (holy crap, they're TINY), and was starting to assemble the board. I don't see a way, with the headers and sockets I currently have, to assemble the parts in such a way as to be able to plug the whole schebang into a solderless breadboard. Any thoughts or suggestions?
 
I breadboarded the Teensy 3.0 and WIZ820io, copied the w5100.cpp and w5100.h files to the /libraries/Ethernet/utility directory and loaded the WebServer.ino file from the ethernet examples directory. I also added a reset to the WIZ820io using digital pin 9. When I went to compile using Teensyduino release 1.15, I got some errors. I then downloaded the Teensyduino 1.16 release and installed it, and the compile completed successfully, but the webserver address was not correct, ie, not the address that I had selected. I then tried the DHCP address printer example, and it could not connect using DHCP.
 
I breadboarded the Teensy 3.0 and WIZ820io, copied the w5100.cpp and w5100.h files to the /libraries/Ethernet/utility directory and loaded the WebServer.ino file from the ethernet examples directory. I also added a reset to the WIZ820io using digital pin 9. When I went to compile using Teensyduino release 1.15, I got some errors. I then downloaded the Teensyduino 1.16 release and installed it, and the compile completed successfully, but the webserver address was not correct, ie, not the address that I had selected. I then tried the DHCP address printer example, and it could not connect using DHCP.
In porting stuff to/from Arduino, check for anything using 'int' and 'unsigned' types (as opposed to int16_t, uint32_t, etc.). The int data type on Arduino is 16 bits, while it is 32-bits on Arm based processor. For other code, you would want to check for 'double' as well, but I doubt ethernet uses double. Also, check for anything to do with interrupts and direct port manipulation. If the code has been ported to the Due (look for #ifdef __SAM3X8E__), that code probably is a reasonable starting off place for the Teensy 3.0. Finally, PROGMEM usage might need to be adjusted.
 
... copied the w5100.cpp and w5100.h files to the /libraries/Ethernet/utility directory and loaded the WebServer.ino file from the ethernet examples directory. .... I got some errors. I then downloaded the Teensyduino 1.16 release and installed it, and the compile completed successfully, but the webserver address was not correct, ie, not the address that I had selected. I then tried the DHCP address printer example, and it could not connect using DHCP.

If you'd like help resolving these software problems, you need to be post the exact files you used or provide links to them. Copying the exact error messages you saw is also a good idea.
 
Here's the ino file:

Code:
/*
  Web Server
 
 A simple web server that shows the value of the analog input pins.
 using an Arduino Wiznet Ethernet shield. 
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)
 
 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe
 
 */

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

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0xDE, 0xAD, 0xBA, 0xBE, 0xFA, 0xCE };
IPAddress ip(192,168,1,135);

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
EthernetServer server(80);

void setup() {
 // Open serial communications and wait for port to open:
  Serial.begin(115200);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  // reset the WIZ812mj nic
  pinMode(9, OUTPUT);
  digitalWrite(9, LOW);
  delay(250);
  digitalWrite(9, HIGH);
  
  delay(1000);

  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}


void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println(F("HTTP/1.1 200 OK"));
          client.println(F("Content-Type: text/html"));
          client.println(F("Connection: close"));  // the connection will be closed after completion of the response
	  client.println(F("Refresh: 5"));  // refresh the page automatically every 5 sec
          client.println(F(""));
          client.println(F("<!DOCTYPE HTML>"));
          client.println(F("<html>"));
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print(F("BoogerHead "));
            client.print(analogChannel);
            client.print(F(" is "));
            client.print(sensorReading);
            client.println(F("<br />"));       
          }
          client.println(F("</html>"));
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
}

Here's the replacement w5100.cpp, per the WizNet github:
Code:
/*
 * 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 <avr/interrupt.h>

#include "w5100.h"

// W5100 controller instance
W5100Class W5100;

#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();
  initSS();
  
  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, (uint8_t *)ptr, data, len);
  if (!peek)
  {
    ptr += len;
    writeSnRX_RD(s, ptr);
  }
}

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

  src_mask = (uint16_t)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)
{
  setSS();  
  
#ifdef W5200
  SPI.transfer(_addr >> 8);
  SPI.transfer(_addr & 0xFF);
  SPI.transfer(0x80);
  SPI.transfer(0x01);
#else	
  SPI.transfer(0xF0);
  SPI.transfer(_addr >> 8);
  SPI.transfer(_addr & 0xFF);
#endif  
  
  SPI.transfer(_data);
  resetSS();
  return 1;
}

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

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

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

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

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

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

  }
    resetSS();

#else	
	
  for (uint16_t i=0; i<_len; i++)
  {
    setSS();
    SPI.transfer(0x0F);
    SPI.transfer(_addr >> 8);
    SPI.transfer(_addr & 0xFF);
    _addr++;
    _buf[i] = SPI.transfer(0);
    resetSS();
  }
#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))
    ;
}

And the w5100.h replacement:
Code:
/*
 * 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.
 */

#ifndef	W5100_H_INCLUDED
#define	W5100_H_INCLUDED

#include <avr/pgmspace.h>
#include <SPI.h>

#define W5200

#ifdef W5200
#define MAX_SOCK_NUM 8
#else
#define MAX_SOCK_NUM 4
#endif


typedef uint8_t SOCKET;

#ifndef W5200
#define IDM_OR  0x8000
#define IDM_AR0 0x8001
#define IDM_AR1 0x8002
#define IDM_DR  0x8003
#endif

/*
class MR {
public:
  static const uint8_t RST   = 0x80;
  static const uint8_t PB    = 0x10;
  static const uint8_t PPPOE = 0x08;
  static const uint8_t LB    = 0x04;
  static const uint8_t AI    = 0x02;
  static const uint8_t IND   = 0x01;
};
*/
/*
class IR {
public:
  static const uint8_t CONFLICT = 0x80;
  static const uint8_t UNREACH  = 0x40;
  static const uint8_t PPPoE    = 0x20;
  static const uint8_t SOCK0    = 0x01;
  static const uint8_t SOCK1    = 0x02;
  static const uint8_t SOCK2    = 0x04;
  static const uint8_t SOCK3    = 0x08;
  static inline uint8_t SOCK(SOCKET ch) { return (0x01 << ch); };
};
*/

class SnMR {
public:
  static const uint8_t CLOSE  = 0x00;
  static const uint8_t TCP    = 0x01;
  static const uint8_t UDP    = 0x02;
  static const uint8_t IPRAW  = 0x03;
  static const uint8_t MACRAW = 0x04;
  static const uint8_t PPPOE  = 0x05;
  static const uint8_t ND     = 0x20;
  static const uint8_t MULTI  = 0x80;
};

enum SockCMD {
  Sock_OPEN      = 0x01,
  Sock_LISTEN    = 0x02,
  Sock_CONNECT   = 0x04,
  Sock_DISCON    = 0x08,
  Sock_CLOSE     = 0x10,
  Sock_SEND      = 0x20,
  Sock_SEND_MAC  = 0x21,
  Sock_SEND_KEEP = 0x22,
  Sock_RECV      = 0x40
};

/*class SnCmd {
public:
  static const uint8_t OPEN      = 0x01;
  static const uint8_t LISTEN    = 0x02;
  static const uint8_t CONNECT   = 0x04;
  static const uint8_t DISCON    = 0x08;
  static const uint8_t CLOSE     = 0x10;
  static const uint8_t SEND      = 0x20;
  static const uint8_t SEND_MAC  = 0x21;
  static const uint8_t SEND_KEEP = 0x22;
  static const uint8_t RECV      = 0x40;
};
*/

class SnIR {
public:
  static const uint8_t SEND_OK = 0x10;
  static const uint8_t TIMEOUT = 0x08;
  static const uint8_t RECV    = 0x04;
  static const uint8_t DISCON  = 0x02;
  static const uint8_t CON     = 0x01;
};

class SnSR {
public:
  static const uint8_t CLOSED      = 0x00;
  static const uint8_t INIT        = 0x13;
  static const uint8_t LISTEN      = 0x14;
  static const uint8_t SYNSENT     = 0x15;
  static const uint8_t SYNRECV     = 0x16;
  static const uint8_t ESTABLISHED = 0x17;
  static const uint8_t FIN_WAIT    = 0x18;
  static const uint8_t CLOSING     = 0x1A;
  static const uint8_t TIME_WAIT   = 0x1B;
  static const uint8_t CLOSE_WAIT  = 0x1C;
  static const uint8_t LAST_ACK    = 0x1D;
  static const uint8_t UDP         = 0x22;
  static const uint8_t IPRAW       = 0x32;
  static const uint8_t MACRAW      = 0x42;
  static const uint8_t PPPOE       = 0x5F;
};

class IPPROTO {
public:
  static const uint8_t IP   = 0;
  static const uint8_t ICMP = 1;
  static const uint8_t IGMP = 2;
  static const uint8_t GGP  = 3;
  static const uint8_t TCP  = 6;
  static const uint8_t PUP  = 12;
  static const uint8_t UDP  = 17;
  static const uint8_t IDP  = 22;
  static const uint8_t ND   = 77;
  static const uint8_t RAW  = 255;
};

class W5100Class {

public:
  void init();

  /**
   * @brief	This function is being used for copy the data form Receive buffer of the chip to application buffer.
   * 
   * It calculate the actual physical address where one has to read
   * the data from Receive buffer. Here also take care of the condition while it exceed
   * the Rx memory uper-bound of socket.
   */
  void read_data(SOCKET s, volatile uint8_t * src, volatile uint8_t * dst, uint16_t len);
  
  /**
   * @brief	 This function is being called by send() and sendto() function also. 
   * 
   * This function read the Tx write pointer register and after copy the data in buffer update the Tx write pointer
   * register. User should read upper byte first and lower byte later to get proper value.
   */
  void send_data_processing(SOCKET s, const uint8_t *data, uint16_t len);
  /**
   * @brief A copy of send_data_processing that uses the provided ptr for the
   *        write offset.  Only needed for the "streaming" UDP API, where
   *        a single UDP packet is built up over a number of calls to
   *        send_data_processing_ptr, because TX_WR doesn't seem to get updated
   *        correctly in those scenarios
   * @param ptr value to use in place of TX_WR.  If 0, then the value is read
   *        in from TX_WR
   * @return New value for ptr, to be used in the next call
   */
// FIXME Update documentation
  void send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len);

  /**
   * @brief	This function is being called by recv() also.
   * 
   * This function read the Rx read pointer register
   * and after copy the data from receive buffer update the Rx write pointer register.
   * User should read upper byte first and lower byte later to get proper value.
   */
  void recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek = 0);

  inline void setGatewayIp(uint8_t *_addr);
  inline void getGatewayIp(uint8_t *_addr);

  inline void setSubnetMask(uint8_t *_addr);
  inline void getSubnetMask(uint8_t *_addr);

  inline void setMACAddress(uint8_t * addr);
  inline void getMACAddress(uint8_t * addr);

  inline void setIPAddress(uint8_t * addr);
  inline void getIPAddress(uint8_t * addr);

  inline void setRetransmissionTime(uint16_t timeout);
  inline void setRetransmissionCount(uint8_t _retry);

  void execCmdSn(SOCKET s, SockCMD _cmd);
  
  uint16_t getTXFreeSize(SOCKET s);
  uint16_t getRXReceivedSize(SOCKET s);
  

  // W5100 Registers
  // ---------------
private:
  static uint8_t write(uint16_t _addr, uint8_t _data);
  static uint16_t write(uint16_t addr, const uint8_t *buf, uint16_t len);
  static uint8_t read(uint16_t addr);
  static uint16_t read(uint16_t addr, uint8_t *buf, uint16_t len);
  
#define __GP_REGISTER8(name, address)             \
  static inline void write##name(uint8_t _data) { \
    write(address, _data);                        \
  }                                               \
  static inline uint8_t read##name() {            \
    return read(address);                         \
  }
#define __GP_REGISTER16(name, address)            \
  static void write##name(uint16_t _data) {       \
    write(address,   _data >> 8);                 \
    write(address+1, _data & 0xFF);               \
  }                                               \
  static uint16_t read##name() {                  \
    uint16_t res = read(address);                 \
    res = (res << 8) + read(address + 1);         \
    return res;                                   \
  }
#define __GP_REGISTER_N(name, address, size)      \
  static uint16_t write##name(uint8_t *_buff) {   \
    return write(address, _buff, size);           \
  }                                               \
  static uint16_t read##name(uint8_t *_buff) {    \
    return read(address, _buff, size);            \
  }

public:
  __GP_REGISTER8 (MR,     0x0000);    // Mode
  __GP_REGISTER_N(GAR,    0x0001, 4); // Gateway IP address
  __GP_REGISTER_N(SUBR,   0x0005, 4); // Subnet mask address
  __GP_REGISTER_N(SHAR,   0x0009, 6); // Source MAC address
  __GP_REGISTER_N(SIPR,   0x000F, 4); // Source IP address
  __GP_REGISTER8 (IR,     0x0015);    // Interrupt
  __GP_REGISTER8 (IMR,    0x0016);    // Interrupt Mask
  __GP_REGISTER16(RTR,    0x0017);    // Timeout address
  __GP_REGISTER8 (RCR,    0x0019);    // Retry count
  
  #ifndef W5200
  __GP_REGISTER8 (RMSR,   0x001A);    // Receive memory size
  __GP_REGISTER8 (TMSR,   0x001B);    // Transmit memory size
  #endif
  __GP_REGISTER8 (PATR,   0x001C);    // Authentication type address in PPPoE mode
  __GP_REGISTER8 (PTIMER, 0x0028);    // PPP LCP Request Timer
  __GP_REGISTER8 (PMAGIC, 0x0029);    // PPP LCP Magic Number
  #ifndef W5200
  __GP_REGISTER_N(UIPR,   0x002A, 4); // Unreachable IP address in UDP mode
  __GP_REGISTER16(UPORT,  0x002E);    // Unreachable Port address in UDP mode
#endif
  
#undef __GP_REGISTER8
#undef __GP_REGISTER16
#undef __GP_REGISTER_N

  // W5100 Socket registers
  // ----------------------
private:
  static inline uint8_t readSn(SOCKET _s, uint16_t _addr);
  static inline uint8_t writeSn(SOCKET _s, uint16_t _addr, uint8_t _data);
  static inline uint16_t readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len);
  static inline uint16_t writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len);

#ifdef W5200
  static const uint16_t CH_BASE = 0x4000;
#else
  static const uint16_t CH_BASE = 0x0400;
#endif  

  static const uint16_t CH_SIZE = 0x0100;

#define __SOCKET_REGISTER8(name, address)                    \
  static inline void write##name(SOCKET _s, uint8_t _data) { \
    writeSn(_s, address, _data);                             \
  }                                                          \
  static inline uint8_t read##name(SOCKET _s) {              \
    return readSn(_s, address);                              \
  }
#define __SOCKET_REGISTER16(name, address)                   \
  static void write##name(SOCKET _s, uint16_t _data) {       \
    writeSn(_s, address,   _data >> 8);                      \
    writeSn(_s, address+1, _data & 0xFF);                    \
  }                                                          \
  static uint16_t read##name(SOCKET _s) {                    \
    uint16_t res = readSn(_s, address);                      \
    res = (res << 8) + readSn(_s, address + 1);              \
    return res;                                              \
  }
#define __SOCKET_REGISTER_N(name, address, size)             \
  static uint16_t write##name(SOCKET _s, uint8_t *_buff) {   \
    return writeSn(_s, address, _buff, size);                \
  }                                                          \
  static uint16_t read##name(SOCKET _s, uint8_t *_buff) {    \
    return readSn(_s, address, _buff, size);                 \
  }
  
public:
  __SOCKET_REGISTER8(SnMR,        0x0000)        // Mode
  __SOCKET_REGISTER8(SnCR,        0x0001)        // Command
  __SOCKET_REGISTER8(SnIR,        0x0002)        // Interrupt
  __SOCKET_REGISTER8(SnSR,        0x0003)        // Status
  __SOCKET_REGISTER16(SnPORT,     0x0004)        // Source Port
  __SOCKET_REGISTER_N(SnDHAR,     0x0006, 6)     // Destination Hardw Addr
  __SOCKET_REGISTER_N(SnDIPR,     0x000C, 4)     // Destination IP Addr
  __SOCKET_REGISTER16(SnDPORT,    0x0010)        // Destination Port
  __SOCKET_REGISTER16(SnMSSR,     0x0012)        // Max Segment Size
  __SOCKET_REGISTER8(SnPROTO,     0x0014)        // Protocol in IP RAW Mode
  __SOCKET_REGISTER8(SnTOS,       0x0015)        // IP TOS
  __SOCKET_REGISTER8(SnTTL,       0x0016)        // IP TTL
  __SOCKET_REGISTER16(SnTX_FSR,   0x0020)        // TX Free Size
  __SOCKET_REGISTER16(SnTX_RD,    0x0022)        // TX Read Pointer
  __SOCKET_REGISTER16(SnTX_WR,    0x0024)        // TX Write Pointer
  __SOCKET_REGISTER16(SnRX_RSR,   0x0026)        // RX Free Size
  __SOCKET_REGISTER16(SnRX_RD,    0x0028)        // RX Read Pointer
  __SOCKET_REGISTER16(SnRX_WR,    0x002A)        // RX Write Pointer (supported?)
  
#undef __SOCKET_REGISTER8
#undef __SOCKET_REGISTER16
#undef __SOCKET_REGISTER_N


private:
  static const uint8_t  RST = 7; // Reset BIT

#ifdef W5200
  static const int SOCKETS = 8;
#else
  static const int SOCKETS = 4;
#endif

  static const uint16_t SMASK = 0x07FF; // Tx buffer MASK
  static const uint16_t RMASK = 0x07FF; // Rx buffer MASK
public:
  static const uint16_t SSIZE = 2048; // Max Tx buffer size
private:
  static const uint16_t RSIZE = 2048; // Max Rx buffer size
  uint16_t SBASE[SOCKETS]; // Tx buffer base address
  uint16_t RBASE[SOCKETS]; // Rx buffer base address

private:
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  inline static void initSS()    { DDRB  |=  _BV(4); };
  inline static void setSS()     { PORTB &= ~_BV(4); };
  inline static void resetSS()   { PORTB |=  _BV(4); };
#elif defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB162__)
  inline static void initSS()    { DDRB  |=  _BV(0); };
  inline static void setSS()     { PORTB &= ~_BV(0); };
  inline static void resetSS()   { PORTB |=  _BV(0); }; 
#else
  inline static void initSS()    { DDRB  |=  _BV(2); };
  inline static void setSS()     { PORTB &= ~_BV(2); };
  inline static void resetSS()   { PORTB |=  _BV(2); };
#endif

};

extern W5100Class W5100;

uint8_t W5100Class::readSn(SOCKET _s, uint16_t _addr) {
  return read(CH_BASE + _s * CH_SIZE + _addr);
}

uint8_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t _data) {
  return write(CH_BASE + _s * CH_SIZE + _addr, _data);
}

uint16_t W5100Class::readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) {
  return read(CH_BASE + _s * CH_SIZE + _addr, _buf, _len);
}

uint16_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) {
  return write(CH_BASE + _s * CH_SIZE + _addr, _buf, _len);
}

void W5100Class::getGatewayIp(uint8_t *_addr) {
  readGAR(_addr);
}

void W5100Class::setGatewayIp(uint8_t *_addr) {
  writeGAR(_addr);
}

void W5100Class::getSubnetMask(uint8_t *_addr) {
  readSUBR(_addr);
}

void W5100Class::setSubnetMask(uint8_t *_addr) {
  writeSUBR(_addr);
}

void W5100Class::getMACAddress(uint8_t *_addr) {
  readSHAR(_addr);
}

void W5100Class::setMACAddress(uint8_t *_addr) {
  writeSHAR(_addr);
}

void W5100Class::getIPAddress(uint8_t *_addr) {
  readSIPR(_addr);
}

void W5100Class::setIPAddress(uint8_t *_addr) {
  writeSIPR(_addr);
}

void W5100Class::setRetransmissionTime(uint16_t _timeout) {
  writeRTR(_timeout);
}

void W5100Class::setRetransmissionCount(uint8_t _retry) {
  writeRCR(_retry);
}

#endif

When I run the code, I get either random IP addresses that are not in my sub-net, or just 0.0.0.0 for the ip address displayed.
 
The files you have posted are referencing the WIZ812mj. As it understand it the Ethernet module you are using is the WIZ820io, so you may need different files. User manitou has posted files in this thread working with Teensy3 and WIZ820io that I can confirm work in my project
 
Status
Not open for further replies.
Back
Top