Basic setup of W6100

I have followed all the info I can find online, but I still cannot make my W6100 (on WIZ610io) work properly.

I tried with and without the io6Library. Expand the tabs to see each version of the process.

Steps with io6Library
  1. Download this repository as a .zip and extract it.
  2. Create a new project in KEIL uVision. Set up the MCU using CubeMX.
  3. Copy over the source code in main.c from the example repo into my new uVision project, but changing the SPI handles, GPIO pins, etc. so that they match with my MCU (STM32F407VGTx).
  4. Change all instances of printf to sprintf followed by a call to HAL_UART_Transmit so that it will work and I can see the print output over UART.
  5. Copy the io6Library files and configure uVision to use them. Make sure everything compiles.
  6. Plug in the WIX610io (power, ground, MISO, MOSI, SCK, CS) and UART serial connection (Rx, Tx) to the board, and plug an Ethernet cable into the W6100 and the PC.
  7. Run the code. It runs, hooray. The printout looks like this:
< W6100EVB Hal Driver Loop Back TEST!! >
interrupt mask: 02
VERSION(200) = 4661
Mac address: 00:08:dc:57:57:20
IP address : 192.168.0.13
SN Mask   : 255.255.255.0
Gate way   : 192.168.0.1
DNS Server : 168.126.63.1
LLA  : FE80:0000:0000:0000:0208:DCFF:FE57:5761
GUA  : 2001:02B8:0010:0001:0208:DCFF:FE57:5761
SN6  : FFFF:FFFF:FFFF:FFFF:0000:0000:0000:0000
GW6  : FE80:0000:0000:0000:0200:87FF:FE08:4C81
  1. Great, it seems to be working. The debugger shows the code looping over the loopback_tcps function, and the state of the Sn_SR register is 0x14 (SOCK_LISTEN). Now it’s time to connect to that socket.
  2. On the PC, I go to Control Panel > Network and Internet > Network and Sharing Center > Chang adapter settings > double click “Ethernet” > Properties > select “Internet Protocol Version 4 (TCP/IPv4)” > Properties > select “Use the following IP address:” > enter 192.168.0.13 for “IP address” and 255.255.255.0 for “Subnet mask” > Ok > Ok > Close
  3. Then open up Hercules SETUP Utility. Go to the TCP Client tab. Enter 192.168.0.13 in the Module IP field and 5001 in the Port field. Click Connect or Ping.
  4. It times out :frowning:.
Steps without io6Library
  1. Write the code shown at the bottom of this post under the CODE tab.
  2. Open the code in Arduino IDE.
  3. Upload the code to a Sparkfun RedBoard.
  4. Connect the WIZ610io to the RedBoard (power, ground, MISO, MOSI, SCK, CS).
  5. Connect an Ethernet cable between the W6100 and the PC
  6. Run the code. The output is the following:
W6100 reset.
Chip ID is: 0x610 (should be 0x610[0])
Version Number is: 0x4661 (should be 0x4661)
Network config set.
Socket sizes set.
Socket 0 opened.
Socket 0 listening.
Waiting for connection...
looping
looping
looping

...
  1. Try the same steps as above (steps 9 and 10)
  2. It times out :frowning:. The interrupt never fires, and so the code says looping forever.

I must be doing something wrong, but I don’t quite know what. I have tried using a router in between the PC and the W6100, I have tried using both straight-through and crossover cables, I have tried connecting to the W6100 with a web browser, I have tried sending Wake on LAN packets to the device while checking for the WoL interrupt (it never triggers), I have tried all sorts of combinations of those things.

I also tried to just sent a raw Ethernet packet from the PC to the W6100 via Python, but Windows does not support opening that type of socket.

CODE section mentioned above:

CODE

main.ino

#include <SPI.h>
#include "constants.h"

// Want SPI data rate of 14 MHZ, MSB transmitted first, clock mode 0
SPISettings W6100_SETTINGS = SPISettings(14000000, MSBFIRST, SPI_MODE0);

