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