Updated 9 Sep 2013
I received an email from Endres Puschner pointing out a bug in my web
browser sample project. The bug causes incorrect data exchanges
if you try to use multiple sockets. The bug (both Tx and Rx)
happens because the code for calculating the pointers into the device's
buffers does not adjust for the socket used.
Endres sent along a couple of patches for fixing the problem, which I'm
including here.
Note that I
have NOT made these changes to the code in the .zip file below!
This isn't because I don't trust Endres' work, but because I simply
don't have the time to track down the hardware, edit the code, and
validate the changes. But I also don't want you to struggle with
this bug if you want to use the sample project with multiple sockets.
So here are the changes proposed by Endres:
In
the function Send() in
w5100_webserv.c, change this line of code:
realaddr = W5100_TXBUFADDR + (offaddr &
W5100_TX_BUF_MASK); // calc W5100
physical buffer addr for this socket
to be this (changes in bold):
realaddr =
(W5100_TXBUFADDR + (0x0800 * sock)) + (offaddr &
W5100_TX_BUF_MASK); // calc
W5100 physical buffer addr for this socket
Similarly, in the function Receive() in w5100_webserv.c, change this
line of code:
realaddr = W5100_RXBUFADDR + (offaddr &
W5100_RX_BUF_MASK);
to be this
realaddr = (W5100_RXBUFADDR
+ (0x0800 * sock)) + (offaddr
& W5100_RX_BUF_MASK);
(Now that I look over my code, I see that I could have done a much
better job with these two loops. Hopefully the compiler will
optimize this. Next time I get some free time, I'll revisit these
routines...)
Thanks to Endres for finding this and taking the time to write back
with a solution.
I started playing with the W5100 chip a few months ago and like it a
lot. I built a test platform using an ATmega644p and connected
the W5100 (on a WIZ811MJ development board) via SPI.
To start out, I loaded code from the
ermicroblog website.
The
code here was developed by RWB and made a terrific starting
point. I especially like the fact that RWB provides a complete
example, with every line of code provided; no header files that might
go missing and no background support code.
I reworked RWB's code to create a library for the W5100 device.
Note that this library is target-independent. This means you can
link any ATmega project against the library module without having to
rebuild the library because your hardware doesn't match my
original. This independence is done with a routine called
W51_register(), which allows your program to pass a set of function
pointers to the library for handling target-specific tasks, such as
enabling/disabling the W5100 chip and exchanging data with the device.
The W5100 library code
Below is the code for the W5100 library module. Unlike RWB's
code, my code uses a header file (derived from RWB's code and from the
Wiznet data sheet); you can find the header file in the .zip file at
the end of this page.
/*
* w5100.c library of
target-independent AVR support routines
*
for
the Wiznet W5100 Ethernet interface device
*
* This file is derived from the excellent work found here:
* www.ermicro.com/blog/?p=1773
* by RWB. I am leaving the header from the original
file intact below,
* but you need to remember the rest of the source here is
fairly
* heavily modified. Go to the above site for the
original.
*/
/*****************************************************************************
// File Name : wiznetping.c
// Version : 1.0
// Description : Wiznet W5100
// Author : RWB
// Target : AVRJazz Mega168
Board
// Compiler : AVR-GCC 4.3.2; avr-libc
1.6.6 (WinAVR 20090313)
// IDE :
Atmel AVR Studio 4.17
// Programmer : AVRJazz Mega168 STK500 v2.0 Bootloader
//
:
AVR Visual Studio 4.17, STK500 programmer
// Last Updated : 01 July 2010
*****************************************************************************/
/*
* The following code turns the above wiznetping.c source
code into a
* generic library of W5100 support routines that are
target-independent.
* That is, you build this library for a generic AVR ATmega
device, then
* write your application to use the W51_xxx routines below
for accessing
* the W5100 chip. Because these routines are
target-independent, you
* never have to rebuild them just because you are moving
your code from,
* say, a 'mega128 to an 'xmega128a1 device.
*
* For this to work properly, your application must provide
three target-
* specific functions and must register the addresses of
those functions
* with the W5100 library at run-time. These functions
are:
*
* select
target-specific function for enabling the W5100 chip
* xchg target-specific
function for exchanging a byte with the W5100 chip
* deselect target-specific function for
disabling the W5100 chip
* reset
target-specific function for hardware reset of the W5100 chip
*
* Your application registers these three functions with the
W5100 library
* by invoking the W51_register() function. Your
application must make this
* call one time and must make this call before calling any
other W5100
* functions.
*/
#include <util/delay.h>
#include "w5100.h"
#ifndef FALSE
#define FALSE 0
#define TRUE !FALSE
#endif
/*
* Define the function pointers used to access the SPI port
assigned to the
* W5100 device. These pointers will be filled in at
run-time when the host
* calls W51_register().
*/
static void
(*select)(void) = (void *)0;
static unsigned char
(*xchg)(unsigned char val) = (void *)0;
static void
(*deselect)(void) = (void *)0;
static void
(*reset)(void)
= (void *)0;
static unsigned char
inited = FALSE;
void W51_register(W5100_CALLBACKS *pcallbacks)
{
select = pcallbacks->_select;
xchg = pcallbacks->_xchg;
deselect = pcallbacks->_deselect;
reset = pcallbacks->_reset;
inited = FALSE;
if ((select) && (xchg) &&
(deselect)) inited = TRUE; // these functions
must be valid
}
void W51_write(unsigned int addr, unsigned char data)
{
if (!inited) return;
// not set up, ignore request
select();
// enable the W5100 chip
xchg(W5100_WRITE_OPCODE);
// need to write a byte
xchg((addr & 0xff00) >>
8);
// send MSB of addr
xchg(addr & 0xff);
// send LSB
xchg(data);
// send the data
deselect();
// done with the chip
}
unsigned char W51_read(unsigned int addr)
{
unsigned char
val;
if (!inited) return 0;
// not set up, ignore request
select();
// enable the W5100 chip
xchg(W5100_READ_OPCODE);
// need to read a byte
xchg((addr & 0xff00) >>
8);
// send MSB of addr
xchg(addr & 0xff);
// send LSB
val = xchg(0x00);
// need to
send a dummy char to get response
deselect();
// done with the chip
return val;
// tell her what she's won
}
void W51_init(void)
{
if (reset) reset();
// if host provided a reset
function, use it
else
W51_write(W5100_MR, W5100_MR_SOFTRST);
// otherwise, force the w5100 to soft-reset
_delay_ms(1);
}
unsigned char W51_config(W5100_CFG *pcfg)
{
if (pcfg == 0) return W5100_FAIL;
W51_write(W5100_GAR + 0,
pcfg->gtw_addr[0]); // set up the gateway address
W51_write(W5100_GAR + 1, pcfg->gtw_addr[1]);
W51_write(W5100_GAR + 2, pcfg->gtw_addr[2]);
W51_write(W5100_GAR + 3, pcfg->gtw_addr[3]);
_delay_ms(1);
W51_write(W5100_SHAR + 0,
pcfg->mac_addr[0]); // set up the MAC address
W51_write(W5100_SHAR + 1, pcfg->mac_addr[1]);
W51_write(W5100_SHAR + 2, pcfg->mac_addr[2]);
W51_write(W5100_SHAR + 3, pcfg->mac_addr[3]);
W51_write(W5100_SHAR + 4, pcfg->mac_addr[4]);
W51_write(W5100_SHAR + 5, pcfg->mac_addr[5]);
_delay_ms(1);
W51_write(W5100_SUBR + 0,
pcfg->sub_mask[0]); // set up the subnet mask
W51_write(W5100_SUBR + 1, pcfg->sub_mask[1]);
W51_write(W5100_SUBR + 2, pcfg->sub_mask[2]);
W51_write(W5100_SUBR + 3, pcfg->sub_mask[3]);
_delay_ms(1);
W51_write(W5100_SIPR + 0,
pcfg->ip_addr[0]); // set up the source IP address
W51_write(W5100_SIPR + 1, pcfg->ip_addr[1]);
W51_write(W5100_SIPR + 2, pcfg->ip_addr[2]);
W51_write(W5100_SIPR + 3, pcfg->ip_addr[3]);
_delay_ms(1);
W51_write(W5100_RMSR, 0x55);
// use default buffer sizes (2K bytes RX and TX for
each socket
W51_write(W5100_TMSR, 0x55);
return W5100_OK;
// everything worked, show success
}
Using the library
To use this library, create a new AVRStudio4 project and add the
w5100.h header file to your project (remember to change your project's
configuration to include the path to the folder holding the w5100.h
file). Also change your project's configuration to add the w5100
library, so the linker can find the library when you build your project.
In your source, you will need to write three (optionally, four)
target-specific routines. The three required routines provide SPI
access to your board's W5100 chip via SPI. The select() routine
sets the correct port line to select the W5100 device. The
deselect() routine changes the port line to deselect the W5100
device. The xchg() routine sends a byte of data to the W5100 via
SPI and simultaneously receives a byte, returning that byte to the
calling routine. Optionally, you may also provide a reset()
routine that uses a port line to perform a hardware reset of the W5100
device. I strongly urge you to provide such a feature in your
hardware, as I have had issues with the W5100 starting up properly if I
don't do a hardware reset.
A sample project (web server)
The code below is a sample web server built with the library above.
#include <avr/io.h>
#include <string.h>
#include <stdio.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include "w5100.h"
unsigned char
OpenSocket(unsigned char
sock, unsigned char eth_protocol, unsigned int tcp_port);
void
CloseSocket(unsigned char sock);
void
DisconnectSocket(unsigned char sock);
unsigned char
Listen(unsigned char sock);
unsigned char
Send(unsigned char sock,
const unsigned char *buf, unsigned int buflen);
unsigned int
Receive(unsigned char sock,
unsigned char *buf, unsigned int buflen);
unsigned int
ReceivedSize(unsigned char
sock);
void
my_select(void);
void
my_deselect(void);
unsigned char
my_xchg(unsigned char val);
void
my_reset(void);
#define
MAX_BUF
512
/* largest buffer we can read
from chip */
#define
HTTP_PORT
80
/* TCP port for HTTP */
/*
* Ethernet setup
*
* Define the MAC
address, IP address, subnet mask, and gateway
* address for the
target device.
*/
W5100_CFG
my_cfg =
{
{0x00,0x16,0x36,0xDE,0x58,0xF6},
// mac_addr
{192,168,1,233},
// ip_addr
{255,255,255,0},
// sub_mask
{192,168,1,1}
// gtw_addr
};
/*
* Callback function
block
*
* Define callback
functions for target-independent support of the
* W5100 chip.
Here is where you store pointers to the various
* functions needed by
the W5100 library code. These functions all
* handle tasks that
are target-dependent, which means the library
* code can be
target-INdependent.
*/
W5100_CALLBACKS
my_callbacks;
unsigned char
buf[MAX_BUF];
unsigned char
OpenSocket(unsigned char sock, unsigned char eth_protocol,
unsigned int tcp_port)
{
unsigned
char retval;
unsigned
int sockaddr;
retval =
W5100_FAIL;
// assume this doesn't work
if (sock >=
W5100_NUM_SOCKETS) return retval; // illegal
socket value is bad!
sockaddr
= W5100_SKT_BASE(sock);
// calc base addr for this socket
if
(W51_read(sockaddr+W5100_SR_OFFSET) ==
W5100_SKT_SR_CLOSED) // Make sure we close the socket
first
{
CloseSocket(sock);
}
W51_write(sockaddr+W5100_MR_OFFSET ,eth_protocol);
// set protocol for this socket
W51_write(sockaddr+W5100_PORT_OFFSET, ((tcp_port & 0xFF00) >>
8 )); // set port for this socket
(MSB)
W51_write(sockaddr+W5100_PORT_OFFSET + 1, (tcp_port &
0x00FF)); //
set port for this socket (LSB)
W51_write(sockaddr+W5100_CR_OFFSET,
W5100_SKT_CR_OPEN);
// open the socket
while
(W51_read(sockaddr+W5100_CR_OFFSET)) ;
// loop until device reports
socket is open (blocks!!)
if
(W51_read(sockaddr+W5100_SR_OFFSET) == W5100_SKT_SR_INIT) retval
= sock; // if success, return socket number
else
CloseSocket(sock);
// if failed,
close socket immediately
return
retval;
}
void CloseSocket(unsigned
char sock)
{
unsigned
int sockaddr;
if (sock >
W5100_NUM_SOCKETS) return;
// if illegal socket number, ignore request
sockaddr =
W5100_SKT_BASE(sock);
// calc base addr for this socket
W51_write(sockaddr+W5100_CR_OFFSET,
W5100_SKT_CR_CLOSE); // tell chip to close the socket
while
(W51_read(sockaddr+W5100_CR_OFFSET)) ; // loop
until socket is closed (blocks!!)
}
void
DisconnectSocket(unsigned char sock)
{
unsigned
int sockaddr;
if (sock >
W5100_NUM_SOCKETS) return;
// if illegal socket number, ignore request
sockaddr =
W5100_SKT_BASE(sock);
// calc base addr for this socket
W51_write(sockaddr+W5100_CR_OFFSET,
W5100_SKT_CR_DISCON); //
disconnect the socket
while
(W51_read(sockaddr+W5100_CR_OFFSET)) ; // loop
until socket is closed (blocks!!)
}
unsigned char
Listen(unsigned char sock)
{
unsigned
char retval;
unsigned
int sockaddr;
retval =
W5100_FAIL;
// assume this fails
if (sock >
W5100_NUM_SOCKETS) return retval; // if
illegal socket number, ignore request
sockaddr =
W5100_SKT_BASE(sock);
// calc base addr for this socket
if
(W51_read(sockaddr+W5100_SR_OFFSET) ==
W5100_SKT_SR_INIT) // if socket is in initialized
state...
{
W51_write(sockaddr+W5100_CR_OFFSET,
W5100_SKT_CR_LISTEN); // put
socket in listen state
while (W51_read(sockaddr+W5100_CR_OFFSET))
; // block until command is
accepted
if (W51_read(sockaddr+W5100_SR_OFFSET) ==
W5100_SKT_SR_LISTEN) retval = W5100_OK; // if
socket state changed, show success
else CloseSocket(sock);
// not in listen mode, close and show an error
occurred
}
return
retval;
}
unsigned char Send(unsigned
char sock, const unsigned char *buf, unsigned int
buflen)
{
unsigned
int
ptr;
unsigned
int
offaddr;
unsigned
int
realaddr;
unsigned
int
txsize;
unsigned
int
timeout;
unsigned
int
sockaddr;
if (buflen ==
0 || sock >= W5100_NUM_SOCKETS) return
W5100_FAIL; // ignore illegal
requests
sockaddr =
W5100_SKT_BASE(sock);
// calc base addr for this socket
// Make sure
the TX Free Size Register is available
txsize =
W51_read(sockaddr+W5100_TX_FSR_OFFSET);
// make sure the TX free-size reg is available
txsize =
(((txsize & 0x00FF) << 8 ) +
W51_read(sockaddr+W5100_TX_FSR_OFFSET + 1));
timeout = 0;
while (txsize
< buflen)
{
_delay_ms(1);
txsize =
W51_read(sockaddr+W5100_TX_FSR_OFFSET);
// make sure the TX free-size reg is available
txsize = (((txsize & 0x00FF) << 8 ) +
W51_read(sockaddr+W5100_TX_FSR_OFFSET + 1));
if (timeout++ > 1000)
// if max delay has passed...
{
DisconnectSocket(sock);
// can't
connect, close it down
return
W5100_FAIL;
// show failure
}
}
// Read the Tx Write
Pointer
ptr =
W51_read(sockaddr+W5100_TX_WR_OFFSET);
offaddr =
(((ptr & 0x00FF) << 8 ) +
W51_read(sockaddr+W5100_TX_WR_OFFSET + 1));
while (buflen)
{
buflen--;
realaddr = W5100_TXBUFADDR + (offaddr &
W5100_TX_BUF_MASK); // calc W5100
physical buffer addr for this socket
W51_write(realaddr, *buf);
// send a byte of application data to TX buffer
offaddr++;
// next TX buffer addr
buf++;
// next input buffer addr
}
W51_write(sockaddr+W5100_TX_WR_OFFSET, (offaddr & 0xFF00) >>
8); // send MSB of new write-pointer addr
W51_write(sockaddr+W5100_TX_WR_OFFSET + 1, (offaddr &
0x00FF)); // send
LSB
W51_write(sockaddr+W5100_CR_OFFSET,
W5100_SKT_CR_SEND); // start the send on its way
while
(W51_read(sockaddr+W5100_CR_OFFSET)) ; // loop
until socket starts the send (blocks!!)
return
W5100_OK;
}
/*
* Define the SPI
port, used to exchange data with a W5100 chip.
*/
#define SPI_PORT
PORTB
/* target-specific port
containing the SPI lines */
#define SPI_DDR
DDRB
/* target-specific DDR for the
SPI port lines */
#define CS_DDR
DDRD
/* target-specific DDR for
chip-select */
#define CS_PORT
PORTD
/* target-specific port used as
chip-select */
#define CS_BIT
2
/*
target-specific port line used as chip-select */
#define RESET_DDR
DDRD
/* target-specific DDR for reset */
#define
RESET_PORT PORTD
/* target-specific port used for
reset */
#define
RESET_BIT 3
/*
target-specific port line used as reset */
/*
* Define macros for
selecting and deselecting the W5100 device.
*/
#define
W51_ENABLE
CS_PORT&=~(1<<CS_BIT)
#define
W51_DISABLE CS_PORT|=(1<<CS_BIT)
unsigned int
Receive(unsigned char sock, unsigned char *buf, unsigned
int buflen)
{
unsigned
int
ptr;
unsigned
int
offaddr;
unsigned
int
realaddr;
unsigned
int
sockaddr;
if (buflen ==
0 || sock >= W5100_NUM_SOCKETS) return
W5100_FAIL; // ignore illegal
conditions
if (buflen
> (MAX_BUF-2)) buflen = MAX_BUF - 2;
// requests that exceed the max are truncated
sockaddr =
W5100_SKT_BASE(sock);
// calc base addr for this socket
ptr =
W51_read(sockaddr+W5100_RX_RD_OFFSET);
// get the RX read pointer (MSB)
offaddr =
(((ptr & 0x00FF) << 8 ) +
W51_read(sockaddr+W5100_RX_RD_OFFSET + 1));
// get LSB and calc offset addr
while (buflen)
{
buflen--;
realaddr = W5100_RXBUFADDR + (offaddr &
W5100_RX_BUF_MASK);
*buf = W51_read(realaddr);
offaddr++;
buf++;
}
*buf='\0';
// buffer read
is complete, terminate the string
// Increase
the S0_RX_RD value, so it point to the next receive
W51_write(sockaddr+W5100_RX_RD_OFFSET, (offaddr & 0xFF00) >>
8); // update RX read offset (MSB)
W51_write(sockaddr+W5100_RX_RD_OFFSET + 1,(offaddr &
0x00FF)); // update LSB
// Now Send
the RECV command
W51_write(sockaddr+W5100_CR_OFFSET,
W5100_SKT_CR_RECV);
// issue the receive command
_delay_us(5);
// wait for receive to start
return
W5100_OK;
}
unsigned int
ReceivedSize(unsigned char sock)
{
unsigned
int
val;
unsigned
int
sockaddr;
if (sock >=
W5100_NUM_SOCKETS) return 0;
sockaddr =
W5100_SKT_BASE(sock);
// calc base addr for this socket
val =
W51_read(sockaddr+W5100_RX_RSR_OFFSET) & 0xff;
val = (val
<< 8) + W51_read(sockaddr+W5100_RX_RSR_OFFSET + 1);
return
val;
}
/*
* Simple wrapper
function for selecting the W5100 device. This function
* allows the library
code to invoke a target-specific function for enabling
* the W5100 chip.
*/
void my_select(void)
{
W51_ENABLE;
}
/*
* Simple wrapper
function for deselecting the W5100 device. This function
* allows the library
code to invoke a target-specific function for disabling
* the W5100 chip.
*/
void my_deselect(void)
{
W51_DISABLE;
}
/*
*
my_xchg callback function; exchanges a
byte with W5100 chip
*/
unsigned char
my_xchg(unsigned char val)
{
SPDR = val;
while
(!(SPSR & (1<<SPIF))) ;
return
SPDR;
}
/*
*
my_reset callback function; force a
hardware reset of the W5100 device
*/
void my_reset(void)
{
RESET_PORT |=
(1<<RESET_BIT);
// pull reset line high
RESET_DDR |=
(1<<RESET_BIT);
// now make it an output
RESET_PORT
&= ~(1<<RESET_BIT);
// pull the line low
_delay_ms(5);
// let the device reset
RESET_PORT |=
(1<<RESET_BIT);
// done with reset, pull the line
high
_delay_ms(10);
// let the chip wake up
}
int main(void)
{
unsigned
int
sockaddr;
unsigned
char
mysocket;
unsigned
int
rsize;
mysocket =
0;
// magic number! declare the
socket number we will use (0-3)
sockaddr =
W5100_SKT_BASE(mysocket);
// calc
address of W5100 register set for this socket
/*
* Initialize the
ATmega644p SPI subsystem
*/
CS_PORT |=
(1<<CS_BIT);
// pull CS pin high
CS_DDR |=
(1<<CS_BIT);
// now make it an output
SPI_PORT =
SPI_PORT | (1<<PORTB4);
// make sure SS is high
SPI_DDR =
(1<<PORTB4)|(1<<PORTB5)|(1<<PORTB7);
// set MOSI, SCK and SS as
output, others as input
SPCR =
(1<<SPE)|(1<<MSTR);
// enable SPI,
master mode 0
SPSR |=
(1<<SPI2X);
// set the clock rate fck/2
/*
* Load up the
callback block, then initialize the Wiznet W5100
*/
my_callbacks._select = &my_select;
// callback for selecting the
W5100
my_callbacks._xchg = &my_xchg;
// callback for exchanging data
my_callbacks._deselect = &my_deselect;
// callback for deselecting the W5100
my_callbacks._reset = &my_reset;
// callback for hardware-reset of
the W5100
W51_register(&my_callbacks);
// register our target-specific
W5100 routines with the W5100 library
W51_init();
// now
initialize the W5100
/*
* Configure the W5100
device to handle PING requests.
* This requires
configuring the chip, not a specific socket.
*/
W51_config(&my_cfg);
// config the W5100 (MAC, TCP address, subnet, etc
/*
* The main
loop. Control stays in this loop forever, processing any received
packets
* and sending any
requested data.
*/
while (1)
{
switch
(W51_read(sockaddr+W5100_SR_OFFSET))
// based on current status of socket...
{
case
W5100_SKT_SR_CLOSED:
// if socket is closed...
if (OpenSocket(mysocket,
W5100_SKT_MR_TCP, HTTP_PORT) == mysocket)
// if successful opening a socket...
{
Listen(mysocket);
_delay_ms(1);
}
break;
case
W5100_SKT_SR_ESTABLISHED:
// if socket
connection is established...
rsize =
ReceivedSize(mysocket);
// find out
how many bytes
if (rsize > 0)
{
if
(Receive(mysocket, buf, rsize) != W5100_OK)
break; // if we had problems, all done
/*
* Add code here to
process the payload from the packet.
*
* For now, we just
ignore the payload and send a canned HTML page so the client at least
* knows we are alive.
*/
strcpy_P((char
*)buf, PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma:
no-cache\r\n\r\n"));
strcat_P((char
*)buf, PSTR("<html>\r\n<body>\r\n"));
strcat_P((char
*)buf, PSTR("<title>Karl's W5100 web server
(ATmega644p)</title>\r\n"));
strcat_P((char
*)buf, PSTR("<h2>Karl's ATmega644p web server using Wiznet W5100
chip</h2>\r\n"));
strcat_P((char
*)buf, PSTR("<br /><hr>\r\n"));
if
(Send(mysocket, buf, strlen((char *)buf)) == W5100_FAIL)
break; // just throw out the
packet for now
strcpy_P((char
*)buf, PSTR("This is part 2 of the page."));
strcat_P((char
*)buf, PSTR("</body>\r\n</html>\r\n"));
if
(Send(mysocket, buf, strlen((char *)buf)) == W5100_FAIL)
break; // just throw out the
packet for now
DisconnectSocket(mysocket);
}
else
// no data yet...
{
_delay_us(10);
}
break;
case W5100_SKT_SR_FIN_WAIT:
case W5100_SKT_SR_CLOSING:
case W5100_SKT_SR_TIME_WAIT:
case
W5100_SKT_SR_CLOSE_WAIT:
case W5100_SKT_SR_LAST_ACK:
CloseSocket(mysocket);
break;
}
}
return 0;
}
About the web server
The code above was modified from RWB's
original and is much more limited. Basically, the above code
doesn't even try to parse the HTTP packet received; it just throws out
the same fixed file. This is good enough to confirm the server is
working, but hardly makes a finished project. Look over RWB's
code and check out similar projects on the web for details on how to
parse the packets and create your own web server. Note also that
I've removed all of the USART routines from RWB's original.
I have also modified RWB's code so you can use any of the four W5100
sockets. The code has been tested using socket 0, but has not
been tested using other sockets or using multiple sockets
simultaneously.
The above code, plus the library code that gets linked in, yields a
final image of 2.4 KB. Yes, that is an ATmega644p web server in
under 2500 bytes of code!
To modify this code for your own use, you will need to recode the four
callback functions (just above main()) for your particular
hardware. You will also need to modify the entries in the
W5100_CFG structure to match your network; see the declaration of
my_cfg above. Finally, rebuild and link against the w5100 library
module and you should be good to go.
Here is the .zip file containing the
above code plus the w5100.h header file and a custom Makefile for
creating the w5100 library module. To use the Makefile, create an
AVRStudio4 project for the w5100 library, add the w5100.c file ahd
w5100.h header file, then invoke the Makefile from the Windows command
prompt as: make -f Makefile_library.mak
Home