// Static parameters for the W6100 device (source)
uint8_t sourceHWAddress[] = {0x11, 0x22, 0x33, 0xAA, 0xBB, 0xCC}; // 11:22:33:AA:BB:CC
uint8_t gateway[] = {0xC0, 0xA8, 0x01, 0x01};                     // 192.168.1.1
uint8_t subnet[] = {0xFF, 0xFF, 0xFF, 0x00};                      // 255.255.255.0
uint8_t sourceIPAddress[] = {0xC0, 0xA8, 0x01, 0x63};             // 192.168.1.99

void setup() {
  // Initialize debug output and SPI
  Serial.begin(9600);
  SPI.begin();
  
  // W6100 chip select signal is an output and defaults to HIGH
  pinMode(W6100_CS_PIN, OUTPUT);
  digitalWrite(W6100_CS_PIN, HIGH);

  // Reset the W6100
  resetW6100();
  Serial.println("W6100 reset.");

  // Read chip ID and version number
  uint8_t chipID[2];
  uint8_t versionNumber[2];
  accessW6100(READ, CIDR, chipID, 2, CONTROL_REG, CR);
  accessW6100(READ, VER, versionNumber, 2, CONTROL_REG, CR);
  Serial.print("Chip ID is: 0x");
  Serial.print(chipID[0], HEX);
  Serial.print(chipID[1], HEX);
  Serial.println(" (should be 0x610[0])");
  Serial.print("Version Number is: 0x");
  Serial.print(versionNumber[0], HEX);
  Serial.print(versionNumber[1], HEX);
  Serial.println(" (should be 0x4661)");

  // Configure network
  setNetworkConfig(sourceHWAddress, gateway, subnet, sourceIPAddress);
  Serial.println("Network config set.");

  // Set all socket buffers (TX and RX) to 2 KB
  for(int i = 0; i < NUM_SOCKETS; i++) {
    setSocketSize((Socket)i, SOCKET_2KB);
  }
  Serial.println("Socket sizes set.");

  // Open socket 0 on port 5000
  SocketState state = openSocket(SOCKET_0, 5000);
  if(state == SOCK_INIT)
    Serial.println("Socket 0 opened.");
  else
    error("Failed to open socket 0");

  // Listen on socket 0
  state = listenSocket(SOCKET_0);
  if(state == SOCK_LISTEN)
    Serial.println("Socket 0 listening.");
  else
    error("Failed to listen on socket 0");

  // Wait for a connection
  Serial.println("Waiting for connection...");

  uint8_t interrupt[1];
  uint8_t socketInterrupt[1];
  uint8_t systemInterrupt[1];
  int x=0;
  while(true) {
    x++;
    if(x%10000 == 0)
      Serial.println("looping");

    accessW6100(READ, IR, systemInterrupt, 1, CONTROL_REG, CR);
    if(systemInterrupt[0]) {
      accessW6100(WRITE, IRCLR, systemInterrupt, 1, CONTROL_REG, CR);
      Serial.println("system interrupt");
      break;
    }
    accessW6100(READ, SIR, socketInterrupt, 1, CONTROL_REG, CR);
    if(socketInterrupt[0]) {
      Serial.println("socket interrupt");
      break;
    }

    // Read interrupt register
    accessW6100(READ, Sn_IR, interrupt, 1, SOCKET_0, Sn_REG);

    // Check for connection established interrupt
    if(interrupt[0] & IRMASK_CON) {
      interrupt[0] = IRMASK_CON;
      accessW6100(WRITE, Sn_IRCLR, interrupt, 1, SOCKET_0, Sn_REG);
      break;
    }

    // Check for timeout interrupt
    if(interrupt[0] & IRMASK_TIMEOUT) {
      interrupt[0] = IRMASK_TIMEOUT;
      accessW6100(WRITE, Sn_IRCLR, interrupt, 1, SOCKET_0, Sn_REG);
      error("Timeout :(");
    }
  }

  Serial.println("Connection interrupt!");
}

/*
 * Sets socket `socket` to listening mode. `socket` must
 * already be open.
 */
SocketState listenSocket(Socket socket) {
  // Send the listen command
  uint8_t command[] = {CMD_LISTEN};
  accessW6100(WRITE, Sn_CR, command, 1, socket, Sn_REG);

  // Wait for the command to be processed
  while(command[0]) {
    accessW6100(READ, Sn_CR, command, 1, socket, Sn_REG);
  }

  // Check the status register
  uint8_t statusBuffer[1];
  accessW6100(READ, Sn_SR, statusBuffer, 1, socket, Sn_REG);

  return (SocketState)statusBuffer[0];
}

