From a hardware standpoint, everything appears fine... but I've found a problem with the mikroC ethernet library while working on this project.
The web server broke down as I was building my server's web page, and so I went back to the example program to demonstrate the problem. You will notice that the attached program is just a simplified version of the ethernet example program. Perhaps I have tracked down enough information for ME to advise.
The example provided with the compiler works fine, but the web server responses that it provides are short and fit within one datagram.
But if the web server response exceeds ~1500 bytes (the Maximum Transmission Unit for ethernet), then the web server fails to respond correctly. Using a packet sniffer, I see "previous segment lost" errors.
I modified the source of the example to simply respond with web pages of different lengths so that you can see where it fails.
Anyone else trying this should only have to modify the arguments to the Spi_Ethernet_Init() call to reflect the ports on whatever development hardware you are using... and you will also have to modify the IP address to fit your router configuration.
Then, use the following request format:
http://192.168.1.160/n
(where n = the number of A's filled on the web page)
The server will always fail when n>1285 (and total bytes>1460).
For n<=1285, the server works excellent.
I hope this helps all you other mikroC/EasyPIC users and ME.... and if I can provide further info, I will be glad.
Code: Select all
/*
* Project Name:
Spi_EthernetDemo (Ethernet Library demo for ENC28J60 mcu)
* Target Platform:
PIC
* Copyright:
(c) mikroElektronika, 2006.
* Revision History:
20060810:
- Initial release. Author: Bruno Gavand.
*
* V1.0 : first release
* V1.1 : bad MIME type for / path request, changed to HTML instead of SCRIPT (thanks Srdjan !)
*
* description :
* this code shows how to use the Spi_Ethernet mini library :
* the board will reply to ARP & ICMP echo requests
* the board will reply to UDP requests on any port :
* returns the request in upper char with a header made of remote host IP & port number
* the board will reply to HTTP requests on port 80, GET method with pathnames :
* / will return the HTML main page
* /s will return board status as text string
* /t0 ... /t7 will toggle RC0 to RC7 bit and return HTML main page
* all other requests return also HTML main page
*
* target devices :
* any PIC with integrated SPI and more than 4 Kb ROM memory
* 32 to 40 MHz clock is recommended to get from 8 to 10 Mhz SPI clock,
* otherwise PIC should be clocked by ENC clock output due to ENC silicon bug in SPI hardware
* if you try lower PIC clock speed, don't be surprised if the board hang or miss some requests !
* tested with PIC16F877A@10Mhz, PIC18F452@40Mhz on EasyPIC3 board
*
*
* EP settings :
* RA2 & RA3 pots jumper : closed
* PORTB : pull-down
* PORTC : pull-down
* BUTTONS : pull-up
*
* RC0 : !RESET to ENC reset input pin
* RC1 : !CS to ENC chip select input pin
* the ENC28J60 SPI bus CLK, SO, SI must be connected to the corresponding SPI pins of the PIC
* the INT and WOL signals from the ENC are not used
*
* Test configuration:
MCU: PIC18F452/PIC16F877A
Dev.Board: EasyPIC4
Oscillator: HS/PLL4, 10.000MHz
Ext. Modules: mE Serial Ethernet board
SW: mikroC v6.2.0.0.
* NOTES:
Make sure that you use right compiler version with this project
Renamed functions of Spi ethernet library from (v6.0)ENC28j60... to (v6.2)Spi_Ethernet...
*/
#define Spi_Ethernet_HALFDUPLEX 0
#define Spi_Ethernet_FULLDUPLEX 1
unsigned char httpMethod[] = "GET /";
/***********************************
* RAM variables
*/
unsigned char myMacAddr[6] = {0x00, 0x14, 0xA5, 0x76, 0x19, 0x3f} ; // my MAC address
unsigned char myIpAddr[4] = {192, 168, 1, 160} ; // my IP address
unsigned char getRequest[15] ; // HTTP request buffer
unsigned char dyna[31] ; // buffer for dynamic response
unsigned long httpCounter = 0 ; // counter of HTTP requests
/*******************************************
* functions
*/
/*
* put the constant string pointed to by s to the ENC transmit buffer
*/
unsigned int putConstString(const char *s)
{
unsigned int ctr = 0 ;
while(*s)
{
Spi_Ethernet_putByte(*s++) ;
ctr++ ;
}
return(ctr) ;
}
/*
* put the string pointed to by s to the ENC transmit buffer
*/
unsigned int putString(char *s)
{
unsigned int ctr = 0 ;
while(*s)
{
Spi_Ethernet_putByte(*s++) ;
ctr++ ;
}
return(ctr) ;
}
/*
* this function is called by the library
* the user accesses to the HTTP request by successive calls to Spi_Ethernet_getByte()
* the user puts data in the transmit buffer by successive calls to Spi_Ethernet_putByte()
* the function must return the length in bytes of the HTTP reply, or 0 if nothing to transmit
*
* if you don't need to reply to HTTP requests,
* just define this function with a return(0) as single statement
*
*/
unsigned int Spi_Ethernet_UserTCP(unsigned char *remoteHost, unsigned int remotePort, unsigned int localPort, unsigned int reqLength)
{
unsigned int len = 0 ; // my reply length
unsigned int i ; // general purpose integer
unsigned int iReqBytes ;
unsigned int len2 ;
char szBytes[12] ;
if(localPort != 80) // I listen only to web request on port 80
{
return(0) ;
}
// get 12 first bytes only of the request, the rest does not matter here
for(i = 0 ; i < 12 ; i++)
{
getRequest[i] = Spi_Ethernet_getByte() ;
}
getRequest[i] = 0 ;
if(memcmp(getRequest, httpMethod, 5)) // only GET method is supported here
{
return(0) ;
}
iReqBytes = atoi(&getrequest[5]);
if ( iReqBytes>0 && iReqBytes<10000 )
{
len = putConstString("HTTP/1.1 200 OK\nContent-type: text/html\n\n"); // 41 bytes
len += putConstString("<HTML><HEAD></HEAD><BODY>\n"); // 26 bytes
for ( i=0 ; i<iReqBytes ; i++ )
{
if ( i%50 == 0 )
{
len += putConstString("<BR>");
}
else
{
Spi_Ethernet_putByte('A') ;
len++ ;
}
}
len += putConstString("<BR>");
IntToStr(len+26,szBytes);
len += putString(szBytes); // 6 bytes
len += putConstString(" Bytes"); // 6 bytes
len += putConstString("</BODY></HTML>"); // 14 bytes
}
// Always fails when total bytes > 1460 (URL arg > 1285)
// (and this does not take into account framing bytes, etc.)
// Since typical MTU (Maximum Transmission Unit) sizes for
// ethernet are ~1500, I'm wondering whether this web server
// breaks down when the response must be broken into 2 or
// more datagrams.
if(len == 0) // what do to by default
{
len = putConstString("HTTP/1.1 200 OK\nContent-type: text/html\n\n");
len += putConstString("<HTML><HEAD></HEAD><BODY>\n");
len += putConstString("Usage: URL/nbytes\n");
len += putConstString("</BODY></HTML>");
}
return(len) ; // return to the library with the number of bytes to transmit
}
/*
* this function is called by the library
* the user accesses to the UDP request by successive calls to Spi_Ethernet_getByte()
* the user puts data in the transmit buffer by successive calls to Spi_Ethernet_putByte()
* the function must return the length in bytes of the UDP reply, or 0 if nothing to transmit
*
* if you don't need to reply to UDP requests,
* just define this function with a return(0) as single statement
*
*/
unsigned int Spi_Ethernet_UserUDP(unsigned char *remoteHost, unsigned int remotePort, unsigned int destPort, unsigned int reqLength)
{
unsigned int len ; // my reply length
unsigned char *ptr ; // pointer to the dynamic buffer
// reply is made of the remote host IP address in human readable format
byteToStr(remoteHost[0], dyna) ; // first IP address byte
dyna[3] = '.' ;
byteToStr(remoteHost[1], dyna + 4) ; // second
dyna[7] = '.' ;
byteToStr(remoteHost[2], dyna + 8) ; // third
dyna[11] = '.' ;
byteToStr(remoteHost[3], dyna + 12) ; // fourth
dyna[15] = ':' ; // add separator
// then remote host port number
intToStr(remotePort, dyna + 16) ;
dyna[22] = '[' ;
intToStr(destPort, dyna + 23) ;
dyna[29] = ']' ;
dyna[30] = 0 ;
// the total length of the request is the length of the dynamic string plus the text of the request
len = 30 + reqLength ;
// puts the dynamic string into the transmit buffer
ptr = dyna ;
while(*ptr)
{
Spi_Ethernet_putByte(*ptr++) ;
}
// then puts the request string converted into upper char into the transmit buffer
while(reqLength--)
{
Spi_Ethernet_putByte(toupper(Spi_Ethernet_getByte())) ;
}
return(len) ; // back to the library with the length of the UDP reply
}
/*
* main entry
*/
void main()
{
// Set Ports Per User-Specific Board Configuration...
/*
* starts ENC28J60 with :
* reset bit on RC0
* CS bit on RC1
* my MAC & IP address
* full duplex
*/
Spi_Init();
Spi_Ethernet_Init(&PORTA, 4, &PORTA, 3, myMacAddr, myIpAddr, Spi_Ethernet_FULLDUPLEX) ;
while(1)
{
Spi_Ethernet_doPacket() ; // process incoming Ethernet packets
}
}