Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers enc28j60.c Source File

enc28j60.c

Go to the documentation of this file.
00001 /**
00002  * @file enc28j60.c
00003  * @brief ENC28J60 Ethernet controller
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL NIC_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <limits.h>
00034 #include "core/net.h"
00035 #include "drivers/enc28j60.h"
00036 #include "debug.h"
00037 
00038 
00039 /**
00040  * @brief ENC28J60 driver
00041  **/
00042 
00043 const NicDriver enc28j60Driver =
00044 {
00045    NIC_TYPE_ETHERNET,
00046    ETH_MTU,
00047    enc28j60Init,
00048    enc28j60Tick,
00049    enc28j60EnableIrq,
00050    enc28j60DisableIrq,
00051    enc28j60EventHandler,
00052    enc28j60SendPacket,
00053    enc28j60SetMulticastFilter,
00054    NULL,
00055    NULL,
00056    NULL,
00057    TRUE,
00058    TRUE,
00059    TRUE,
00060    FALSE
00061 };
00062 
00063 
00064 /**
00065  * @brief ENC28J60 controller initialization
00066  * @param[in] interface Underlying network interface
00067  * @return Error code
00068  **/
00069 
00070 error_t enc28j60Init(NetInterface *interface)
00071 {
00072    uint8_t revisionId;
00073    Enc28j60Context *context;
00074 
00075    //Debug message
00076    TRACE_INFO("Initializing ENC28J60 Ethernet controller...\r\n");
00077 
00078    //Initialize SPI
00079    interface->spiDriver->init();
00080    //Initialize external interrupt line
00081    interface->extIntDriver->init();
00082 
00083    //Issue a system reset
00084    enc28j60SoftReset(interface);
00085 
00086    //After issuing the reset command, wait at least 1ms in firmware
00087    //for the device to be ready
00088    sleep(10);
00089 
00090    //Point to the driver context
00091    context = (Enc28j60Context *) interface->nicContext;
00092 
00093    //Initialize driver specific variables
00094    context->currentBank = UINT16_MAX;
00095    context->nextPacket = ENC28J60_RX_BUFFER_START;
00096 
00097    //Allocate RX buffer
00098    context->rxBuffer = memPoolAlloc(ETH_MAX_FRAME_SIZE);
00099    //Failed to allocate memory?
00100    if(context->rxBuffer == NULL)
00101       return ERROR_OUT_OF_MEMORY;
00102 
00103    //Read silicon revision ID
00104    revisionId = enc28j60ReadReg(interface, ENC28J60_REG_EREVID);
00105 
00106    //Debug message
00107    TRACE_INFO("ENC28J60 revision ID: 0x%02X\r\n", revisionId);
00108 
00109    //Disable CLKOUT output
00110    enc28j60WriteReg(interface, ENC28J60_REG_ECOCON, 0x00);
00111 
00112    //Set the MAC address
00113    enc28j60WriteReg(interface, ENC28J60_REG_MAADR1, interface->macAddr.b[0]);
00114    enc28j60WriteReg(interface, ENC28J60_REG_MAADR2, interface->macAddr.b[1]);
00115    enc28j60WriteReg(interface, ENC28J60_REG_MAADR3, interface->macAddr.b[2]);
00116    enc28j60WriteReg(interface, ENC28J60_REG_MAADR4, interface->macAddr.b[3]);
00117    enc28j60WriteReg(interface, ENC28J60_REG_MAADR5, interface->macAddr.b[4]);
00118    enc28j60WriteReg(interface, ENC28J60_REG_MAADR6, interface->macAddr.b[5]);
00119 
00120    //Set receive buffer location
00121    enc28j60WriteReg(interface, ENC28J60_REG_ERXSTL, LSB(ENC28J60_RX_BUFFER_START));
00122    enc28j60WriteReg(interface, ENC28J60_REG_ERXSTH, MSB(ENC28J60_RX_BUFFER_START));
00123    enc28j60WriteReg(interface, ENC28J60_REG_ERXNDL, LSB(ENC28J60_RX_BUFFER_STOP));
00124    enc28j60WriteReg(interface, ENC28J60_REG_ERXNDH, MSB(ENC28J60_RX_BUFFER_STOP));
00125 
00126    //The ERXRDPT register defines a location within the FIFO
00127    //where the receive hardware is forbidden to write to
00128    enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTL, LSB(ENC28J60_RX_BUFFER_STOP));
00129    enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTH, MSB(ENC28J60_RX_BUFFER_STOP));
00130 
00131    //Configure the receive filters
00132    enc28j60WriteReg(interface, ENC28J60_REG_ERXFCON, ERXFCON_UCEN |
00133       ERXFCON_CRCEN | ERXFCON_HTEN | ERXFCON_BCEN);
00134 
00135    //Initialize the hash table
00136    enc28j60WriteReg(interface, ENC28J60_REG_EHT0, 0x00);
00137    enc28j60WriteReg(interface, ENC28J60_REG_EHT1, 0x00);
00138    enc28j60WriteReg(interface, ENC28J60_REG_EHT2, 0x00);
00139    enc28j60WriteReg(interface, ENC28J60_REG_EHT3, 0x00);
00140    enc28j60WriteReg(interface, ENC28J60_REG_EHT4, 0x00);
00141    enc28j60WriteReg(interface, ENC28J60_REG_EHT5, 0x00);
00142    enc28j60WriteReg(interface, ENC28J60_REG_EHT6, 0x00);
00143    enc28j60WriteReg(interface, ENC28J60_REG_EHT7, 0x00);
00144 
00145    //Pull the MAC out of reset
00146    enc28j60WriteReg(interface, ENC28J60_REG_MACON2, 0x00);
00147 
00148    //Enable the MAC to receive frames
00149    enc28j60WriteReg(interface, ENC28J60_REG_MACON1,
00150       MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN);
00151 
00152    //Enable automatic padding to at least 60 bytes, always append a valid CRC
00153    //and check frame length. MAC can operate in half-duplex or full-duplex mode
00154 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED)
00155    enc28j60WriteReg(interface, ENC28J60_REG_MACON3, MACON3_PADCFG(1) |
00156       MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX);
00157 #else
00158    enc28j60WriteReg(interface, ENC28J60_REG_MACON3, MACON3_PADCFG(1) |
00159       MACON3_TXCRCEN | MACON3_FRMLNEN);
00160 #endif
00161 
00162    //When the medium is occupied, the MAC will wait indefinitely for it to
00163    //become free when attempting to transmit
00164    enc28j60WriteReg(interface, ENC28J60_REG_MACON4, MACON4_DEFER);
00165 
00166    //Maximum frame length that can be received or transmitted (1518 bytes)
00167    enc28j60WriteReg(interface, ENC28J60_REG_MAMXFLL, LSB(1518));
00168    enc28j60WriteReg(interface, ENC28J60_REG_MAMXFLH, MSB(1518));
00169 
00170    //Configure the back-to-back inter-packet gap register
00171 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED)
00172    enc28j60WriteReg(interface, ENC28J60_REG_MABBIPG, 0x15);
00173 #else
00174    enc28j60WriteReg(interface, ENC28J60_REG_MABBIPG, 0x12);
00175 #endif
00176 
00177    //Configure the non-back-to-back inter-packet gap register
00178    enc28j60WriteReg(interface, ENC28J60_REG_MAIPGL, 0x12);
00179    enc28j60WriteReg(interface, ENC28J60_REG_MAIPGH, 0x0C);
00180 
00181    //Collision window register
00182    enc28j60WriteReg(interface, ENC28J60_REG_MACLCON2, 63);
00183 
00184    //Set the PHY to the proper duplex mode
00185 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED)
00186    enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHCON1, PHCON1_PDPXMD);
00187 #else
00188    enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHCON1, 0x0000);
00189 #endif
00190 
00191    //Disable half-duplex loopback in PHY
00192    enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHCON2, PHCON2_HDLDIS);
00193 
00194    //LEDA displays link status and LEDB displays TX/RX activity
00195    enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHLCON,
00196       PHLCON_LACFG(4) | PHLCON_LBCFG(7) | PHLCON_LFRQ(0) | PHLCON_STRCH);
00197 
00198    //Clear interrupt flags
00199    enc28j60WriteReg(interface, ENC28J60_REG_EIR, 0x00);
00200 
00201    //Configure interrupts as desired
00202    enc28j60WriteReg(interface, ENC28J60_REG_EIE, EIE_INTIE |
00203       EIE_PKTIE | EIE_LINKIE | EIE_TXIE | EIE_TXERIE);
00204 
00205    //Configure PHY interrupts as desired
00206    enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHIE,
00207       PHIE_PLNKIE | PHIE_PGEIE);
00208 
00209    //Set RXEN to enable reception
00210    enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_RXEN);
00211 
00212    //Dump registers for debugging purpose
00213    enc28j60DumpReg(interface);
00214    enc28j60DumpPhyReg(interface);
00215 
00216    //Accept any packets from the upper layer
00217    osSetEvent(&interface->nicTxEvent);
00218 
00219    //Force the TCP/IP stack to poll the link state at startup
00220    interface->nicEvent = TRUE;
00221    //Notify the TCP/IP stack of the event
00222    osSetEvent(&netEvent);
00223 
00224    //Successful initialization
00225    return NO_ERROR;
00226 }
00227 
00228 
00229 /**
00230  * @brief ENC28J60 timer handler
00231  * @param[in] interface Underlying network interface
00232  **/
00233 
00234 void enc28j60Tick(NetInterface *interface)
00235 {
00236 }
00237 
00238 
00239 /**
00240  * @brief Enable interrupts
00241  * @param[in] interface Underlying network interface
00242  **/
00243 
00244 void enc28j60EnableIrq(NetInterface *interface)
00245 {
00246    //Enable interrupts
00247    interface->extIntDriver->enableIrq();
00248 }
00249 
00250 
00251 /**
00252  * @brief Disable interrupts
00253  * @param[in] interface Underlying network interface
00254  **/
00255 
00256 void enc28j60DisableIrq(NetInterface *interface)
00257 {
00258    //Disable interrupts
00259    interface->extIntDriver->disableIrq();
00260 }
00261 
00262 
00263 /**
00264  * @brief ENC28J60 interrupt service routine
00265  * @param[in] interface Underlying network interface
00266  * @return TRUE if a higher priority task must be woken. Else FALSE is returned
00267  **/
00268 
00269 bool_t enc28j60IrqHandler(NetInterface *interface)
00270 {
00271    bool_t flag;
00272    uint8_t status;
00273 
00274    //This flag will be set if a higher priority task must be woken
00275    flag = FALSE;
00276 
00277    //Clear the INTIE bit, immediately after an interrupt event
00278    enc28j60ClearBit(interface, ENC28J60_REG_EIE, EIE_INTIE);
00279 
00280    //Read interrupt status register
00281    status = enc28j60ReadReg(interface, ENC28J60_REG_EIR);
00282 
00283    //Link status change?
00284    if(status & EIR_LINKIF)
00285    {
00286       //Disable LINKIE interrupt
00287       enc28j60ClearBit(interface, ENC28J60_REG_EIE, EIE_LINKIE);
00288 
00289       //Set event flag
00290       interface->nicEvent = TRUE;
00291       //Notify the TCP/IP stack of the event
00292       flag |= osSetEventFromIsr(&netEvent);
00293    }
00294 
00295    //Packet received?
00296    if(status & EIR_PKTIF)
00297    {
00298       //Disable PKTIE interrupt
00299       enc28j60ClearBit(interface, ENC28J60_REG_EIE, EIE_PKTIE);
00300 
00301       //Set event flag
00302       interface->nicEvent = TRUE;
00303       //Notify the TCP/IP stack of the event
00304       flag |= osSetEventFromIsr(&netEvent);
00305    }
00306 
00307    //Packet transmission complete?
00308    if(status & (EIR_TXIF | EIE_TXERIE))
00309    {
00310       //Clear interrupt flags
00311       enc28j60ClearBit(interface, ENC28J60_REG_EIR, EIR_TXIF | EIE_TXERIE);
00312 
00313       //Notify the TCP/IP stack that the transmitter is ready to send
00314       flag |= osSetEventFromIsr(&interface->nicTxEvent);
00315    }
00316 
00317    //Once the interrupt has been serviced, the INTIE bit
00318    //is set again to re-enable interrupts
00319    enc28j60SetBit(interface, ENC28J60_REG_EIE, EIE_INTIE);
00320 
00321    //A higher priority task must be woken?
00322    return flag;
00323 }
00324 
00325 
00326 /**
00327  * @brief ENC28J60 event handler
00328  * @param[in] interface Underlying network interface
00329  **/
00330 
00331 void enc28j60EventHandler(NetInterface *interface)
00332 {
00333    error_t error;
00334    uint16_t status;
00335    uint16_t value;
00336 
00337    //Read interrupt status register
00338    status = enc28j60ReadReg(interface, ENC28J60_REG_EIR);
00339 
00340    //Check whether the link state has changed
00341    if(status & EIR_LINKIF)
00342    {
00343       //Clear PHY interrupts flags
00344       enc28j60ReadPhyReg(interface, ENC28J60_PHY_REG_PHIR);
00345       //Clear interrupt flag
00346       enc28j60ClearBit(interface, ENC28J60_REG_EIR, EIR_LINKIF);
00347       //Read PHY status register
00348       value = enc28j60ReadPhyReg(interface, ENC28J60_PHY_REG_PHSTAT2);
00349 
00350       //Check link state
00351       if(value & PHSTAT2_LSTAT)
00352       {
00353          //Link speed
00354          interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
00355 
00356 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED)
00357          //Full-duplex mode
00358          interface->duplexMode = NIC_FULL_DUPLEX_MODE;
00359 #else
00360          //Half-duplex mode
00361          interface->duplexMode = NIC_HALF_DUPLEX_MODE;
00362 #endif
00363          //Link is up
00364          interface->linkState = TRUE;
00365       }
00366       else
00367       {
00368          //Link is down
00369          interface->linkState = FALSE;
00370       }
00371 
00372       //Process link state change event
00373       nicNotifyLinkChange(interface);
00374    }
00375 
00376    //Check whether a packet has been received?
00377    if(status & EIR_PKTIF)
00378    {
00379       //Clear interrupt flag
00380       enc28j60ClearBit(interface, ENC28J60_REG_EIR, EIR_PKTIF);
00381 
00382       //Process all pending packets
00383       do
00384       {
00385          //Read incoming packet
00386          error = enc28j60ReceivePacket(interface);
00387 
00388          //No more data in the receive buffer?
00389       } while(error != ERROR_BUFFER_EMPTY);
00390    }
00391 
00392    //Re-enable LINKIE and PKTIE interrupts
00393    enc28j60SetBit(interface, ENC28J60_REG_EIE, EIE_LINKIE | EIE_PKTIE);
00394 }
00395 
00396 
00397 /**
00398  * @brief Send a packet
00399  * @param[in] interface Underlying network interface
00400  * @param[in] buffer Multi-part buffer containing the data to send
00401  * @param[in] offset Offset to the first data byte
00402  * @return Error code
00403  **/
00404 
00405 error_t enc28j60SendPacket(NetInterface *interface,
00406    const NetBuffer *buffer, size_t offset)
00407 {
00408    size_t length;
00409 
00410    //Retrieve the length of the packet
00411    length = netBufferGetLength(buffer) - offset;
00412 
00413    //Check the frame length
00414    if(length > 1536)
00415    {
00416       //The transmitter can accept another packet
00417       osSetEvent(&interface->nicTxEvent);
00418       //Report an error
00419       return ERROR_INVALID_LENGTH;
00420    }
00421 
00422    //Make sure the link is up before transmitting the frame
00423    if(!interface->linkState)
00424    {
00425       //The transmitter can accept another packet
00426       osSetEventFromIsr(&interface->nicTxEvent);
00427       //Drop current packet
00428       return NO_ERROR;
00429    }
00430 
00431    //It is recommended to reset the transmit logic before
00432    //attempting to transmit a packet
00433    enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_TXRST);
00434    enc28j60ClearBit(interface, ENC28J60_REG_ECON1, ECON1_TXRST);
00435 
00436    //Interrupt flags should be cleared after the reset is completed
00437    enc28j60ClearBit(interface, ENC28J60_REG_EIR, EIR_TXIF | EIR_TXERIF);
00438 
00439    //Set transmit buffer location
00440    enc28j60WriteReg(interface, ENC28J60_REG_ETXSTL, LSB(ENC28J60_TX_BUFFER_START));
00441    enc28j60WriteReg(interface, ENC28J60_REG_ETXSTH, MSB(ENC28J60_TX_BUFFER_START));
00442 
00443    //Point to start of transmit buffer
00444    enc28j60WriteReg(interface, ENC28J60_REG_EWRPTL, LSB(ENC28J60_TX_BUFFER_START));
00445    enc28j60WriteReg(interface, ENC28J60_REG_EWRPTH, MSB(ENC28J60_TX_BUFFER_START));
00446 
00447    //Copy the data to the transmit buffer
00448    enc28j60WriteBuffer(interface, buffer, offset);
00449 
00450    //ETXND should point to the last byte in the data payload
00451    enc28j60WriteReg(interface, ENC28J60_REG_ETXNDL, LSB(ENC28J60_TX_BUFFER_START + length));
00452    enc28j60WriteReg(interface, ENC28J60_REG_ETXNDH, MSB(ENC28J60_TX_BUFFER_START + length));
00453 
00454    //Start transmission
00455    enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_TXRTS);
00456 
00457    //Successful processing
00458    return NO_ERROR;
00459 }
00460 
00461 
00462 /**
00463  * @brief Receive a packet
00464  * @param[in] interface Underlying network interface
00465  * @return Error code
00466  **/
00467 
00468 error_t enc28j60ReceivePacket(NetInterface *interface)
00469 {
00470    error_t error;
00471    uint16_t n;
00472    uint16_t status;
00473    Enc28j60Context *context;
00474 
00475    //Point to the driver context
00476    context = (Enc28j60Context *) interface->nicContext;
00477 
00478    //Any packet pending in the receive buffer?
00479    if(enc28j60ReadReg(interface, ENC28J60_REG_EPKTCNT))
00480    {
00481       //Point to the start of the received packet
00482       enc28j60WriteReg(interface, ENC28J60_REG_ERDPTL, LSB(context->nextPacket));
00483       enc28j60WriteReg(interface, ENC28J60_REG_ERDPTH, MSB(context->nextPacket));
00484 
00485       //Read the first two bytes, which are the address of the next packet
00486       enc28j60ReadBuffer(interface, (uint8_t *) &context->nextPacket, sizeof(uint16_t));
00487       //Get the length of the received frame in bytes
00488       enc28j60ReadBuffer(interface, (uint8_t *) &n, sizeof(uint16_t));
00489       //Read the receive status vector (RSV)
00490       enc28j60ReadBuffer(interface, (uint8_t *) &status, sizeof(uint16_t));
00491 
00492       //Make sure no error occurred
00493       if(status & RSV_RECEIVED_OK)
00494       {
00495          //Limit the number of data to read
00496          n = MIN(n, ETH_MAX_FRAME_SIZE);
00497          //Read the Ethernet frame
00498          enc28j60ReadBuffer(interface, context->rxBuffer, n);
00499          //Valid packet received
00500          error = NO_ERROR;
00501       }
00502       else
00503       {
00504          //The received packet contains an error
00505          error = ERROR_INVALID_PACKET;
00506       }
00507 
00508       //Advance the ERXRDPT pointer, taking care to wrap back at the
00509       //end of the received memory buffer
00510       if(context->nextPacket == ENC28J60_RX_BUFFER_START)
00511       {
00512          enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTL, LSB(ENC28J60_RX_BUFFER_STOP));
00513          enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTH, MSB(ENC28J60_RX_BUFFER_STOP));
00514       }
00515       else
00516       {
00517          enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTL, LSB(context->nextPacket - 1));
00518          enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTH, MSB(context->nextPacket - 1));
00519       }
00520 
00521       //Decrement the packet counter
00522       enc28j60SetBit(interface, ENC28J60_REG_ECON2, ECON2_PKTDEC);
00523    }
00524    else
00525    {
00526       //No more data in the receive buffer
00527       error = ERROR_BUFFER_EMPTY;
00528    }
00529 
00530    //Check whether a valid packet has been received
00531    if(!error)
00532    {
00533       //Pass the packet to the upper layer
00534       nicProcessPacket(interface, context->rxBuffer, n);
00535    }
00536 
00537    //Return status code
00538    return error;
00539 }
00540 
00541 
00542 /**
00543  * @brief Configure multicast MAC address filtering
00544  * @param[in] interface Underlying network interface
00545  * @return Error code
00546  **/
00547 
00548 error_t enc28j60SetMulticastFilter(NetInterface *interface)
00549 {
00550    uint_t i;
00551    uint_t k;
00552    uint32_t crc;
00553    uint8_t hashTable[8];
00554    MacFilterEntry *entry;
00555 
00556    //Debug message
00557    TRACE_DEBUG("Updating ENC28J60 hash table...\r\n");
00558 
00559    //Clear hash table
00560    memset(hashTable, 0, sizeof(hashTable));
00561 
00562    //The MAC filter table contains the multicast MAC addresses
00563    //to accept when receiving an Ethernet frame
00564    for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
00565    {
00566       //Point to the current entry
00567       entry = &interface->macMulticastFilter[i];
00568 
00569       //Valid entry?
00570       if(entry->refCount > 0)
00571       {
00572          //Compute CRC over the current MAC address
00573          crc = enc28j60CalcCrc(&entry->addr, sizeof(MacAddr));
00574          //Calculate the corresponding index in the table
00575          k = (crc >> 23) & 0x3F;
00576          //Update hash table contents
00577          hashTable[k / 8] |= (1 << (k % 8));
00578       }
00579    }
00580 
00581    //Write the hash table to the ENC28J60 controller
00582    enc28j60WriteReg(interface, ENC28J60_REG_EHT0, hashTable[0]);
00583    enc28j60WriteReg(interface, ENC28J60_REG_EHT1, hashTable[1]);
00584    enc28j60WriteReg(interface, ENC28J60_REG_EHT2, hashTable[2]);
00585    enc28j60WriteReg(interface, ENC28J60_REG_EHT3, hashTable[3]);
00586    enc28j60WriteReg(interface, ENC28J60_REG_EHT4, hashTable[4]);
00587    enc28j60WriteReg(interface, ENC28J60_REG_EHT5, hashTable[5]);
00588    enc28j60WriteReg(interface, ENC28J60_REG_EHT6, hashTable[6]);
00589    enc28j60WriteReg(interface, ENC28J60_REG_EHT7, hashTable[7]);
00590 
00591    //Debug message
00592    TRACE_DEBUG("  EHT0 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT0));
00593    TRACE_DEBUG("  EHT1 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT1));
00594    TRACE_DEBUG("  EHT2 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT2));
00595    TRACE_DEBUG("  EHT3 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT3));
00596    TRACE_DEBUG("  EHT0 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT4));
00597    TRACE_DEBUG("  EHT1 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT5));
00598    TRACE_DEBUG("  EHT2 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT6));
00599    TRACE_DEBUG("  EHT3 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT7));
00600 
00601    //Successful processing
00602    return NO_ERROR;
00603 }
00604 
00605 
00606 /**
00607  * @brief ENC28J60 controller reset
00608  * @param[in] interface Underlying network interface
00609  **/
00610 
00611 void enc28j60SoftReset(NetInterface *interface)
00612 {
00613    //Pull the CS pin low
00614    interface->spiDriver->assertCs();
00615 
00616    //Write opcode
00617    interface->spiDriver->transfer(ENC28J60_CMD_SRC);
00618 
00619    //Terminate the operation by raising the CS pin
00620    interface->spiDriver->deassertCs();
00621 }
00622 
00623 
00624 /**
00625  * @brief Bank selection
00626  * @param[in] interface Underlying network interface
00627  * @param[in] address Register address
00628  **/
00629 
00630 void enc28j60SelectBank(NetInterface *interface, uint16_t address)
00631 {
00632    uint16_t bank;
00633    Enc28j60Context *context;
00634 
00635    //Point to the driver context
00636    context = (Enc28j60Context *) interface->nicContext;
00637 
00638    //Get the bank number from the specified address
00639    bank = address & REG_BANK_MASK;
00640 
00641    //Rewrite the bank number only if a change is detected
00642    if(bank != context->currentBank)
00643    {
00644       //Select specified bank
00645       switch(bank)
00646       {
00647       case BANK_0:
00648          //Select bank 0
00649          enc28j60ClearBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL1 | ECON1_BSEL0);
00650          break;
00651       case BANK_1:
00652          //Select bank 1
00653          enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL0);
00654          enc28j60ClearBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL1);
00655          break;
00656       case BANK_2:
00657          //Select bank 2
00658          enc28j60ClearBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL0);
00659          enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL1);
00660          break;
00661       case BANK_3:
00662          //Select bank 3
00663          enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL1 | ECON1_BSEL0);
00664          break;
00665       default:
00666          //Invalid bank
00667          break;
00668       }
00669 
00670       //Save bank number
00671       context->currentBank = bank;
00672    }
00673 }
00674 
00675 
00676 /**
00677  * @brief Write ENC28J60 register
00678  * @param[in] interface Underlying network interface
00679  * @param[in] address Register address
00680  * @param[in] data Register value
00681  **/
00682 
00683 void enc28j60WriteReg(NetInterface *interface, uint16_t address, uint8_t data)
00684 {
00685    //Make sure the corresponding bank is selected
00686    enc28j60SelectBank(interface, address);
00687 
00688    //Pull the CS pin low
00689    interface->spiDriver->assertCs();
00690 
00691    //Write opcode and register address
00692    interface->spiDriver->transfer(ENC28J60_CMD_WCR | (address & REG_ADDR_MASK));
00693    //Write register value
00694    interface->spiDriver->transfer(data);
00695 
00696    //Terminate the operation by raising the CS pin
00697    interface->spiDriver->deassertCs();
00698 }
00699 
00700 
00701 /**
00702  * @brief Read ENC28J60 register
00703  * @param[in] interface Underlying network interface
00704  * @param[in] address Register address
00705  * @return Register value
00706  **/
00707 
00708 uint8_t enc28j60ReadReg(NetInterface *interface, uint16_t address)
00709 {
00710    uint16_t data;
00711 
00712    //Make sure the corresponding bank is selected
00713    enc28j60SelectBank(interface, address);
00714 
00715    //Pull the CS pin low
00716    interface->spiDriver->assertCs();
00717 
00718    //Write opcode and register address
00719    interface->spiDriver->transfer(ENC28J60_CMD_RCR | (address & REG_ADDR_MASK));
00720 
00721    //When reading MAC or MII registers, a dummy byte is first shifted out
00722    if((address & REG_TYPE_MASK) != ETH_REG_TYPE)
00723       interface->spiDriver->transfer(0x00);
00724 
00725    //Read register contents
00726    data = interface->spiDriver->transfer(0x00);
00727 
00728    //Terminate the operation by raising the CS pin
00729    interface->spiDriver->deassertCs();
00730 
00731    //Return register contents
00732    return data;
00733 }
00734 
00735 
00736 /**
00737  * @brief Write PHY register
00738  * @param[in] interface Underlying network interface
00739  * @param[in] address PHY register address
00740  * @param[in] data Register value
00741  **/
00742 
00743 void enc28j60WritePhyReg(NetInterface *interface, uint16_t address, uint16_t data)
00744 {
00745    //Write register address
00746    enc28j60WriteReg(interface, ENC28J60_REG_MIREGADR, address & REG_ADDR_MASK);
00747 
00748    //Write the lower 8 bits
00749    enc28j60WriteReg(interface, ENC28J60_REG_MIWRL, LSB(data));
00750    //Write the upper 8 bits
00751    enc28j60WriteReg(interface, ENC28J60_REG_MIWRH, MSB(data));
00752 
00753    //Wait until the PHY register has been written
00754    while(enc28j60ReadReg(interface, ENC28J60_REG_MISTAT) & MISTAT_BUSY);
00755 }
00756 
00757 
00758 /**
00759  * @brief Read PHY register
00760  * @param[in] interface Underlying network interface
00761  * @param[in] address PHY register address
00762  * @return Register value
00763  **/
00764 
00765 uint16_t enc28j60ReadPhyReg(NetInterface *interface, uint16_t address)
00766 {
00767    uint16_t data;
00768 
00769    //Write register address
00770    enc28j60WriteReg(interface, ENC28J60_REG_MIREGADR, address & REG_ADDR_MASK);
00771 
00772    //Start read operation
00773    enc28j60WriteReg(interface, ENC28J60_REG_MICMD, MICMD_MIIRD);
00774    //Wait for the read operation to complete
00775    while(enc28j60ReadReg(interface, ENC28J60_REG_MISTAT) & MISTAT_BUSY);
00776    //Clear command register
00777    enc28j60WriteReg(interface, ENC28J60_REG_MICMD, 0);
00778 
00779    //Read the lower 8 bits
00780    data = enc28j60ReadReg(interface, ENC28J60_REG_MIRDL);
00781    //Read the upper 8 bits
00782    data |= enc28j60ReadReg(interface, ENC28J60_REG_MIRDH) << 8;
00783 
00784    //Return register contents
00785    return data;
00786 }
00787 
00788 
00789 /**
00790  * @brief Write SRAM buffer
00791  * @param[in] interface Underlying network interface
00792  * @param[in] buffer Multi-part buffer containing the data to be written
00793  * @param[in] offset Offset to the first data byte
00794  **/
00795 
00796 void enc28j60WriteBuffer(NetInterface *interface,
00797    const NetBuffer *buffer, size_t offset)
00798 {
00799    uint_t i;
00800    size_t j;
00801    size_t n;
00802    uint8_t *p;
00803 
00804    //Pull the CS pin low
00805    interface->spiDriver->assertCs();
00806 
00807    //Write opcode
00808    interface->spiDriver->transfer(ENC28J60_CMD_WBM);
00809    //Write per-packet control byte
00810    interface->spiDriver->transfer(0x00);
00811 
00812    //Loop through data chunks
00813    for(i = 0; i < buffer->chunkCount; i++)
00814    {
00815       //Is there any data to copy from the current chunk?
00816       if(offset < buffer->chunk[i].length)
00817       {
00818          //Point to the first byte to be read
00819          p = (uint8_t *) buffer->chunk[i].address + offset;
00820          //Compute the number of bytes to copy at a time
00821          n = buffer->chunk[i].length - offset;
00822 
00823          //Copy data to SRAM buffer
00824          for(j = 0; j < n; j++)
00825             interface->spiDriver->transfer(p[j]);
00826 
00827          //Process the next block from the start
00828          offset = 0;
00829       }
00830       else
00831       {
00832          //Skip the current chunk
00833          offset -= buffer->chunk[i].length;
00834       }
00835    }
00836 
00837    //Terminate the operation by raising the CS pin
00838    interface->spiDriver->deassertCs();
00839 }
00840 
00841 
00842 /**
00843  * @brief Read SRAM buffer
00844  * @param[in] interface Underlying network interface
00845  * @param[in] data Buffer where to store the incoming data
00846  * @param[in] length Number of data to read
00847  **/
00848 
00849 void enc28j60ReadBuffer(NetInterface *interface,
00850    uint8_t *data, size_t length)
00851 {
00852    size_t i;
00853 
00854    //Pull the CS pin low
00855    interface->spiDriver->assertCs();
00856 
00857    //Write opcode
00858    interface->spiDriver->transfer(ENC28J60_CMD_RBM);
00859 
00860    //Copy data from SRAM buffer
00861    for(i = 0; i < length; i++)
00862       data[i] = interface->spiDriver->transfer(0x00);
00863 
00864    //Terminate the operation by raising the CS pin
00865    interface->spiDriver->deassertCs();
00866 }
00867 
00868 
00869 /**
00870  * @brief Set bit field
00871  * @param[in] interface Underlying network interface
00872  * @param[in] address Register address
00873  * @param[in] mask Bits to set in the target register
00874  **/
00875 
00876 void enc28j60SetBit(NetInterface *interface, uint16_t address, uint16_t mask)
00877 {
00878    //Pull the CS pin low
00879    interface->spiDriver->assertCs();
00880 
00881    //Write opcode and register address
00882    interface->spiDriver->transfer(ENC28J60_CMD_BFS | (address & REG_ADDR_MASK));
00883    //Write bit mask
00884    interface->spiDriver->transfer(mask);
00885 
00886    //Terminate the operation by raising the CS pin
00887    interface->spiDriver->deassertCs();
00888 }
00889 
00890 
00891 /**
00892  * @brief Clear bit field
00893  * @param[in] interface Underlying network interface
00894  * @param[in] address Register address
00895  * @param[in] mask Bits to clear in the target register
00896  **/
00897 
00898 void enc28j60ClearBit(NetInterface *interface, uint16_t address, uint16_t mask)
00899 {
00900    //Pull the CS pin low
00901    interface->spiDriver->assertCs();
00902 
00903    //Write opcode and register address
00904    interface->spiDriver->transfer(ENC28J60_CMD_BFC | (address & REG_ADDR_MASK));
00905    //Write bit mask
00906    interface->spiDriver->transfer(mask);
00907 
00908    //Terminate the operation by raising the CS pin
00909    interface->spiDriver->deassertCs();
00910 }
00911 
00912 
00913 /**
00914  * @brief CRC calculation using the polynomial 0x4C11DB7
00915  * @param[in] data Pointer to the data over which to calculate the CRC
00916  * @param[in] length Number of bytes to process
00917  * @return Resulting CRC value
00918  **/
00919 
00920 uint32_t enc28j60CalcCrc(const void *data, size_t length)
00921 {
00922    uint_t i;
00923    uint_t j;
00924 
00925    //Point to the data over which to calculate the CRC
00926    const uint8_t *p = (uint8_t *) data;
00927    //CRC preset value
00928    uint32_t crc = 0xFFFFFFFF;
00929 
00930    //Loop through data
00931    for(i = 0; i < length; i++)
00932    {
00933       //The message is processed bit by bit
00934       for(j = 0; j < 8; j++)
00935       {
00936          //Update CRC value
00937          if(((crc >> 31) ^ (p[i] >> j)) & 0x01)
00938             crc = (crc << 1) ^ 0x04C11DB7;
00939          else
00940             crc = crc << 1;
00941       }
00942    }
00943 
00944    //Return CRC value
00945    return crc;
00946 }
00947 
00948 
00949 /**
00950  * @brief Dump registers for debugging purpose
00951  * @param[in] interface Underlying network interface
00952  **/
00953 
00954 void enc28j60DumpReg(NetInterface *interface)
00955 {
00956 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
00957    uint8_t i;
00958    uint8_t bank;
00959    uint16_t address;
00960 
00961    //Display header
00962    TRACE_DEBUG("    Bank 0  Bank 1  Bank 2  Bank 3\r\n");
00963 
00964    //Loop through register addresses
00965    for(i = 0; i < 32; i++)
00966    {
00967       //Display register address
00968       TRACE_DEBUG("%02" PRIX8 ": ", i);
00969 
00970       //Loop through bank numbers
00971       for(bank = 0; bank < 4; bank++)
00972       {
00973          //Format register address
00974          address = (bank << 8) | i;
00975 
00976          //MAC and MII registers require a specific read sequence
00977          if(address >= 0x200 && address <= 0x219)
00978             address |= MAC_REG_TYPE;
00979          else if(address >= 0x300 && address <= 0x305)
00980             address |= MAC_REG_TYPE;
00981          else if(address == 0x30A)
00982             address |= MAC_REG_TYPE;
00983 
00984          //Display register contents
00985          TRACE_DEBUG("0x%02" PRIX8 "    ", enc28j60ReadReg(interface, address));
00986       }
00987 
00988       //Jump to the following line
00989       TRACE_DEBUG("\r\n");
00990    }
00991 
00992    //Terminate with a line feed
00993    TRACE_DEBUG("\r\n");
00994 #endif
00995 }
00996 
00997 
00998 /**
00999  * @brief Dump PHY registers for debugging purpose
01000  * @param[in] interface Underlying network interface
01001  **/
01002 
01003 void enc28j60DumpPhyReg(NetInterface *interface)
01004 {
01005 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
01006    uint8_t i;
01007 
01008    //Loop through PHY registers
01009    for(i = 0; i < 32; i++)
01010    {
01011       //Display current PHY register
01012       TRACE_DEBUG("%02" PRIX8 ": 0x%04" PRIX16 "\r\n", i, enc28j60ReadPhyReg(interface, i));
01013    }
01014 
01015    //Terminate with a line feed
01016    TRACE_DEBUG("\r\n");
01017 #endif
01018 }
01019