/*
 * Sets socket `socket` to TCP mode using IPv4, sets the port
 * number, sets the socet to open, and waits for the socket
 * to finish opening.
 */
SocketState openSocket(Socket socket, uint16_t port) {
  // Read-modify-write mode register
  uint8_t socketMode[1];
  accessW6100(READ, Sn_MR, socketMode, 1, socket, Sn_REG);
  socketMode[0] = (socketMode[0] & 0xF0) | PM_TCP4;
  accessW6100(WRITE, Sn_MR, socketMode, 1, socket, Sn_REG);

  // Set the port
  uint8_t portBuffer[2];
  portBuffer[0] = (uint8_t)(port >> 8);
  portBuffer[1] = (uint8_t)(port & 0xFF);
  accessW6100(WRITE, Sn_PORTR, portBuffer, 2, socket, Sn_REG);

  // Send the open command
  uint8_t command[] = {CMD_OPEN};
  accessW6100(WRITE, Sn_CR, command, 1, socket, Sn_REG);

  // Wait for the command to be processed
  while(command[0]) {
    accessW6100(READ, Sn_CR, command, 1, socket, Sn_REG);
  }

  // Check the status register
  uint8_t statusBuffer[1];
  accessW6100(READ, Sn_SR, statusBuffer, 1, socket, Sn_REG);

  return (SocketState)statusBuffer[0];
}

/*
 * Unlocks the network config, sets the given parameters,
 * then locks it again.
 */
void setNetworkConfig(uint8_t sourceHWAddress[], uint8_t gateway[], uint8_t subnet[], uint8_t sourceIPAddress[]) {
  uint8_t lock[] = {NETLCK_UNLOCK};
  accessW6100(WRITE, NETLCKR, lock,            1, CONTROL_REG, CR);
  accessW6100(WRITE, SHAR,    sourceHWAddress, 6, CONTROL_REG, CR);
  accessW6100(WRITE, GAR,     gateway,         4, CONTROL_REG, CR);
  accessW6100(WRITE, SUBR,    subnet,          4, CONTROL_REG, CR);
  accessW6100(WRITE, SIPR,    sourceIPAddress, 4, CONTROL_REG, CR);
  lock[0] = NETLCK_LOCK;
  accessW6100(WRITE, NETLCKR, lock,            1, CONTROL_REG, CR);
}

/*
 * Sets the buffer sizes for socket `socketNum` to `socketSize`.
 */
void setSocketSize(Socket socket, SocketSize socketSize) {
  uint8_t socketSizeBuffer[] = {socketSize};
  accessW6100(WRITE, Sn_TX_BSR, socketSizeBuffer, 1, socket, Sn_REG);
  accessW6100(WRITE, Sn_RX_BSR, socketSizeBuffer, 1, socket, Sn_REG);
}

/*
 * Returns the appropriate control byte based on the given parameters.
 * The returned byte should be transmitted to the W6100 third (after
 * the two address bytes).
 */
uint8_t controlByte(Socket socket, BlockSelect blockSelect, RW rw)/*, Opcode opcode*/ {
  // Always use VDM
  Opcode opcode = VDM;
  
  return (socket << 5) | (blockSelect << 3) | (rw << 2) | opcode;
}

/*
 * Resets the chip to initial register values.
 */
void resetW6100() {
  // Unlock the chip
  uint8_t lock[] = {CHPLCK_UNLOCK};
  accessW6100(WRITE, CHPLCKR, lock, 1, CONTROL_REG, CR);

  // Set the reset flag, then read it (for delay)
  uint8_t resetBuffer[] = {W6100_RESET};
  accessW6100(WRITE, SYCR0, resetBuffer, 1, CONTROL_REG, CR);
  accessW6100(READ, SYCR0, resetBuffer, 1, CONTROL_REG, CR);

  // Lock the chip
  lock[0] = CHPLCK_LOCK;
  accessW6100(WRITE, CHPLCKR, lock, 1, CONTROL_REG, CR);
}

