Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers enc624j600.c Source File

enc624j600.c

Go to the documentation of this file.
00001 /**
00002  * @file enc624j600.c
00003  * @brief ENC624J600/ENC424J600 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 "core/net.h"
00034 #include "drivers/enc624j600.h"
00035 #include "debug.h"
00036 
00037 
00038 /**
00039  * @brief ENC624J600 driver
00040  **/
00041 
00042 const NicDriver enc624j600Driver =
00043 {
00044    NIC_TYPE_ETHERNET,
00045    ETH_MTU,
00046    enc624j600Init,
00047    enc624j600Tick,
00048    enc624j600EnableIrq,
00049    enc624j600DisableIrq,
00050    enc624j600EventHandler,
00051    enc624j600SendPacket,
00052    enc624j600SetMulticastFilter,
00053    NULL,
00054    NULL,
00055    NULL,
00056    TRUE,
00057    TRUE,
00058    TRUE,
00059    FALSE
00060 };
00061 
00062 
00063 /**
00064  * @brief ENC624J600 controller initialization
00065  * @param[in] interface Underlying network interface
00066  * @return Error code
00067  **/
00068 
00069 error_t enc624j600Init(NetInterface *interface)
00070 {
00071    Enc624j600Context *context;
00072 
00073    //Debug message
00074    TRACE_INFO("Initializing ENC624J600 Ethernet controller...\r\n");
00075 
00076    //Initialize SPI
00077    interface->spiDriver->init();
00078    //Initialize external interrupt line
00079    interface->extIntDriver->init();
00080 
00081    //Point to the driver context
00082    context = (Enc624j600Context *) interface->nicContext;
00083 
00084    //Initialize driver specific variables
00085    context->nextPacket = ENC624J600_RX_BUFFER_START;
00086 
00087    //Allocate RX buffer
00088    context->rxBuffer = memPoolAlloc(ETH_MAX_FRAME_SIZE);
00089    //Failed to allocate memory?
00090    if(context->rxBuffer == NULL)
00091       return ERROR_OUT_OF_MEMORY;
00092 
00093    //Issue a system reset
00094    enc624j600SoftReset(interface);
00095 
00096    //Disable CLKOUT output
00097    enc624j600WriteReg(interface, ENC624J600_REG_ECON2, ECON2_ETHEN | ECON2_STRCH);
00098 
00099    //Optionally set the station MAC address
00100    if(macCompAddr(&interface->macAddr, &MAC_UNSPECIFIED_ADDR))
00101    {
00102       //Use the factory preprogrammed station address
00103       interface->macAddr.w[0] = enc624j600ReadReg(interface, ENC624J600_REG_MAADR1);
00104       interface->macAddr.w[1] = enc624j600ReadReg(interface, ENC624J600_REG_MAADR2);
00105       interface->macAddr.w[2] = enc624j600ReadReg(interface, ENC624J600_REG_MAADR3);
00106 
00107       //Generate the 64-bit interface identifier
00108       macAddrToEui64(&interface->macAddr, &interface->eui64);
00109    }
00110    else
00111    {
00112       //Override the factory preprogrammed address
00113       enc624j600WriteReg(interface, ENC624J600_REG_MAADR1, interface->macAddr.w[0]);
00114       enc624j600WriteReg(interface, ENC624J600_REG_MAADR2, interface->macAddr.w[1]);
00115       enc624j600WriteReg(interface, ENC624J600_REG_MAADR3, interface->macAddr.w[2]);
00116    }
00117 
00118    //Set receive buffer location
00119    enc624j600WriteReg(interface, ENC624J600_REG_ERXST, ENC624J600_RX_BUFFER_START);
00120    //Program the tail pointer ERXTAIL to the last even address of the buffer
00121    enc624j600WriteReg(interface, ENC624J600_REG_ERXTAIL, ENC624J600_RX_BUFFER_STOP);
00122 
00123    //Configure the receive filters
00124    enc624j600WriteReg(interface, ENC624J600_REG_ERXFCON, ERXFCON_HTEN |
00125       ERXFCON_CRCEN | ERXFCON_RUNTEN | ERXFCON_UCEN | ERXFCON_BCEN);
00126 
00127    //Initialize the hash table
00128    enc624j600WriteReg(interface, ENC624J600_REG_EHT1, 0x0000);
00129    enc624j600WriteReg(interface, ENC624J600_REG_EHT2, 0x0000);
00130    enc624j600WriteReg(interface, ENC624J600_REG_EHT3, 0x0000);
00131    enc624j600WriteReg(interface, ENC624J600_REG_EHT4, 0x0000);
00132 
00133    //All short frames will be zero-padded to 60 bytes and a valid CRC is then appended
00134    enc624j600WriteReg(interface, ENC624J600_REG_MACON2,
00135       MACON2_DEFER | MACON2_PADCFG0 | MACON2_TXCRCEN | MACON2_R1);
00136 
00137    //Program the MAMXFL register with the maximum frame length to be accepted
00138    enc624j600WriteReg(interface, ENC624J600_REG_MAMXFL, 1518);
00139 
00140    //PHY initialization
00141    enc624j600WritePhyReg(interface, ENC624J600_PHY_REG_PHANA, PHANA_ADPAUS0 |
00142       PHANA_AD100FD | PHANA_AD100 | PHANA_AD10FD | PHANA_AD10 | PHANA_ADIEEE0);
00143 
00144    //Clear interrupt flags
00145    enc624j600WriteReg(interface, ENC624J600_REG_EIR, 0x0000);
00146 
00147    //Configure interrupts as desired
00148    enc624j600WriteReg(interface, ENC624J600_REG_EIE, EIE_INTIE |
00149       EIE_LINKIE | EIE_PKTIE | EIE_TXIE | EIE_TXABTIE);
00150 
00151    //Set RXEN to enable reception
00152    enc624j600SetBit(interface, ENC624J600_REG_ECON1, ECON1_RXEN);
00153 
00154    //Dump registers for debugging purpose
00155    enc624j600DumpReg(interface);
00156    enc624j600DumpPhyReg(interface);
00157 
00158    //Accept any packets from the upper layer
00159    osSetEvent(&interface->nicTxEvent);
00160 
00161    //Force the TCP/IP stack to poll the link state at startup
00162    interface->nicEvent = TRUE;
00163    //Notify the TCP/IP stack of the event
00164    osSetEvent(&netEvent);
00165 
00166    //Successful initialization
00167    return NO_ERROR;
00168 }
00169 
00170 
00171 /**
00172  * @brief ENC624J600 timer handler
00173  * @param[in] interface Underlying network interface
00174  **/
00175 
00176 void enc624j600Tick(NetInterface *interface)
00177 {
00178 }
00179 
00180 
00181 /**
00182  * @brief Enable interrupts
00183  * @param[in] interface Underlying network interface
00184  **/
00185 
00186 void enc624j600EnableIrq(NetInterface *interface)
00187 {
00188    //Enable interrupts
00189    interface->extIntDriver->enableIrq();
00190 }
00191 
00192 
00193 /**
00194  * @brief Disable interrupts
00195  * @param[in] interface Underlying network interface
00196  **/
00197 
00198 void enc624j600DisableIrq(NetInterface *interface)
00199 {
00200    //Disable interrupts
00201    interface->extIntDriver->disableIrq();
00202 }
00203 
00204 
00205 /**
00206  * @brief ENC624J600 interrupt service routine
00207  * @param[in] interface Underlying network interface
00208  * @return TRUE if a higher priority task must be woken. Else FALSE is returned
00209  **/
00210 
00211 bool_t enc624j600IrqHandler(NetInterface *interface)
00212 {
00213    bool_t flag;
00214    uint16_t status;
00215 
00216    //This flag will be set if a higher priority task must be woken
00217    flag = FALSE;
00218 
00219    //Clear the INTIE bit, immediately after an interrupt event
00220    enc624j600ClearBit(interface, ENC624J600_REG_EIE, EIE_INTIE);
00221 
00222    //Read interrupt status register
00223    status = enc624j600ReadReg(interface, ENC624J600_REG_EIR);
00224 
00225    //Link status change?
00226    if(status & EIR_LINKIF)
00227    {
00228       //Disable LINKIE interrupt
00229       enc624j600ClearBit(interface, ENC624J600_REG_EIE, EIE_LINKIE);
00230 
00231       //Set event flag
00232       interface->nicEvent = TRUE;
00233       //Notify the TCP/IP stack of the event
00234       flag |= osSetEventFromIsr(&netEvent);
00235    }
00236 
00237    //Packet received?
00238    if(status & EIR_PKTIF)
00239    {
00240       //Disable PKTIE interrupt
00241       enc624j600ClearBit(interface, ENC624J600_REG_EIE, EIE_PKTIE);
00242 
00243       //Set event flag
00244       interface->nicEvent = TRUE;
00245       //Notify the TCP/IP stack of the event
00246       flag |= osSetEventFromIsr(&netEvent);
00247    }
00248 
00249    //Packet transmission complete?
00250    if(status & (EIR_TXIF | EIR_TXABTIF))
00251    {
00252       //Clear interrupt flags
00253       enc624j600ClearBit(interface, ENC624J600_REG_EIR, EIR_TXIF | EIR_TXABTIF);
00254 
00255       //Notify the TCP/IP stack that the transmitter is ready to send
00256       flag |= osSetEventFromIsr(&interface->nicTxEvent);
00257    }
00258 
00259    //Once the interrupt has been serviced, the INTIE bit
00260    //is set again to re-enable interrupts
00261    enc624j600SetBit(interface, ENC624J600_REG_EIE, EIE_INTIE);
00262 
00263    //A higher priority task must be woken?
00264    return flag;
00265 }
00266 
00267 
00268 /**
00269  * @brief ENC624J600 event handler
00270  * @param[in] interface Underlying network interface
00271  **/
00272 
00273 void enc624j600EventHandler(NetInterface *interface)
00274 {
00275    error_t error;
00276    uint16_t status;
00277    uint16_t value;
00278 
00279    //Read interrupt status register
00280    status = enc624j600ReadReg(interface, ENC624J600_REG_EIR);
00281 
00282    //Check whether the link state has changed
00283    if(status & EIR_LINKIF)
00284    {
00285       //Clear interrupt flag
00286       enc624j600ClearBit(interface, ENC624J600_REG_EIR, EIR_LINKIF);
00287       //Read Ethernet status register
00288       value = enc624j600ReadReg(interface, ENC624J600_REG_ESTAT);
00289 
00290       //Check link state
00291       if(value & ESTAT_PHYLNK)
00292       {
00293          //Read PHY status register 3
00294          value = enc624j600ReadPhyReg(interface, ENC624J600_PHY_REG_PHSTAT3);
00295 
00296          //Get current speed
00297          if(value & PHSTAT3_SPDDPX1)
00298             interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
00299          else
00300             interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
00301 
00302          //Determine the new duplex mode
00303          if(value & PHSTAT3_SPDDPX2)
00304             interface->duplexMode = NIC_FULL_DUPLEX_MODE;
00305          else
00306             interface->duplexMode = NIC_HALF_DUPLEX_MODE;
00307 
00308          //Link is up
00309          interface->linkState = TRUE;
00310 
00311          //Update MAC configuration parameters for proper operation
00312          enc624j600UpdateMacConfig(interface);
00313       }
00314       else
00315       {
00316          //Link is down
00317          interface->linkState = FALSE;
00318       }
00319 
00320       //Process link state change event
00321       nicNotifyLinkChange(interface);
00322    }
00323 
00324    //Check whether a packet has been received?
00325    if(status & EIR_PKTIF)
00326    {
00327       //Clear interrupt flag
00328       enc624j600ClearBit(interface, ENC624J600_REG_EIR, EIR_PKTIF);
00329 
00330       //Process all pending packets
00331       do
00332       {
00333          //Read incoming packet
00334          error = enc624j600ReceivePacket(interface);
00335 
00336          //No more data in the receive buffer?
00337       } while(error != ERROR_BUFFER_EMPTY);
00338    }
00339 
00340    //Re-enable LINKIE and PKTIE interrupts
00341    enc624j600SetBit(interface, ENC624J600_REG_EIE, EIE_LINKIE | EIE_PKTIE);
00342 }
00343 
00344 
00345 /**
00346  * @brief Send a packet
00347  * @param[in] interface Underlying network interface
00348  * @param[in] buffer Multi-part buffer containing the data to send
00349  * @param[in] offset Offset to the first data byte
00350  * @return Error code
00351  **/
00352 
00353 error_t enc624j600SendPacket(NetInterface *interface,
00354    const NetBuffer *buffer, size_t offset)
00355 {
00356    size_t length;
00357 
00358    //Retrieve the length of the packet
00359    length = netBufferGetLength(buffer) - offset;
00360 
00361    //Check the frame length
00362    if(length > 1536)
00363    {
00364       //The transmitter can accept another packet
00365       osSetEvent(&interface->nicTxEvent);
00366       //Report an error
00367       return ERROR_INVALID_LENGTH;
00368    }
00369 
00370    //Make sure the link is up before transmitting the frame
00371    if(!interface->linkState)
00372    {
00373       //The transmitter can accept another packet
00374       osSetEventFromIsr(&interface->nicTxEvent);
00375       //Drop current packet
00376       return NO_ERROR;
00377    }
00378 
00379    //Ensure that the transmitter is ready to send
00380    if(enc624j600ReadReg(interface, ENC624J600_REG_ECON1) & ECON1_TXRTS)
00381       return ERROR_FAILURE;
00382 
00383    //Point to the SRAM buffer
00384    enc624j600WriteReg(interface, ENC624J600_REG_EGPWRPT, ENC624J600_TX_BUFFER_START);
00385    //Copy the packet to the SRAM buffer
00386    enc624j600WriteBuffer(interface, ENC624J600_CMD_WGPDATA, buffer, offset);
00387 
00388    //Program ETXST to the start address of the packet
00389    enc624j600WriteReg(interface, ENC624J600_REG_ETXST, ENC624J600_TX_BUFFER_START);
00390    //Program ETXLEN with the length of data copied to the memory
00391    enc624j600WriteReg(interface, ENC624J600_REG_ETXLEN, length);
00392 
00393    //Clear TXIF and TXABTIF interrupt flags
00394    enc624j600ClearBit(interface, ENC624J600_REG_EIR, EIR_TXIF | EIR_TXABTIF);
00395    //Set the TXRTS bit to initiate transmission
00396    enc624j600SetBit(interface, ENC624J600_REG_ECON1, ECON1_TXRTS);
00397 
00398    //Successful processing
00399    return NO_ERROR;
00400 }
00401 
00402 
00403 /**
00404  * @brief Receive a packet
00405  * @param[in] interface Underlying network interface
00406  * @return Error code
00407  **/
00408 
00409 error_t enc624j600ReceivePacket(NetInterface *interface)
00410 {
00411    error_t error;
00412    uint16_t n;
00413    uint32_t status;
00414    Enc624j600Context *context;
00415 
00416    //Point to the driver context
00417    context = (Enc624j600Context *) interface->nicContext;
00418 
00419    //Verify that a packet is waiting by ensuring that PKTCNT is non-zero
00420    if(enc624j600ReadReg(interface, ENC624J600_REG_ESTAT) & ESTAT_PKTCNT)
00421    {
00422       //Point to the next packet
00423       enc624j600WriteReg(interface, ENC624J600_REG_ERXRDPT, context->nextPacket);
00424 
00425       //Read the first two bytes, which are the address of the next packet
00426       enc624j600ReadBuffer(interface, ENC624J600_CMD_RRXDATA,
00427          (uint8_t *) &context->nextPacket, sizeof(uint16_t));
00428 
00429       //Get the length of the received frame in bytes
00430       enc624j600ReadBuffer(interface, ENC624J600_CMD_RRXDATA,
00431          (uint8_t *) &n, sizeof(uint16_t));
00432 
00433       //Read the receive status vector (RSV)
00434       enc624j600ReadBuffer(interface, ENC624J600_CMD_RRXDATA,
00435          (uint8_t *) &status, sizeof(uint32_t));
00436 
00437       //Make sure no error occurred
00438       if(status & RSV_RECEIVED_OK)
00439       {
00440          //Limit the number of data to read
00441          n = MIN(n, ETH_MAX_FRAME_SIZE);
00442          //Read the Ethernet frame
00443          enc624j600ReadBuffer(interface, ENC624J600_CMD_RRXDATA, context->rxBuffer, n);
00444          //Valid packet received
00445          error = NO_ERROR;
00446       }
00447       else
00448       {
00449          //The received packet contains an error
00450          error = ERROR_INVALID_PACKET;
00451       }
00452 
00453       //Update the ERXTAIL pointer value to the point where the packet
00454       //has been processed, taking care to wrap back at the end of the
00455       //received memory buffer
00456       if(context->nextPacket == ENC624J600_RX_BUFFER_START)
00457          enc624j600WriteReg(interface, ENC624J600_REG_ERXTAIL, ENC624J600_RX_BUFFER_STOP);
00458       else
00459          enc624j600WriteReg(interface, ENC624J600_REG_ERXTAIL, context->nextPacket - 2);
00460 
00461       //Set PKTDEC to decrement the PKTCNT bits
00462       enc624j600SetBit(interface, ENC624J600_REG_ECON1, ECON1_PKTDEC);
00463    }
00464    else
00465    {
00466       //No more data in the receive buffer
00467       error = ERROR_BUFFER_EMPTY;
00468    }
00469 
00470    //Check whether a valid packet has been received
00471    if(!error)
00472    {
00473       //Pass the packet to the upper layer
00474       nicProcessPacket(interface, context->rxBuffer, n);
00475    }
00476 
00477    //Return status code
00478    return error;
00479 }
00480 
00481 
00482 /**
00483  * @brief Configure multicast MAC address filtering
00484  * @param[in] interface Underlying network interface
00485  * @return Error code
00486  **/
00487 
00488 error_t enc624j600SetMulticastFilter(NetInterface *interface)
00489 {
00490    uint_t i;
00491    uint_t k;
00492    uint32_t crc;
00493    uint16_t hashTable[4];
00494    MacFilterEntry *entry;
00495 
00496    //Debug message
00497    TRACE_DEBUG("Updating ENC624J600 hash table...\r\n");
00498 
00499    //Clear hash table
00500    memset(hashTable, 0, sizeof(hashTable));
00501 
00502    //The MAC filter table contains the multicast MAC addresses
00503    //to accept when receiving an Ethernet frame
00504    for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
00505    {
00506       //Point to the current entry
00507       entry = &interface->macMulticastFilter[i];
00508 
00509       //Valid entry?
00510       if(entry->refCount > 0)
00511       {
00512          //Compute CRC over the current MAC address
00513          crc = enc624j600CalcCrc(&entry->addr, sizeof(MacAddr));
00514          //Calculate the corresponding index in the table
00515          k = (crc >> 23) & 0x3F;
00516          //Update hash table contents
00517          hashTable[k / 16] |= (1 << (k % 16));
00518       }
00519    }
00520 
00521    //Write the hash table to the ENC624J600 controller
00522    enc624j600WriteReg(interface, ENC624J600_REG_EHT1, hashTable[0]);
00523    enc624j600WriteReg(interface, ENC624J600_REG_EHT2, hashTable[1]);
00524    enc624j600WriteReg(interface, ENC624J600_REG_EHT3, hashTable[2]);
00525    enc624j600WriteReg(interface, ENC624J600_REG_EHT4, hashTable[3]);
00526 
00527    //Debug message
00528    TRACE_DEBUG("  EHT1 = %04" PRIX16 "\r\n", enc624j600ReadReg(interface, ENC624J600_REG_EHT1));
00529    TRACE_DEBUG("  EHT2 = %04" PRIX16 "\r\n", enc624j600ReadReg(interface, ENC624J600_REG_EHT2));
00530    TRACE_DEBUG("  EHT3 = %04" PRIX16 "\r\n", enc624j600ReadReg(interface, ENC624J600_REG_EHT3));
00531    TRACE_DEBUG("  EHT4 = %04" PRIX16 "\r\n", enc624j600ReadReg(interface, ENC624J600_REG_EHT4));
00532 
00533    //Successful processing
00534    return NO_ERROR;
00535 }
00536 
00537 
00538 /**
00539  * @brief Adjust MAC configuration parameters for proper operation
00540  * @param[in] interface Underlying network interface
00541  **/
00542 
00543 void enc624j600UpdateMacConfig(NetInterface *interface)
00544 {
00545    uint16_t duplexMode;
00546 
00547    //Determine the new duplex mode by reading the PHYDPX bit
00548    duplexMode = enc624j600ReadReg(interface, ENC624J600_REG_ESTAT) & ESTAT_PHYDPX;
00549 
00550    //Full-duplex mode?
00551    if(duplexMode)
00552    {
00553       //Configure the FULDPX bit to match the current duplex mode
00554       enc624j600WriteReg(interface, ENC624J600_REG_MACON2, MACON2_DEFER |
00555          MACON2_PADCFG2 | MACON2_PADCFG0 | MACON2_TXCRCEN | MACON2_R1 | MACON2_FULDPX);
00556       //Configure the Back-to-Back Inter-Packet Gap register
00557       enc624j600WriteReg(interface, ENC624J600_REG_MABBIPG, 0x15);
00558    }
00559    //Half-duplex mode?
00560    else
00561    {
00562       //Configure the FULDPX bit to match the current duplex mode
00563       enc624j600WriteReg(interface, ENC624J600_REG_MACON2, MACON2_DEFER |
00564          MACON2_PADCFG2 | MACON2_PADCFG0 | MACON2_TXCRCEN | MACON2_R1);
00565       //Configure the Back-to-Back Inter-Packet Gap register
00566       enc624j600WriteReg(interface, ENC624J600_REG_MABBIPG, 0x12);
00567    }
00568 }
00569 
00570 
00571 /**
00572  * @brief Reset ENC624J600 controller
00573  * @param[in] interface Underlying network interface
00574  * @return Error code
00575  **/
00576 
00577 error_t enc624j600SoftReset(NetInterface *interface)
00578 {
00579    //Wait for the SPI interface to be ready
00580    do
00581    {
00582       //Write 0x1234 to EUDAST
00583       enc624j600WriteReg(interface, ENC624J600_REG_EUDAST, 0x1234);
00584       //Read back register and check contents
00585    } while(enc624j600ReadReg(interface, ENC624J600_REG_EUDAST) != 0x1234);
00586 
00587    //Poll CLKRDY and wait for it to become set
00588    while(!(enc624j600ReadReg(interface, ENC624J600_REG_ESTAT) & ESTAT_CLKRDY));
00589 
00590    //Issue a system reset command by setting ETHRST
00591    enc624j600SetBit(interface, ENC624J600_REG_ECON2, ECON2_ETHRST);
00592    //Wait at least 25us for the reset to take place
00593    sleep(1);
00594 
00595    //Read EUDAST to confirm that the system reset took place.
00596    //EUDAST should have reverted back to its reset default
00597    if(enc624j600ReadReg(interface, ENC624J600_REG_EUDAST) != 0x0000)
00598       return ERROR_FAILURE;
00599 
00600    //Wait at least 256us for the PHY registers and PHY
00601    //status bits to become available
00602    sleep(1);
00603 
00604    //The controller is now ready to accept further commands
00605    return NO_ERROR;
00606 }
00607 
00608 
00609 /**
00610  * @brief Write ENC624J600 register
00611  * @param[in] interface Underlying network interface
00612  * @param[in] address Register address
00613  * @param[in] data Register value
00614  **/
00615 
00616 void enc624j600WriteReg(NetInterface *interface, uint8_t address, uint16_t data)
00617 {
00618    //Pull the CS pin low
00619    interface->spiDriver->assertCs();
00620 
00621    //Write opcode
00622    interface->spiDriver->transfer(ENC624J600_CMD_WCRU);
00623    //Write register address
00624    interface->spiDriver->transfer(address);
00625    //Write register value
00626    interface->spiDriver->transfer(LSB(data));
00627    interface->spiDriver->transfer(MSB(data));
00628 
00629    //Terminate the operation by raising the CS pin
00630    interface->spiDriver->deassertCs();
00631 }
00632 
00633 
00634 /**
00635  * @brief Read ENC624J600 register
00636  * @param[in] interface Underlying network interface
00637  * @param[in] address Register address
00638  * @return Register value
00639  **/
00640 
00641 uint16_t enc624j600ReadReg(NetInterface *interface, uint8_t address)
00642 {
00643    uint16_t data;
00644 
00645    //Pull the CS pin low
00646    interface->spiDriver->assertCs();
00647 
00648    //Write opcode
00649    interface->spiDriver->transfer(ENC624J600_CMD_RCRU);
00650    //Write register address
00651    interface->spiDriver->transfer(address);
00652    //Read the lower 8 bits of data
00653    data = interface->spiDriver->transfer(0x00);
00654    //Read the upper 8 bits of data
00655    data |= interface->spiDriver->transfer(0x00) << 8;
00656 
00657    //Terminate the operation by raising the CS pin
00658    interface->spiDriver->deassertCs();
00659 
00660    //Return register contents
00661    return data;
00662 }
00663 
00664 
00665 /**
00666  * @brief Write PHY register
00667  * @param[in] interface Underlying network interface
00668  * @param[in] address PHY register address
00669  * @param[in] data Register value
00670  **/
00671 
00672 void enc624j600WritePhyReg(NetInterface *interface, uint8_t address, uint16_t data)
00673 {
00674    //Write the address of the PHY register to write to
00675    enc624j600WriteReg(interface, ENC624J600_REG_MIREGADR, MIREGADR_R8 | address);
00676    //Write the 16 bits of data into the MIWR register
00677    enc624j600WriteReg(interface, ENC624J600_REG_MIWR, data);
00678 
00679    //Wait until the PHY register has been written
00680    while(enc624j600ReadReg(interface, ENC624J600_REG_MISTAT) & MISTAT_BUSY);
00681 }
00682 
00683 
00684 /**
00685  * @brief Read PHY register
00686  * @param[in] interface Underlying network interface
00687  * @param[in] address PHY register address
00688  * @return Register value
00689  **/
00690 
00691 uint16_t enc624j600ReadPhyReg(NetInterface *interface, uint8_t address)
00692 {
00693    //Write the address of the PHY register to read from
00694    enc624j600WriteReg(interface, ENC624J600_REG_MIREGADR, MIREGADR_R8 | address);
00695    //Start read operation
00696    enc624j600WriteReg(interface, ENC624J600_REG_MICMD, MICMD_MIIRD);
00697 
00698    //Wait at least 25.6us before polling the BUSY bit
00699    usleep(100);
00700    //Wait for the read operation to complete
00701    while(enc624j600ReadReg(interface, ENC624J600_REG_MISTAT) & MISTAT_BUSY);
00702 
00703    //Clear command register
00704    enc624j600WriteReg(interface, ENC624J600_REG_MICMD, 0x00);
00705 
00706    //Return register contents
00707    return enc624j600ReadReg(interface, ENC624J600_REG_MIRD);
00708 }
00709 
00710 
00711 /**
00712  * @brief Write SRAM buffer
00713  * @param[in] interface Underlying network interface
00714  * @param[in] opcode SRAM buffer operation
00715  * @param[in] buffer Multi-part buffer containing the data to be written
00716  * @param[in] offset Offset to the first data byte
00717  **/
00718 
00719 void enc624j600WriteBuffer(NetInterface *interface,
00720    uint8_t opcode, const NetBuffer *buffer, size_t offset)
00721 {
00722    uint_t i;
00723    size_t j;
00724    size_t n;
00725    uint8_t *p;
00726 
00727    //Pull the CS pin low
00728    interface->spiDriver->assertCs();
00729 
00730    //Write opcode
00731    interface->spiDriver->transfer(opcode);
00732 
00733    //Loop through data chunks
00734    for(i = 0; i < buffer->chunkCount; i++)
00735    {
00736       //Is there any data to copy from the current chunk?
00737       if(offset < buffer->chunk[i].length)
00738       {
00739          //Point to the first byte to be read
00740          p = (uint8_t *) buffer->chunk[i].address + offset;
00741          //Compute the number of bytes to copy at a time
00742          n = buffer->chunk[i].length - offset;
00743 
00744          //Copy data to SRAM buffer
00745          for(j = 0; j < n; j++)
00746             interface->spiDriver->transfer(p[j]);
00747 
00748          //Process the next block from the start
00749          offset = 0;
00750       }
00751       else
00752       {
00753          //Skip the current chunk
00754          offset -= buffer->chunk[i].length;
00755       }
00756    }
00757 
00758    //Terminate the operation by raising the CS pin
00759    interface->spiDriver->deassertCs();
00760 }
00761 
00762 
00763 /**
00764  * @brief Read SRAM buffer
00765  * @param[in] interface Underlying network interface
00766  * @param[in] opcode SRAM buffer operation
00767  * @param[in] data Buffer where to store the incoming data
00768  * @param[in] length Number of data to read
00769  **/
00770 
00771 void enc624j600ReadBuffer(NetInterface *interface,
00772    uint8_t opcode, uint8_t *data, size_t length)
00773 {
00774    size_t i;
00775 
00776    //Pull the CS pin low
00777    interface->spiDriver->assertCs();
00778 
00779    //Write opcode
00780    interface->spiDriver->transfer(opcode);
00781 
00782    //Copy data from SRAM buffer
00783    for(i = 0; i < length; i++)
00784       data[i] = interface->spiDriver->transfer(0x00);
00785 
00786    //Terminate the operation by raising the CS pin
00787    interface->spiDriver->deassertCs();
00788 }
00789 
00790 
00791 /**
00792  * @brief Set bit field
00793  * @param[in] interface Underlying network interface
00794  * @param[in] address Register address
00795  * @param[in] mask Bits to set in the target register
00796  **/
00797 
00798 void enc624j600SetBit(NetInterface *interface, uint8_t address, uint16_t mask)
00799 {
00800    //Pull the CS pin low
00801    interface->spiDriver->assertCs();
00802 
00803    //Write opcode
00804    interface->spiDriver->transfer(ENC624J600_CMD_BFSU);
00805    //Write register address
00806    interface->spiDriver->transfer(address);
00807    //Write bit mask
00808    interface->spiDriver->transfer(LSB(mask));
00809    interface->spiDriver->transfer(MSB(mask));
00810 
00811    //Terminate the operation by raising the CS pin
00812    interface->spiDriver->deassertCs();
00813 }
00814 
00815 
00816 /**
00817  * @brief Clear bit field
00818  * @param[in] interface Underlying network interface
00819  * @param[in] address Register address
00820  * @param[in] mask Bits to clear in the target register
00821  **/
00822 
00823 void enc624j600ClearBit(NetInterface *interface, uint8_t address, uint16_t mask)
00824 {
00825    //Pull the CS pin low
00826    interface->spiDriver->assertCs();
00827 
00828    //Write opcode
00829    interface->spiDriver->transfer(ENC624J600_CMD_BFCU);
00830    //Write register address
00831    interface->spiDriver->transfer(address);
00832    //Write bit mask
00833    interface->spiDriver->transfer(LSB(mask));
00834    interface->spiDriver->transfer(MSB(mask));
00835 
00836    //Terminate the operation by raising the CS pin
00837    interface->spiDriver->deassertCs();
00838 }
00839 
00840 
00841 /**
00842  * @brief CRC calculation using the polynomial 0x4C11DB7
00843  * @param[in] data Pointer to the data over which to calculate the CRC
00844  * @param[in] length Number of bytes to process
00845  * @return Resulting CRC value
00846  **/
00847 
00848 uint32_t enc624j600CalcCrc(const void *data, size_t length)
00849 {
00850    uint_t i;
00851    uint_t j;
00852 
00853    //Point to the data over which to calculate the CRC
00854    const uint8_t *p = (uint8_t *) data;
00855    //CRC preset value
00856    uint32_t crc = 0xFFFFFFFF;
00857 
00858    //Loop through data
00859    for(i = 0; i < length; i++)
00860    {
00861       //The message is processed bit by bit
00862       for(j = 0; j < 8; j++)
00863       {
00864          //Update CRC value
00865          if(((crc >> 31) ^ (p[i] >> j)) & 0x01)
00866             crc = (crc << 1) ^ 0x04C11DB7;
00867          else
00868             crc = crc << 1;
00869       }
00870    }
00871 
00872    //Return CRC value
00873    return crc;
00874 }
00875 
00876 
00877 /**
00878  * @brief Dump registers for debugging purpose
00879  * @param[in] interface Underlying network interface
00880  **/
00881 
00882 void enc624j600DumpReg(NetInterface *interface)
00883 {
00884 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
00885    uint8_t i;
00886    uint8_t bank;
00887    uint16_t address;
00888 
00889    //Display header
00890    TRACE_DEBUG("    Bank 0  Bank 1  Bank 2  Bank 3  Unbanked\r\n");
00891 
00892    //Loop through register addresses
00893    for(i = 0; i < 32; i += 2)
00894    {
00895       //Display register address
00896       TRACE_DEBUG("%02" PRIX8 ": ", i);
00897 
00898       //Loop through bank numbers
00899       for(bank = 0; bank < 5; bank++)
00900       {
00901          //Format register address
00902          address = 0x7E00 | (bank << 5) | i;
00903          //Display register contents
00904          TRACE_DEBUG("0x%04" PRIX16 "  ", enc624j600ReadReg(interface, address));
00905       }
00906 
00907       //Jump to the following line
00908       TRACE_DEBUG("\r\n");
00909    }
00910 
00911    //Terminate with a line feed
00912    TRACE_DEBUG("\r\n");
00913 #endif
00914 }
00915 
00916 
00917 /**
00918  * @brief Dump PHY registers for debugging purpose
00919  * @param[in] interface Underlying network interface
00920  **/
00921 
00922 void enc624j600DumpPhyReg(NetInterface *interface)
00923 {
00924 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
00925    uint8_t i;
00926 
00927    //Loop through PHY registers
00928    for(i = 0; i < 32; i++)
00929    {
00930       //Display current PHY register
00931       TRACE_DEBUG("%02" PRIX8 ": 0x%04" PRIX16 "\r\n", i, enc624j600ReadPhyReg(interface, i));
00932    }
00933 
00934    //Terminate with a line feed
00935    TRACE_DEBUG("\r\n");
00936 #endif
00937 }
00938