Skip to content

In Which I Am Appalled, then Charmed, and Finally Pretty Darn Pleased

November 26, 2014

I quickly rewired the ioShield-A then started looking at the code. The C++ library for the Arduino seems over the top. There are hundreds of lines of classes and methods between you and the fact that an IP address is stored as an array of 4 unsigned chars. Don’t even get me started on the collision of W5500, W5200, and W5100. It worked on the arduino but trying to boil it down to C for the 1802 looked pretty daunting. What you see is just a couple of the high level modules. There wouldn’t have been enough paper in Ottawa to print out all the definitions and code.
14-11-26 c++

I went back and looked again at the logic analyzer output and thought about what a pleasant prospect it presented in comparison: What you see below is the Arduino writing the MAC address and really, what could be simpler: You select the module, send the address of the MAC register(00 09), send the code to write it(04), send the 6 bytes of data , and then deselect the module. Surely we don’t need hundreds or thousands of lines of code.
14-11-26 set mac

I abandoned the arduino code and grabbed my W5100 C code (which I originally found here for an AVR). The W5500 SPI frames are quite different but very easy to adapt to. If you only want to read or write one byte you just send address then opcode then data as opposed to opcode, address, then data for the W5100. If you’re sending multiple bytes it’s even simpler: you send the beginning address, then an op code, then stream data as long as you need to without deselecting the chip – I think the W5500 even handles wrapping the buffer address. Pretty sweet. With the W5100 you had to repeat the sequence for each byte adjusting and wrapping the address for each one.

To get a leg up, I tossed out all my W5100 code except what I would need to initialize the W5500 and read back the IP address to make sure it had “taken”. After a bit of arguing with the compiler – bingo, it worked:
14-11-26 Success

This is still the easy part: I wasn’t doing any error or timeout checking – just flinging bits at the module and reading them back. But I think the rest is just a small matter of programming.

The assembled module looks like this with the 1802 cpu board on the bottom, the olduino above that, then the ioShield-A, and finally the W5500 module. Definitely harks back to the Hardware Mountain setup but at least there’s no way to put anything on top!
14-11-26 success2

For my purposes, here’s some of the code:

//w5500.h - defines for wiznet w5500 data structures

// Wiznet W5500 Op Codes
#define WIZNET_WRITE_COMMON 0x04
#define WIZNET_READ_COMMON 0x00
#define WIZNET_WRITE_SOCKET0 0x0C
#define WIZNET_READ_SOCKET0 0x08
// Wiznet W5500 Register Addresses
#define MR     0x0000    // Mode
#define GAR    0x0001    // Gateway IP address
#define SUBR   0x0005    // Subnet mask address
#define SHAR   0x0009    // Source MAC address
#define SIPR   0x000F    // Source IP address
#define IR     0x0015    // Interrupt
#define IMR    0x0016    // Interrupt Mask
#define RTR    0x0019    // Timeout address
#define RCR    0x001B    // Retry count
#define UIPR   0x0028    // Unreachable IP address in UDP mode
#define UPORT  0x002C    // Unreachable Port address in UDP mode
//W5500 Socket Registers follow
#define SnMR        0x0000        // Mode
#define SnCR        0x0001        // Command
#define SnIR        0x0002        // Interrupt
#define SnSR        0x0003        // Status
#define SnPORT      0x0004        // Source Port
#define SnDHAR      0x0006      // Destination Hardw Addr
#define SnDIPR      0x000C      // Destination IP Addr
#define SnDPORT     0x0010        // Destination Port
#define SnMSSR      0x0012        // Max Segment Size
#define SnPROTO     0x0014        // Protocol in IP RAW Mode
#define SnTOS       0x0015        // IP TOS
#define SnTTL       0x0016        // IP TTL
#define SnTX_FSR    0x0020        // TX Free Size
#define SnTX_RD     0x0022        // TX Read Pointer
#define SnTX_WR     0x0024        // TX Write Pointer
#define SnRX_RSR    0x0026        // RX Free Size
#define SnRX_RD     0x0028        // RX Read Pointer
#define SnRX_WR     0x002A        // RX Write Pointer (supported?
// S0_MR values
#define MR_CLOSE	  0x00    // Unused socket
#define MR_TCP		  0x01    // TCP
#define MR_UDP		  0x02    // UDP
#define MR_IPRAW	  0x03	  // IP LAYER RAW SOCK
#define MR_MACRAW	  0x04	  // MAC LAYER RAW SOCK
#define MR_PPPOE	  0x05	  // PPPoE
#define MR_ND		  0x20	  // No Delayed Ack(TCP) flag
#define MR_MULTI	  0x80	  // support multicating
// S0_CR values
#define CR_OPEN          0x01	  // Initialize or open socket
#define CR_LISTEN        0x02	  // Wait connection request in tcp mode(Server mode)
#define CR_CONNECT       0x04	  // Send connection request in tcp mode(Client mode)
#define CR_DISCON        0x08	  // Send closing reqeuset in tcp mode
#define CR_CLOSE         0x10	  // Close socket
#define CR_SEND          0x20	  // Update Tx memory pointer and send data
#define CR_SEND_MAC      0x21	  // Send data with MAC address, so without ARP process
#define CR_SEND_KEEP     0x22	  // Send keep alive message
#define CR_RECV          0x40	  // Update Rx memory buffer pointer and receive data
// S0_SR values
#define SOCK_CLOSED      0x00     // Closed
#define SOCK_INIT        0x13	  // Init state
#define SOCK_LISTEN      0x14	  // Listen state
#define SOCK_SYNSENT     0x15	  // Connection state
#define SOCK_SYNRECV     0x16	  // Connection state
#define SOCK_ESTABLISHED 0x17	  // Success to connect
#define SOCK_FIN_WAIT    0x18	  // Closing state
#define SOCK_CLOSING     0x1A	  // Closing state
#define SOCK_TIME_WAIT	 0x1B	  // Closing state
#define SOCK_CLOSE_WAIT  0x1C	  // Closing state
#define SOCK_LAST_ACK    0x1D	  // Closing state
#define SOCK_UDP         0x22	  // UDP socket
#define SOCK_IPRAW       0x32	  // IP raw mode socket
#define SOCK_MACRAW      0x42	  // MAC raw mode socket
#define SOCK_PPPOE       0x5F	  // PPPOE socket