/*
 * Read or write `len` bytes of data from the W6100 from
 * `address` into `dataBuffer` using `contol` parameters.
 * 
 * The control mode must be consistent with `len`, i.e. in
 * fixed data mode, `len` must match with the control opcode.
 */
void accessW6100(RW rw, uint16_t address, uint8_t dataBuffer[], int len, Socket socket, BlockSelect blockSelect) {
  uint8_t control = controlByte(socket, blockSelect, rw);
  uint8_t command[3];
  command[0] = (uint8_t)(address >> 8);
  command[1] = (uint8_t)(address & 0xFF);
  command[2] = control;
  SPI.beginTransaction(W6100_SETTINGS);
  digitalWrite(W6100_CS_PIN, LOW);
  SPI.transfer(command, 3);
  SPI.transfer(dataBuffer, len);
  digitalWrite(W6100_CS_PIN, HIGH);
  SPI.endTransaction();
}

void printArray(uint8_t arr[], int len) {
  for(int i = 0; i < len - 1; i++) {
    Serial.print(arr[i], HEX);
    Serial.print(",");
  }
  Serial.println(arr[len - 1], HEX);
}
  
void loop() {
}

void error(const char* message) {
  Serial.println(message);
  delay(1000);
  exit(1);
}

constants.h

// W6100 CHIP SELECT PIN
#define W6100_CS_PIN      10
#define W6100_INT_PIN    9

// TOTAL SOCKETS
#define NUM_SOCKETS           0x8

// MAX SIZE OF ONE BUFFER
#define SOCKET_BUFFER_SIZE    0x07FF

// NETWORK LOCK
#define NETLCK_LOCK     0x3A
#define NETLCK_UNLOCK   0xC5

// CHIP LOCK
#define CHPLCK_LOCK     0xCE
#define CHPLCK_UNLOCK   0x00

// SW RESET
#define W6100_RESET   0x00

typedef enum BlockSelect {
  CR     = 0x0,
  Sn_REG = 0x1,
  Sn_TX  = 0x2,
  Sn_RX  = 0x3,
} BlockSelect;

typedef enum Socket {
  CONTROL_REG = 0x0,
  SOCKET_0    = 0x0,
  SOCKET_1    = 0x1,
  SOCKET_2    = 0x2,
  SOCKET_3    = 0x3,
  SOCKET_4    = 0x4,
  SOCKET_5    = 0x5,
  SOCKET_6    = 0x6,
  SOCKET_7    = 0x7,
} Socket;

typedef enum RW {
  READ  = 0x0,
  WRITE = 0x1,
} RW;

typedef enum Opcode {
  VDM   = 0x0,
  FDM_1 = 0x1,
  FDM_2 = 0x2,
  FDM_4 = 0x3,
} Opcode;

typedef enum SocketSize {
  SOCKET_0KB  = 0x00,
  SOCKET_1KB  = 0x01,
  SOCKET_2KB  = 0x02,
  SOCKET_4KB  = 0x04,
  SOCKET_8KB  = 0x08,
  SOCKET_16KB = 0x10,
} SocketSize;

typedef enum SocketCommand {
  CMD_OPEN      = 0x01,
  CMD_LISTEN    = 0x02,
  CMD_CONNECT   = 0x04,
  CMD_CONNECT6  = 0x84,
  CMD_DISCON    = 0x08,
  CMD_CLOSE     = 0x10,
  CMD_SEND      = 0x20,
  CMD_SEND6     = 0xA0,
  CMD_SEND_KEEP = 0x22,
  CMD_RECV      = 0x40,
} SocketCommand;

typedef enum ProtocolMode {
  PM_CLOSED = 0x0,
  PM_TCP4   = 0x1,
  PM_UDP4   = 0x2,
  PM_IPRAW4 = 0x3,
  PM_MACRAW = 0x7,
  PM_TCP6   = 0x9,
  PM_UDP6   = 0xA,
  PM_IPRAW6 = 0xB,
  PM_TCPD   = 0xD,
  PM_UDPD   = 0xE,
} ProtocolMode;

