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
- Download this repository as a .zip and extract it.
- Create a new project in KEIL uVision. Set up the MCU using CubeMX.
- 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). - Change all instances of
printf
tosprintf
followed by a call toHAL_UART_Transmit
so that it will work and I can see the print output over UART. - Copy the io6Library files and configure uVision to use them. Make sure everything compiles.
- 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.
- 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
- Great, it seems to be working. The debugger shows the code looping over the
loopback_tcps
function, and the state of theSn_SR
register is0x14
(SOCK_LISTEN
). Now it’s time to connect to that socket. - 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
- 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.
- It times out .
Steps without io6Library
- Write the code shown at the bottom of this post under the CODE tab.
- Open the code in Arduino IDE.
- Upload the code to a Sparkfun RedBoard.
- Connect the WIZ610io to the RedBoard (power, ground, MISO, MOSI, SCK, CS).
- Connect an Ethernet cable between the W6100 and the PC
- 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
...
- Try the same steps as above (steps 9 and 10)
- It times out . 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.