Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

enc28j60.c

Go to the documentation of this file.
00001 /*! \file enc28j60.c \brief Microchip ENC28J60 Ethernet Interface Driver. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'enc28j60.c'
00005 // Title        : Microchip ENC28J60 Ethernet Interface Driver
00006 // Author       : Pascal Stang (c)2005
00007 // Created      : 9/22/2005
00008 // Revised      : 9/22/2005
00009 // Version      : 0.1
00010 // Target MCU   : Atmel AVR series
00011 // Editor Tabs  : 4
00012 //
00013 // Description  : This driver provides initialization and transmit/receive
00014 //  functions for the Microchip ENC28J60 10Mb Ethernet Controller and PHY.
00015 // This chip is novel in that it is a full MAC+PHY interface all in a 28-pin
00016 // chip, using an SPI interface to the host processor.
00017 //
00018 //*****************************************************************************
00019 
00020 #include "avr/io.h"
00021 
00022 #include "global.h"
00023 #include "timer.h"
00024 #include "rprintf.h"
00025 
00026 #include "enc28j60.h"
00027 
00028 #ifdef SPDR0
00029     #define SPDR    SPDR0
00030     #define SPCR    SPCR0
00031     #define SPSR    SPSR0
00032 
00033     #define SPIF    SPIF0
00034     #define MSTR    MSTR0
00035     #define CPOL    CPOL0
00036     #define DORD    DORD0
00037     #define SPR0    SPR00
00038     #define SPR1    SPR01
00039     #define SPI2X   SPI2X0
00040     #define SPE     SPE0
00041 #endif
00042 
00043 // include configuration
00044 #include "enc28j60conf.h"
00045 
00046 u08 Enc28j60Bank;
00047 u16 NextPacketPtr;
00048 
00049 void nicInit(void)
00050 {
00051     enc28j60Init();
00052 }
00053 
00054 void nicSend(unsigned int len, unsigned char* packet)
00055 {
00056     enc28j60PacketSend(len, packet);
00057 }
00058 
00059 unsigned int nicPoll(unsigned int maxlen, unsigned char* packet)
00060 {
00061     return enc28j60PacketReceive(maxlen, packet);
00062 }
00063 
00064 void nicGetMacAddress(u08* macaddr)
00065 {
00066     // read MAC address registers
00067     // NOTE: MAC address in ENC28J60 is byte-backward
00068     *macaddr++ = enc28j60Read(MAADR5);
00069     *macaddr++ = enc28j60Read(MAADR4);
00070     *macaddr++ = enc28j60Read(MAADR3);
00071     *macaddr++ = enc28j60Read(MAADR2);
00072     *macaddr++ = enc28j60Read(MAADR1);
00073     *macaddr++ = enc28j60Read(MAADR0);
00074 }
00075 
00076 void nicSetMacAddress(u08* macaddr)
00077 {
00078     // write MAC address
00079     // NOTE: MAC address in ENC28J60 is byte-backward
00080     enc28j60Write(MAADR5, *macaddr++);
00081     enc28j60Write(MAADR4, *macaddr++);
00082     enc28j60Write(MAADR3, *macaddr++);
00083     enc28j60Write(MAADR2, *macaddr++);
00084     enc28j60Write(MAADR1, *macaddr++);
00085     enc28j60Write(MAADR0, *macaddr++);
00086 }
00087 
00088 void nicRegDump(void)
00089 {
00090     enc28j60RegDump();
00091 }
00092 
00093 /*
00094 void ax88796SetupPorts(void)
00095 {
00096 #if NIC_CONNECTION == MEMORY_MAPPED
00097     // enable external SRAM interface - no wait states
00098     sbi(MCUCR, SRE);
00099 //  sbi(MCUCR, SRW10);
00100 //  sbi(XMCRA, SRW00);
00101 //  sbi(XMCRA, SRW01);
00102 //  sbi(XMCRA, SRW11);
00103 #else
00104     // set address port to output
00105     AX88796_ADDRESS_DDR = AX88796_ADDRESS_MASK;
00106     
00107     // set data port to input with pull-ups
00108     AX88796_DATA_DDR = 0x00;
00109     AX88796_DATA_PORT = 0xFF;
00110 
00111     // initialize the control port read and write pins to de-asserted
00112     sbi( AX88796_CONTROL_PORT, AX88796_CONTROL_READPIN );
00113     sbi( AX88796_CONTROL_PORT, AX88796_CONTROL_WRITEPIN );
00114     // set the read and write pins to output
00115     sbi( AX88796_CONTROL_DDR, AX88796_CONTROL_READPIN );
00116     sbi( AX88796_CONTROL_DDR, AX88796_CONTROL_WRITEPIN );
00117 #endif
00118     // set reset pin to output
00119     sbi( AX88796_RESET_DDR, AX88796_RESET_PIN );
00120 }
00121 */
00122 
00123 u08 enc28j60ReadOp(u08 op, u08 address)
00124 {
00125     u08 data;
00126    
00127     // assert CS
00128     ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS);
00129     
00130     // issue read command
00131     SPDR = op | (address & ADDR_MASK);
00132     while(!(SPSR & (1<<SPIF)));
00133     // read data
00134     SPDR = 0x00;
00135     while(!(SPSR & (1<<SPIF)));
00136     // do dummy read if needed
00137     if(address & 0x80)
00138     {
00139         SPDR = 0x00;
00140         while(!(inb(SPSR) & (1<<SPIF)));
00141     }
00142     data = SPDR;
00143     
00144     // release CS
00145     ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS);
00146 
00147     return data;
00148 }
00149 
00150 void enc28j60WriteOp(u08 op, u08 address, u08 data)
00151 {
00152     // assert CS
00153     ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS);
00154 
00155     // issue write command
00156     SPDR = op | (address & ADDR_MASK);
00157     while(!(SPSR & (1<<SPIF)));
00158     // write data
00159     SPDR = data;
00160     while(!(SPSR & (1<<SPIF)));
00161 
00162     // release CS
00163     ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS);
00164 }
00165 
00166 void enc28j60ReadBuffer(u16 len, u08* data)
00167 {
00168     // assert CS
00169     ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS);
00170     
00171     // issue read command
00172     SPDR = ENC28J60_READ_BUF_MEM;
00173     while(!(SPSR & (1<<SPIF)));
00174     while(len--)
00175     {
00176         // read data
00177         SPDR = 0x00;
00178         while(!(SPSR & (1<<SPIF)));
00179         *data++ = SPDR;
00180     }   
00181     // release CS
00182     ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS);
00183 }
00184 
00185 void enc28j60WriteBuffer(u16 len, u08* data)
00186 {
00187     // assert CS
00188     ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS);
00189     
00190     // issue write command
00191     SPDR = ENC28J60_WRITE_BUF_MEM;
00192     while(!(SPSR & (1<<SPIF)));
00193     while(len--)
00194     {
00195         // write data
00196         SPDR = *data++;
00197         while(!(SPSR & (1<<SPIF)));
00198     }   
00199     // release CS
00200     ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS);
00201 }
00202 
00203 void enc28j60SetBank(u08 address)
00204 {
00205     // set the bank (if needed)
00206     if((address & BANK_MASK) != Enc28j60Bank)
00207     {
00208         // set the bank
00209         enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
00210         enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
00211         Enc28j60Bank = (address & BANK_MASK);
00212     }
00213 }
00214 
00215 u08 enc28j60Read(u08 address)
00216 {
00217     // set the bank
00218     enc28j60SetBank(address);
00219     // do the read
00220     return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address);
00221 }
00222 
00223 void enc28j60Write(u08 address, u08 data)
00224 {
00225     // set the bank
00226     enc28j60SetBank(address);
00227     // do the write
00228     enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data);
00229 }
00230 
00231 u16 enc28j60PhyRead(u08 address)
00232 {
00233     u16 data;
00234 
00235     // Set the right address and start the register read operation
00236     enc28j60Write(MIREGADR, address);
00237     enc28j60Write(MICMD, MICMD_MIIRD);
00238 
00239     // wait until the PHY read completes
00240     while(enc28j60Read(MISTAT) & MISTAT_BUSY);
00241 
00242     // quit reading
00243     enc28j60Write(MICMD, 0x00);
00244     
00245     // get data value
00246     data  = enc28j60Read(MIRDL);
00247     data |= enc28j60Read(MIRDH);
00248     // return the data
00249     return data;
00250 }
00251 
00252 void enc28j60PhyWrite(u08 address, u16 data)
00253 {
00254     // set the PHY register address
00255     enc28j60Write(MIREGADR, address);
00256     
00257     // write the PHY data
00258     enc28j60Write(MIWRL, data); 
00259     enc28j60Write(MIWRH, data>>8);
00260 
00261     // wait until the PHY write completes
00262     while(enc28j60Read(MISTAT) & MISTAT_BUSY);
00263 }
00264 
00265 void enc28j60Init(void)
00266 {
00267     // initialize I/O
00268     sbi(ENC28J60_CONTROL_DDR, ENC28J60_CONTROL_CS);
00269     sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
00270 
00271     // setup SPI I/O pins
00272     sbi(ENC28J60_SPI_PORT, ENC28J60_SPI_SCK);   // set SCK hi
00273     sbi(ENC28J60_SPI_DDR, ENC28J60_SPI_SCK);    // set SCK as output
00274     cbi(ENC28J60_SPI_DDR, ENC28J60_SPI_MISO);   // set MISO as input
00275     sbi(ENC28J60_SPI_DDR, ENC28J60_SPI_MOSI);   // set MOSI as output
00276     sbi(ENC28J60_SPI_DDR, ENC28J60_SPI_SS);     // SS must be output for Master mode to work
00277     // initialize SPI interface
00278     // master mode
00279     sbi(SPCR, MSTR);
00280     // select clock phase positive-going in middle of data
00281     cbi(SPCR, CPOL);
00282     // Data order MSB first
00283     cbi(SPCR,DORD);
00284     // switch to f/4 2X = f/2 bitrate
00285     cbi(SPCR, SPR0);
00286     cbi(SPCR, SPR1);
00287     sbi(SPSR, SPI2X);
00288     // enable SPI
00289     sbi(SPCR, SPE);
00290 
00291     // perform system reset
00292     enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
00293     // check CLKRDY bit to see if reset is complete
00294     delay_us(50);
00295     while(!(enc28j60Read(ESTAT) & ESTAT_CLKRDY));
00296 
00297     // do bank 0 stuff
00298     // initialize receive buffer
00299     // 16-bit transfers, must write low byte first
00300     // set receive buffer start address
00301     NextPacketPtr = RXSTART_INIT;
00302     enc28j60Write(ERXSTL, RXSTART_INIT&0xFF);
00303     enc28j60Write(ERXSTH, RXSTART_INIT>>8);
00304     // set receive pointer address
00305     enc28j60Write(ERXRDPTL, RXSTART_INIT&0xFF);
00306     enc28j60Write(ERXRDPTH, RXSTART_INIT>>8);
00307     // set receive buffer end
00308     // ERXND defaults to 0x1FFF (end of ram)
00309     enc28j60Write(ERXNDL, RXSTOP_INIT&0xFF);
00310     enc28j60Write(ERXNDH, RXSTOP_INIT>>8);
00311     // set transmit buffer start
00312     // ETXST defaults to 0x0000 (beginnging of ram)
00313     enc28j60Write(ETXSTL, TXSTART_INIT&0xFF);
00314     enc28j60Write(ETXSTH, TXSTART_INIT>>8);
00315 
00316     // do bank 2 stuff
00317     // enable MAC receive
00318     enc28j60Write(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
00319     // bring MAC out of reset
00320     enc28j60Write(MACON2, 0x00);
00321     // enable automatic padding and CRC operations
00322     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
00323 //  enc28j60Write(MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
00324     // set inter-frame gap (non-back-to-back)
00325     enc28j60Write(MAIPGL, 0x12);
00326     enc28j60Write(MAIPGH, 0x0C);
00327     // set inter-frame gap (back-to-back)
00328     enc28j60Write(MABBIPG, 0x12);
00329     // Set the maximum packet size which the controller will accept
00330     enc28j60Write(MAMXFLL, MAX_FRAMELEN&0xFF);  
00331     enc28j60Write(MAMXFLH, MAX_FRAMELEN>>8);
00332 
00333     // do bank 3 stuff
00334     // write MAC address
00335     // NOTE: MAC address in ENC28J60 is byte-backward
00336     enc28j60Write(MAADR5, ENC28J60_MAC0);
00337     enc28j60Write(MAADR4, ENC28J60_MAC1);
00338     enc28j60Write(MAADR3, ENC28J60_MAC2);
00339     enc28j60Write(MAADR2, ENC28J60_MAC3);
00340     enc28j60Write(MAADR1, ENC28J60_MAC4);
00341     enc28j60Write(MAADR0, ENC28J60_MAC5);
00342 
00343     // no loopback of transmitted frames
00344     enc28j60PhyWrite(PHCON2, PHCON2_HDLDIS);
00345 
00346     // switch to bank 0
00347     enc28j60SetBank(ECON1);
00348     // enable interrutps
00349     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE);
00350     // enable packet reception
00351     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
00352 /*
00353     enc28j60PhyWrite(PHLCON, 0x0AA2);
00354 
00355     // setup duplex ----------------------
00356 
00357     // Disable receive logic and abort any packets currently being transmitted
00358     enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS|ECON1_RXEN);
00359     
00360     {
00361         u16 temp;
00362         // Set the PHY to the proper duplex mode
00363         temp = enc28j60PhyRead(PHCON1);
00364         temp &= ~PHCON1_PDPXMD;
00365         enc28j60PhyWrite(PHCON1, temp);
00366         // Set the MAC to the proper duplex mode
00367         temp = enc28j60Read(MACON3);
00368         temp &= ~MACON3_FULDPX;
00369         enc28j60Write(MACON3, temp);
00370     }
00371 
00372     // Set the back-to-back inter-packet gap time to IEEE specified 
00373     // requirements.  The meaning of the MABBIPG value changes with the duplex
00374     // state, so it must be updated in this function.
00375     // In full duplex, 0x15 represents 9.6us; 0x12 is 9.6us in half duplex
00376     //enc28j60Write(MABBIPG, DuplexState ? 0x15 : 0x12);    
00377     
00378     // Reenable receive logic
00379     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
00380 
00381     // setup duplex ----------------------
00382 */
00383 }
00384 
00385 void enc28j60PacketSend(unsigned int len, unsigned char* packet)
00386 {
00387     // Set the write pointer to start of transmit buffer area
00388     enc28j60Write(EWRPTL, TXSTART_INIT);
00389     enc28j60Write(EWRPTH, TXSTART_INIT>>8);
00390     // Set the TXND pointer to correspond to the packet size given
00391     enc28j60Write(ETXNDL, (TXSTART_INIT+len));
00392     enc28j60Write(ETXNDH, (TXSTART_INIT+len)>>8);
00393 
00394     // write per-packet control byte
00395     enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
00396 
00397     // copy the packet into the transmit buffer
00398     enc28j60WriteBuffer(len, packet);
00399     
00400     // send the contents of the transmit buffer onto the network
00401     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
00402 }
00403 
00404 unsigned int enc28j60PacketReceive(unsigned int maxlen, unsigned char* packet)
00405 {
00406     u16 rxstat;
00407     u16 len;
00408 
00409     // check if a packet has been received and buffered
00410 //  if( !(enc28j60Read(EIR) & EIR_PKTIF) )
00411     if( !enc28j60Read(EPKTCNT) )
00412         return 0;
00413     
00414     // Make absolutely certain that any previous packet was discarded   
00415     //if( WasDiscarded == FALSE)
00416     //  MACDiscardRx();
00417 
00418     // Set the read pointer to the start of the received packet
00419     enc28j60Write(ERDPTL, (NextPacketPtr));
00420     enc28j60Write(ERDPTH, (NextPacketPtr)>>8);
00421     // read the next packet pointer
00422     NextPacketPtr  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
00423     NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
00424     // read the packet length
00425     len  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
00426     len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
00427     // read the receive status
00428     rxstat  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
00429     rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
00430 
00431     // limit retrieve length
00432     // (we reduce the MAC-reported length by 4 to remove the CRC)
00433     len = MIN(len, maxlen);
00434 
00435     // copy the packet from the receive buffer
00436     enc28j60ReadBuffer(len, packet);
00437 
00438     // Move the RX read pointer to the start of the next received packet
00439     // This frees the memory we just read out
00440     enc28j60Write(ERXRDPTL, (NextPacketPtr));
00441     enc28j60Write(ERXRDPTH, (NextPacketPtr)>>8);
00442 
00443     // decrement the packet counter indicate we are done with this packet
00444     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
00445 
00446     return len;
00447 }
00448 
00449 void enc28j60ReceiveOverflowRecover(void)
00450 {
00451     // receive buffer overflow handling procedure
00452 
00453     // recovery completed
00454 }
00455 
00456 void enc28j60RegDump(void)
00457 {
00458 //  unsigned char macaddr[6];
00459 //  result = ax88796Read(TR);
00460     
00461 //  rprintf("Media State: ");
00462 //  if(!(result & AUTOD))
00463 //      rprintf("Autonegotiation\r\n");
00464 //  else if(result & RST_B)
00465 //      rprintf("PHY in Reset   \r\n");
00466 //  else if(!(result & RST_10B))
00467 //      rprintf("10BASE-T       \r\n");
00468 //  else if(!(result & RST_TXB))
00469 //      rprintf("100BASE-T      \r\n");
00470                 
00471     rprintf("RevID: 0x%x\r\n", enc28j60Read(EREVID));
00472 
00473     rprintfProgStrM("Cntrl: ECON1 ECON2 ESTAT  EIR  EIE\r\n");
00474     rprintfProgStrM("         ");
00475     rprintfu08(enc28j60Read(ECON1));
00476     rprintfProgStrM("    ");
00477     rprintfu08(enc28j60Read(ECON2));
00478     rprintfProgStrM("    ");
00479     rprintfu08(enc28j60Read(ESTAT));
00480     rprintfProgStrM("    ");
00481     rprintfu08(enc28j60Read(EIR));
00482     rprintfProgStrM("   ");
00483     rprintfu08(enc28j60Read(EIE));
00484     rprintfCRLF();
00485 
00486     rprintfProgStrM("MAC  : MACON1  MACON2  MACON3  MACON4  MAC-Address\r\n");
00487     rprintfProgStrM("        0x");
00488     rprintfu08(enc28j60Read(MACON1));
00489     rprintfProgStrM("    0x");
00490     rprintfu08(enc28j60Read(MACON2));
00491     rprintfProgStrM("    0x");
00492     rprintfu08(enc28j60Read(MACON3));
00493     rprintfProgStrM("    0x");
00494     rprintfu08(enc28j60Read(MACON4));
00495     rprintfProgStrM("   ");
00496     rprintfu08(enc28j60Read(MAADR5));
00497     rprintfu08(enc28j60Read(MAADR4));
00498     rprintfu08(enc28j60Read(MAADR3));
00499     rprintfu08(enc28j60Read(MAADR2));
00500     rprintfu08(enc28j60Read(MAADR1));
00501     rprintfu08(enc28j60Read(MAADR0));
00502     rprintfCRLF();
00503 
00504     rprintfProgStrM("Rx   : ERXST  ERXND  ERXWRPT ERXRDPT ERXFCON EPKTCNT MAMXFL\r\n");
00505     rprintfProgStrM("       0x");
00506     rprintfu08(enc28j60Read(ERXSTH));
00507     rprintfu08(enc28j60Read(ERXSTL));
00508     rprintfProgStrM(" 0x");
00509     rprintfu08(enc28j60Read(ERXNDH));
00510     rprintfu08(enc28j60Read(ERXNDL));
00511     rprintfProgStrM("  0x");
00512     rprintfu08(enc28j60Read(ERXWRPTH));
00513     rprintfu08(enc28j60Read(ERXWRPTL));
00514     rprintfProgStrM("  0x");
00515     rprintfu08(enc28j60Read(ERXRDPTH));
00516     rprintfu08(enc28j60Read(ERXRDPTL));
00517     rprintfProgStrM("   0x");
00518     rprintfu08(enc28j60Read(ERXFCON));
00519     rprintfProgStrM("    0x");
00520     rprintfu08(enc28j60Read(EPKTCNT));
00521     rprintfProgStrM("  0x");
00522     rprintfu08(enc28j60Read(MAMXFLH));
00523     rprintfu08(enc28j60Read(MAMXFLL));
00524     rprintfCRLF();
00525 
00526     rprintfProgStrM("Tx   : ETXST  ETXND  MACLCON1 MACLCON2 MAPHSUP\r\n");
00527     rprintfProgStrM("       0x");
00528     rprintfu08(enc28j60Read(ETXSTH));
00529     rprintfu08(enc28j60Read(ETXSTL));
00530     rprintfProgStrM(" 0x");
00531     rprintfu08(enc28j60Read(ETXNDH));
00532     rprintfu08(enc28j60Read(ETXNDL));
00533     rprintfProgStrM("   0x");
00534     rprintfu08(enc28j60Read(MACLCON1));
00535     rprintfProgStrM("     0x");
00536     rprintfu08(enc28j60Read(MACLCON2));
00537     rprintfProgStrM("     0x");
00538     rprintfu08(enc28j60Read(MAPHSUP));
00539     rprintfCRLF();
00540 
00541     delay_ms(25);
00542 }
00543 
00544 
00545 

Generated on Sun Oct 29 03:41:07 2006 for Procyon AVRlib by  doxygen 1.4.2