#define TCP_PORT         80       // TCP/IP Port
//14-11-26 w5500code.h - header for routines to address the wiznet w5500
#define disablewiz()   	asm("	ldad memaddr,_PIN4\n	ldn memaddr\n	ori 0x80\n	str memaddr\n" \
  							"	sex memaddr\n	out 4\n	sex 2\n"); //high level on 7(SS) disables the w5100 from the spi bus
#define enablewiz()  asm("	ldad memaddr,_PIN4\n	ldn memaddr\n	ani 0x7f\n	str memaddr\n" \
						"	sex memaddr\n	out 4\n	sex 2\n");
#define sendlit(x) send0((unsigned char*)x,sizeof(x)-1)
#define sendconst(x) send0((unsigned char*)x,sizeof(x)-1)
#define selectmask 0x7f;//turns off the top bit in the parallel port
#define deselectmask 0x80;//turns on the top bit in the parallel port

union IPaddr{
	long l;
	unsigned char c[4];
};

void wiz_WriteC(unsigned int addr,unsigned char data);
void wiz_WriteCN(unsigned int addr,unsigned char * data, unsigned int N);

unsigned char wiz_ReadC(unsigned int addr);

void wiz_Init(unsigned char ip_addr[]);// Ethernet Setup
//14-11-26 routines to address the wiznet w5500

void wiz_WriteC(unsigned int addr,unsigned char data) //write a general Register
{
  enablewiz();   			// Activate the CS pin
  spiSend(addr >>8); 		// Send Wiznet Address High Byte
  spiSend(addr & 0x00FF);	// Send Wiznet Address Low Byte
  spiSend(WIZNET_WRITE_COMMON);   // Send Wiznet Write OpCode
  spiSend(data);			// Send the data byte
  disablewiz();				// make CS pin not active
}
void wiz_WriteCN(unsigned int addr,unsigned char * data, unsigned int n) //write a general Register
{
  unsigned int i;
  enablewiz();   			// Activate the CS pin
  spiSend(addr >>8); 		// Send Wiznet Address High Byte
  spiSend(addr & 0x00FF);	// Send Wiznet Address Low Byte
  spiSend(WIZNET_WRITE_COMMON);   // Send Wiznet Write OpCode
  for (i=0;i<n;i++){ //variable length send
    spiSend(data[i]);			// Send the data byte
  }
  disablewiz();				// make CS pin not active
}
unsigned char wiz_ReadC(unsigned int addr)
{
  unsigned char value; 	//data returned from spi transmission
  enablewiz();   		// Activate the CS pin
  spiSend(addr >>8);	// Send Wiznet Address High Byte
  spiSend(addr & 0x00FF);  // Send Wiznet Address Low Byte
  spiSend(WIZNET_READ_COMMON);   //Send Wiznet Write OpCode
  value=spixfer(0xff);	// Send Dummy transmission to read the data
  disablewiz();			// make CS pin inactive
  return(value);
}

void wiz_Init(unsigned char ip_addr[]){// Ethernet Setup
  unsigned char mac_addr[] = {0xDE, 0xAD, 0xBE, 0xE5, 0xFE, 0xED};
  unsigned char sub_mask[] = {255,255,255,0};
  unsigned char gtw_addr[] = {192,168,0,1};
  //set the wiznet gateway address register
  wiz_WriteCN(GAR,gtw_addr,4);
  delay(1);
  // Set the Wiznet W5500 MAC address - Source Address Register (SAR): 0x0009 to 0x000E
  wiz_WriteCN(SHAR,mac_addr,6);
  delay(1);
  // Set the Wiznet W5100 Sub Mask Address (SUBR): 0x0005 to 0x0008
  wiz_WriteCN(SUBR,sub_mask,4);
  delay(1);
  // Set the Wiznet W5100 IP Address (SIPR): 0x000F to 0x0012
  wiz_WriteCN(SIPR,ip_addr,4);
  delay(1);
  printf("Done Wiznet W5100 Initialization on IP address %d.%d.%d.%d\n\n",wiz_ReadC(SIPR + 0),wiz_ReadC(SIPR + 1),wiz_ReadC(SIPR + 2),wiz_ReadC(SIPR + 3));
}
Advertisements

From → web server

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: