SPI Ethernet Library
The ENC28J60
is a stand-alone Ethernet controller with an industry standard Serial Peripheral Interface
(SPIā¢). It is designed to serve as an Ethernet network interface for any controller equipped with SPI.
The ENC28J60
meets all of the IEEE 802.3 specifications. It incorporates a number of packet filtering
schemes to limit incoming packets. It also provides an internal DMA module for fast data throughput and hardware
assisted IP checksum calculations. Communication with the host controller is implemented via two interrupt pins and the SPI, with data rates of up to 10 Mb/s. Two dedicated pins are used for LED link and network activity indication.
This library is designed to simplify handling of the underlying hardware (ENC28J60
). It works with any 8051 MCU with
integrated SPI and more than 4 Kb ROM memory.
SPI Ethernet library supports:
- IPv4 protocol.
- ARP requests.
- ICMP echo requests.
- UDP requests.
- TCP requests (no stack, no packet reconstruction).
- packet fragmentation is NOT supported.
Notes:
- For advanced users there are header files (
"eth_enc28j60LibDef.h"
and"eth_enc28j60LibPrivate.h"
) inUses
folder of the compiler with description of all routines and global variables, relevant to the user, implemented in the SPI Ethernet Library. - The appropriate hardware SPI module must be initialized before using any of the SPI Ethernet library routines. Refer to SPI Library
External dependencies of SPI Ethernet Library
The following variables must be defined in all projects using SPI Ethernet Library: | Description: | Examples : |
---|---|---|
extern sfr sbit SPI_Ethernet_CS; |
ENC28J60 chip select pin. |
sfr sbit SPI_Ethernet_CS at P1_1_bit; |
extern sfr sbit SPI_Ethernet_RST; |
ENC28J60 reset pin. |
sfr sbit SPI_Ethernet_RST at P1_0_bit; |
The following routines must be defined in all project using SPI Ethernet Library: | Description: | Examples : |
---|---|---|
unsigned int SPI_Ethernet_UserTCP(unsigned char *remoteHost,
unsigned int remotePort,
unsigned int localPort,
unsigned int reqLength); |
TCP request handler. | Refer to the library example at the bottom of this page for code implementation. |
unsigned int SPI_Ethernet_UserUDP(unsigned char *remoteHost,
unsigned int remotePort,
unsigned int destPort,
unsigned int reqLength); |
UDP request handler. | Refer to the library example at the bottom of this page for code implementation. |
Library Routines
- SPI_Ethernet_Init
- SPI_Ethernet_Enable
- SPI_Ethernet_Disable
- SPI_Ethernet_doPacket
- SPI_Ethernet_putByte
- SPI_Ethernet_putBytes
- SPI_Ethernet_putString
- SPI_Ethernet_putConstString
- SPI_Ethernet_putConstBytes
- SPI_Ethernet_getByte
- SPI_Ethernet_getBytes
- SPI_Ethernet_UserTCP
- SPI_Ethernet_UserUDP
These routines are private and used by the compiler only :
- SPI_Ethernet_checksum
- SPI_Ethernet_clearBitReg
- SPI_Ethernet_delay
- SPI_Ethernet_doARP
- SPI_Ethernet_doTCP
- SPI_Ethernet_doUDP
- SPI_Ethernet_Init2
- SPI_Ethernet_IPswap
- SPI_Ethernet_MACswap
- SPI_Ethernet_memcmp
- SPI_Ethernet_memcpy
- SPI_Ethernet_RAMcopy
- SPI_Ethernet_readMem
- SPI_Ethernet_readPacket
- SPI_Ethernet_readPHY
- SPI_Ethernet_readReg
- SPI_Ethernet_sendUDP2
- SPI_Ethernet_setBitReg
- SPI_Ethernet_setRxReadAddr
- SPI_Ethernet_TXpacket
- SPI_Ethernet_writeAddr
- SPI_Ethernet_writeMem
- SPI_Ethernet_writeMemory
- SPI_Ethernet_writeMemory2
- SPI_Ethernet_writePHY
- SPI_Ethernet_writeReg
SPI_Ethernet_Init
Prototype |
void SPI_Ethernet_Init(unsigned char *mac, unsigned char *ip, unsigned char fullDuplex); |
---|---|
Returns |
Nothing. |
Description |
This is MAC module routine. It initializes
Parameters:
|
Requires |
Global variables :
|
Example |
#define SPI_Ethernet_HALFDUPLEX 0 #define SPI_Ethernet_FULLDUPLEX 1 // mE ehternet NIC pinout sfr sbit Spi_Ethernet_RST at P1_0_bit; sfr sbit Spi_Ethernet_CS at P1_1_bit; // end ethernet NIC definitions unsigned char myMacAddr[6] = {0x00, 0x14, 0xA5, 0x76, 0x19, 0x3f}; // my MAC address unsigned char myIpAddr = {192, 168, 1, 60 }; // my IP addr SPI1_Init(); SPI_Ethernet_Init(myMacAddr, myIpAddr, SPI_Ethernet_FULLDUPLEX); |
SPI_Ethernet_Enable
Prototype |
void SPI_Ethernet_Enable(unsigned char enFlt); |
||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Returns |
Nothing. |
||||||||||||||||||||||||||||||||||||
Description |
This is MAC module routine. This routine enables appropriate network traffic on the Parameters:
Note: Advanced filtering available in the
Note: This routine will change receive filter configuration on-the-fly. It will not, in any way, mess with enabling/disabling receive/transmit logic or any other part of the |
||||||||||||||||||||||||||||||||||||
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
||||||||||||||||||||||||||||||||||||
Example |
SPI_Ethernet_Enable(_SPI_Ethernet_CRC | _SPI_Ethernet_UNICAST); // enable CRC checking and Unicast traffic |
SPI_Ethernet_Disable
Prototype |
void SPI_Ethernet_Disable(unsigned char disFlt); |
||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Returns |
Nothing. |
||||||||||||||||||||||||||||||||||||
Description |
This is MAC module routine. This routine disables appropriate network traffic on the Parameters:
Note: Advanced filtering available in the
Note: This routine will change receive filter configuration on-the-fly. It will not, in any way, mess with enabling/disabling receive/transmit logic or any other part of the |
||||||||||||||||||||||||||||||||||||
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
||||||||||||||||||||||||||||||||||||
Example |
SPI_Ethernet_Disable(_SPI_Ethernet_CRC | _SPI_Ethernet_UNICAST); // disable CRC checking and Unicast traffic |
SPI_Ethernet_doPacket
Prototype |
unsigned char SPI_Ethernet_doPacket(); |
---|---|
Returns |
|
Description |
This is MAC module routine. It processes next received packet if such exists. Packets are processed in the following manner:
Note: |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
if (SPI_Ethernet_doPacket() == 0)(1) { // process received packets ... } |
SPI_Ethernet_putByte
Prototype |
void SPI_Ethernet_putByte(unsigned char v); |
---|---|
Returns |
Nothing. |
Description |
This is MAC module routine. It stores one byte to address pointed by the current Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
char data_; ... SPI_Ethernet_putByte(data); // put an byte into ENC28J60 buffer |
SPI_Ethernet_putBytes
Prototype |
void SPI_Ethernet_putBytes(unsigned char *ptr, unsigned char n); |
---|---|
Returns |
Nothing. |
Description |
This is MAC module routine. It stores requested number of bytes into Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
char *buffer = "mikroElektronika"; ... SPI_Ethernet_putBytes(buffer, 16); // put an RAM array into ENC28J60 buffer |
SPI_Ethernet_putConstBytes
Prototype |
void SPI_Ethernet_putConstBytes(const code unsigned char *ptr, unsigned char n); |
---|---|
Returns |
Nothing. |
Description |
This is MAC module routine. It stores requested number of const bytes into Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
const char *buffer = "mikroElektronika"; ... SPI_Ethernet_putConstBytes(buffer, 16); // put a const array into ENC28J60 buffer |
SPI_Ethernet_putString
Prototype |
unsigned int SPI_Ethernet_putString(unsigned char *ptr); |
---|---|
Returns |
Number of bytes written into |
Description |
This is MAC module routine. It stores whole string (excluding null termination) into Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
char *buffer = "mikroElektronika"; ... SPI_Ethernet_putString(buffer); // put a RAM string into ENC28J60 buffer |
SPI_Ethernet_putConstString
Prototype |
unsigned int SPI_Ethernet_putConstString(const code unsigned char *ptr); |
---|---|
Returns |
Number of bytes written into |
Description |
This is MAC module routine. It stores whole const string (excluding null termination) into Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
const char *buffer = "mikroElektronika"; ... SPI_Ethernet_putConstString(buffer); // put a const string into ENC28J60 buffer |
SPI_Ethernet_getByte
Prototype |
unsigned char SPI_Ethernet_getByte(); |
---|---|
Returns |
Byte read from |
Description |
This is MAC module routine. It fetches a byte from address pointed to by current |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
char buffer;
...
buffer = SPI_Ethernet_getByte(); // read a byte from
|
SPI_Ethernet_getBytes
Prototype |
void SPI_Ethernet_getBytes(unsigned char *ptr, unsigned int addr, unsigned char n); |
---|---|
Returns |
Nothing. |
Description |
This is MAC module routine. It fetches equested number of bytes from Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
char buffer[16]; ... SPI_Ethernet_getBytes(buffer, 0x100, 16); // read 16 bytes, starting from address 0x100 |
SPI_Ethernet_UserTCP
Prototype |
unsigned int SPI_Ethernet_UserTCP(unsigned char *remoteHost, unsigned int remotePort, unsigned int localPort, unsigned int reqLength); |
---|---|
Returns |
|
Description |
This is TCP module routine. It is internally called by the library. The user accesses to the TCP/HTTP request by using some of the SPI_Ethernet_get routines. The user puts data in the transmit buffer by using some of the SPI_Ethernet_put routines. The function must return the length in bytes of the TCP/HTTP reply, or 0 if there is nothing to transmit. If there is no need to reply to the TCP/HTTP requests, just define this function with return(0) as a single statement. Parameters:
Note: The function source code is provided with appropriate example projects. The code should be adjusted by the user to achieve desired reply. |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
This function is internally called by the library and should not be called by the user's code. |
SPI_Ethernet_UserUDP
Prototype |
unsigned int SPI_Ethernet_UserUDP(unsigned char *remoteHost, unsigned int remotePort, unsigned int destPort, unsigned int reqLength); |
---|---|
Returns |
|
Description |
This is UDP module routine. It is internally called by the library. The user accesses to the UDP request by using some of the SPI_Ethernet_get routines. The user puts data in the transmit buffer by using some of the SPI_Ethernet_put routines. 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 the UDP requests, just define this function with a return(0) as single statement. Parameters:
Note: The function source code is provided with appropriate example projects. The code should be adjusted by the user to achieve desired reply. |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
This function is internally called by the library and should not be called by the user's code. |
Library Example
This code shows how to use the 8051
mini Ethernet 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 P3.b0 to P3.b7 bit and return HTML main page
- all other requests return also HTML main page.
// duplex config flags #define Spi_Ethernet_HALFDUPLEX 0x00 // half duplex #define Spi_Ethernet_FULLDUPLEX 0x01 // full duplex // mE ehternet NIC pinout sfr sbit Spi_Ethernet_RST at P1_0_bit; sfr sbit Spi_Ethernet_CS at P1_1_bit; // end ethernet NIC definitions /************************************************************ * ROM constant strings */ const code unsigned char httpHeader[] = "HTTP/1.1 200 OKnContent-type: " ; // HTTP header const code unsigned char httpMimeTypeHTML[] = "text/htmlnn" ; // HTML MIME type const code unsigned char httpMimeTypeScript[] = "text/plainnn" ; // TEXT MIME type idata unsigned char httpMethod[] = "GET /"; /* * web page, splited into 2 parts : * when coming short of ROM, fragmented data is handled more efficiently by linker * * this HTML page calls the boards to get its status, and builds itself with javascript */ const code char *indexPage = // Change the IP address of the page to be refreshed "<meta http-equiv="refresh" content="3;url=http://192.168.20.60"> <HTML><HEAD></HEAD><BODY> <h1>8051 + ENC28J60 Mini Web Server</h1> <a href=/>Reload</a> <script src=/s></script> <table><tr><td><table border=1 style="font-size:20px ;font-family: terminal ;"> <tr><th colspan=2>P0</th></tr> <script> var str,i; str=""; for(i=0;i<8;i++) {str+="<tr><td bgcolor=pink>BUTTON #"+i+"</td>"; if(P0&(1<<i)){str+="<td bgcolor=red>ON";} else {str+="<td bgcolor=#cccccc>OFF";} str+="</td></tr>";} document.write(str) ; </script> " ; const char *indexPage2 = "</table></td><td> <table border=1 style="font-size:20px ;font-family: terminal ;"> <tr><th colspan=3>P3</th></tr> <script> var str,i; str=""; for(i=0;i<8;i++) {str+="<tr><td bgcolor=yellow>LED #"+i+"</td>"; if(P3&(1<<i)){str+="<td bgcolor=red>ON";} else {str+="<td bgcolor=#cccccc>OFF";} str+="</td><td><a href=/t"+i+">Toggle</a></td></tr>";} document.write(str) ; </script> </table></td></tr></table> This is HTTP request #<script>document.write(REQ)</script></BODY></HTML> " ; /*********************************** * RAM variables */ idata unsigned char myMacAddr[6] = {0x00, 0x14, 0xA5, 0x76, 0x19, 0x3f} ; // my MAC address idata unsigned char myIpAddr[4] = {192, 168, 20, 60} ; // my IP address idata unsigned char getRequest[15] ; // HTTP request buffer idata unsigned char dyna[29] ; // buffer for dynamic response idata 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 code char *s) { unsigned int ctr = 0 ; while(*s) { Spi_Ethernet_putByte(*s++) ; ctr++ ; } return(ctr) ; }*/ /* * it will be much faster to use library Spi_Ethernet_putConstString routine * instead of putConstString routine above. However, the code will be a little * bit bigger. User should choose between size and speed and pick the implementation that * suites him best. If you choose to go with the putConstString definition above * the #define line below should be commented out. * */ #define putConstString Spi_Ethernet_putConstString /* * 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) ; }*/ /* * it will be much faster to use library Spi_Ethernet_putString routine * instead of putString routine above. However, the code will be a little * bit bigger. User should choose between size and speed and pick the implementation that * suites him best. If you choose to go with the putString definition above * the #define line below should be commented out. * */ #define putString Spi_Ethernet_putString /* * 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) { idata unsigned int len; // my reply length if(localPort != 80) // I listen only to web request on port 80 { return(0) ; } // get 10 first bytes only of the request, the rest does not matter here for(len = 0 ; len < 10 ; len++) { getRequest[len] = Spi_Ethernet_getByte() ; } getRequest[len] = 0 ; len = 0; if(memcmp(getRequest, httpMethod, 5)) // only GET method is supported here { return(0) ; } httpCounter++ ; // one more request done if(getRequest[5] == 's') // if request path name starts with s, store dynamic data in transmit buffer { // the text string replied by this request can be interpreted as javascript statements // by browsers len = putConstString(httpHeader) ; // HTTP header len += putConstString(httpMimeTypeScript) ; // with text MIME type // add P3 value (buttons) to reply len += putConstString("var P3=") ; WordToStr(P3, dyna) ; len += putString(dyna) ; len += putConstString(";") ; // add P0 value (LEDs) to reply len += putConstString("var P0=") ; WordToStr(P0, dyna) ; len += putString(dyna) ; len += putConstString(";") ; // add HTTP requests counter to reply WordToStr(httpCounter, dyna) ; len += putConstString("var REQ=") ; len += putString(dyna) ; len += putConstString(";") ; } else if(getRequest[5] == 't') // if request path name starts with t, toggle P3 (LED) bit number that comes after { unsigned char bitMask = 0 ; // for bit mask if(isdigit(getRequest[6])) // if 0 <= bit number <= 9, bits 8 & 9 does not exist but does not matter { bitMask = getRequest[6] - '0' ; // convert ASCII to integer bitMask = 1 << bitMask ; // create bit mask P3 ^= bitMask ; // toggle P3 with xor operator } } if(len == 0) // what do to by default { len = putConstString(httpHeader) ; // HTTP header len += putConstString(httpMimeTypeHTML) ; // with HTML MIME type len += putConstString(indexPage) ; // HTML page first part len += putConstString(indexPage2) ; // HTML page second part } 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) { idata unsigned int len ; // my reply length idata 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 WordToStr(remotePort, dyna + 16) ; dyna[21] = '[' ; WordToStr(destPort, dyna + 22) ; dyna[27] = ']' ; dyna[28] = 0 ; // the total length of the request is the length of the dynamic string plus the text of the request len = 28 + reqLength; // puts the dynamic string into the transmit buffer Spi_Ethernet_putBytes(dyna, 28) ; // 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() { /* * starts ENC28J60 with : * reset bit on P1_0 * CS bit on P1_1 * my MAC & IP address * full duplex */ SPI1_Init(); Spi_Ethernet_Init(myMacAddr, myIpAddr, Spi_Ethernet_FULLDUPLEX) ; // full duplex, CRC + MAC Unicast + MAC Broadcast filtering while(1) // do forever { /* * if necessary, test the return value to get error code */ Spi_Ethernet_doPacket() ; // process incoming Ethernet packets /* * add your stuff here if needed * Spi_Ethernet_doPacket() must be called as often as possible * otherwise packets could be lost */ } }
HW Connection
What do you think about this topic ? Send us feedback!