Wiznet 5100 library for ATmega devices
(Last updated 9 Sep 2013)


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