typedef enum SocketState {
  SOCK_CLOSED      = 0x00,
  SOCK_INIT        = 0x13,
  SOCK_LISTEN      = 0x14,
  SOCK_SYNSENT     = 0x15,
  SOCK_SYNRECV     = 0x16,
  SOCK_ESTABLISHED = 0x17,
  SOCK_FIN_WAIT    = 0x18,
  SOCK_TIME_WAIT   = 0x1B,
  SOCK_CLOSE_WAIT  = 0x1C,
  SOCK_LAST_ACK    = 0x1D,
  SOCK_UDP         = 0x22,
  SOCK_IPRAW       = 0x32,
  SOCK_MACRAW      = 0x42,
  SOCK_IPRAW6      = 0x33,
} SocketState;

typedef enum SocketRegister {
  Sn_MR      = 0x0000,
  Sn_PSR     = 0x0004,
  Sn_CR      = 0x0010,
  Sn_IR      = 0x0020,
  Sn_IMR     = 0x0024,
  Sn_IRCLR   = 0x0028,
  Sn_SR      = 0x0030,
  Sn_ESR     = 0x0031,
  Sn_PNR     = 0x0100,
  Sn_TOSR    = 0x0104,
  Sn_TTLR    = 0x0108,
  Sn_FRGR    = 0x010C,
  Sn_MSSR    = 0x0110,
  Sn_PORTR   = 0x0114,
  Sn_DHAR    = 0x0118,
  Sn_DIPR    = 0x0120,
  Sn_DIP6R   = 0x0130,
  Sn_DPORTR  = 0x0140,
  Sn_MR2     = 0x0144,
  Sn_RTR     = 0x0180,
  Sn_RCR     = 0x0184,
  Sn_KPALVTR = 0x0188,
  Sn_TX_BSR  = 0x0200,
  Sn_TX_FSR  = 0x0204,
  Sn_TX_RD   = 0x0208,
  Sn_TX_WR   = 0x020C,
  Sn_RX_BSR  = 0x0220,
  Sn_RX_FSR  = 0x0224,
  Sn_RX_RD   = 0x0228,
  Sn_RX_WR   = 0x022C,
} SocketRegister;

typedef enum ControlRegister {
  CIDR      = 0x0000,
  VER       = 0x0002,
  SYSR      = 0x2000,
  SYCR0     = 0x2004,
  SYCR1     = 0x2005,
  TCNTR     = 0x2016,
  TCNTRCLR  = 0x2020,
  IR        = 0x2100,
  SIR       = 0x2101,
  SLIR      = 0x2102,
  IMR       = 0x2104,
  IRCLR     = 0x2108,
  SIMR      = 0x2114,
  SLIMR     = 0x2124,
  SLIRCLR   = 0x2128,
  SLPSR     = 0x212C,
  SLCR      = 0x2130,
  PHYSR     = 0x3000,
  PHYRAR    = 0x3008,
  PHYDIR    = 0x300C,
  PHYDOR    = 0x3010,
  PHYACR    = 0x3014,
  PHYDIVR   = 0x3018,
  PHYCR0    = 0x301C,
  PHYCR1    = 0x301D,
  NET4MR    = 0x4000,
  NET6MR    = 0x4004,
  NETMR     = 0x4008,
  NETMR2    = 0x4009,
  PTMR      = 0x4100,
  PMNR      = 0x4104,
  PHAR      = 0x4108,
  PSIDR     = 0x4110,
  PMRUR     = 0x4114,
  SHAR      = 0x4120,
  GAR       = 0x4130,
  SUBR      = 0x4134,
  SIPR      = 0x4138,
  LLAR      = 0x4140,
  GUAR      = 0x4150,
  SUB6R     = 0x4160,
  GA6R      = 0x4170,
  SLDIP6R   = 0x4180,
  SLDIPR    = 0x418C,
  SLDHAR    = 0x4190,
  PINGIDR   = 0x4198,
  PINGSEQR  = 0x419C,
  UIPR      = 0x41A0,
  UPORTR    = 0x41A4,
  UIP6R     = 0x41B0,
  UPORT6R   = 0x41C0,
  INTPTMR   = 0x41C5,
  PLR       = 0x41D0,
  PFR       = 0x41D4,
  VLTR      = 0x41D8,
  PLTR      = 0x41DC,
  PAR       = 0x41E0,
  ICMP6BLKR = 0x41F0,
  CHPLCKR   = 0x41F4,
  NETLCKR   = 0x41F5,
  PHYLCKR   = 0x41F6,
  RTR       = 0x4200,
  RCR       = 0x4204,
  SLRTR     = 0x4208,
  SLRCR     = 0x420C,
  SLHOPR    = 0x420F,
} ControlRegister;

