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

Generated on Mon Nov 6 23:36:59 2006 for Procyon ARMlib by  doxygen 1.4.2