typedef enum IRMask {
  IRMASK_CON     = 0x01,
  IRMASK_DISCON  = 0x02,
  IRMASK_RECV    = 0x04,
  IRMASK_TIMEOUT = 0x08,
  IRMASK_SENDOK  = 0x10,
} IRMask;

If there is anyone who has any ideas of what to try, please let me know. Thanks.

Update: I have now used Wireshark to view the packets being sent by the Hercules Setup Utility, and it seems that Hercules only sends the requests over wi-fi, not Ethernet. When I click “Connect” in Hercules, Wireshark shows a connection packet coming through on the wi-fi monitor, but not on the Ethernet monitor… I can’t find any info on how to fix this.

Update2: I was able to send raw Ethernet packets through my Ethernet adapter by using a Linux VM and inspect them with Wireshark. I will try to see if that can trigger the interrupt in my Arduino version.

Update3: Sending raw packets to the correct MAC address (11:22:33:aa:bb:cc in this case) and the correct IP address (192.168.1.99 in this case) still did not trigger the interrupt on the W6100 for the Arduino version.

7 of Steps with io6Library:
What you saw through serial is the W6100’s information.
IP address mean the W6100’s IP address(192.168.0.13) and it is no the IP address of PC.
Therefore the 9 of Steps with io6Library is set incorrectly.
If you use dynamic address(DHCP), you have to use DHCP the W6100 and PC.

You have to download the arduino ethernet library for W6100 and Of the branch, the W6100 branch value should be apply and download.
This link is arduino ethernet library for W6100 : W6100 Arduino Ethernet library

1 Like

I know that step 7 is showing the W6100 IP address. In this page, it says to set the PC address and the W6100 address to the same thing. For DHCP, the option for “obtain an IP address automatically” should be set in the network adapter options, but then how do I know what the IP address is?

I am looking into the Arduino library now.

In this page ,

Then, set your IP address and subnet mask as same as WIZ550io’s IP address and subnet mask.

This comment mean that same network area.
And If WIZ550io and PC set the same IP/subnet mask, they can’t communicate.

obtain an IP address automatically” should be set in the network adapter options, but then how do I know what the IP address is?

You need IP address for communicating. If you want to know that How do I set my computer to DHCP? If yes, you refer this link : Change TCP/IP settings

I tried using the new Arduino Ethernet library with a router in between the W6100 and the PC. The router’s IP address is 192.168.1.1, which I set as the DNS address and default gateway address. Using the Chat Server example, I was able to use Telnet to connect to the W6100. I then printed out every register in the W6100 by using VDM to read them all out and looked at the differences between the register state from my code and register state from the example code. I noticed that the subnet mask in the example was set to 255.255.0.0, whereas I had mine set to 255.255.255.0 instead.

After changing to the correct subnet mask, I am able to get the interrupt triggering in the non-library code version. However, I am still confused as to why the subnet mask has to be 255.255.0.0. As for the IP address and DCHP, I still don’t understand because I assign an IP address to my device, but then shouldn’t the DCHP re-assign it another address? I think I should read more about subnet masks and about DHCP.

Update: using 255.255.255.0 actually still works, but in my header file I had these lines:

// NETWORK LOCK
#define NETLCK_LOCK     0x3A
#define NETLCK_UNLOCK   0xC5

// CHIP LOCK
#define CHPLCK_LOCK     0xCE
#define CHPLCK_UNLOCK   0x00

which is backwards from how it is supposed to be. After fixing this issue, the registers are set correctly. The correct assignment looks like this:

// NETWORK LOCK
#define NETLCK_LOCK     0xC5
#define NETLCK_UNLOCK   0x3A

// CHIP LOCK
#define CHPLCK_LOCK     0x00
#define CHPLCK_UNLOCK   0xCE

I am now successfully sending and receiving data over Ethernet with the W6100. Thank you so much for your help!

I’m glad it all worked out for you, then
Please feel free to contact me if you have further question.

1 Like