Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lpc18xx_eth.c Source File

lpc18xx_eth.c

Go to the documentation of this file.
00001 /**
00002  * @file lpc18xx_eth.c
00003  * @brief LPC1800 Ethernet MAC 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 "lpc18xx.h"
00034 #include "core/net.h"
00035 #include "drivers/lpc18xx_eth.h"
00036 #include "debug.h"
00037 
00038 //Underlying network interface
00039 static NetInterface *nicDriverInterface;
00040 
00041 //IAR EWARM compiler?
00042 #if defined(__ICCARM__)
00043 
00044 //Transmit buffer
00045 #pragma data_alignment = 4
00046 static uint8_t txBuffer[LPC18XX_ETH_TX_BUFFER_COUNT][LPC18XX_ETH_TX_BUFFER_SIZE];
00047 //Receive buffer
00048 #pragma data_alignment = 4
00049 static uint8_t rxBuffer[LPC18XX_ETH_RX_BUFFER_COUNT][LPC18XX_ETH_RX_BUFFER_SIZE];
00050 //Transmit DMA descriptors
00051 #pragma data_alignment = 4
00052 static Lpc18xxTxDmaDesc txDmaDesc[LPC18XX_ETH_TX_BUFFER_COUNT];
00053 //Receive DMA descriptors
00054 #pragma data_alignment = 4
00055 static Lpc18xxRxDmaDesc rxDmaDesc[LPC18XX_ETH_RX_BUFFER_COUNT];
00056 
00057 //ARM or GCC compiler?
00058 #else
00059 
00060 //Transmit buffer
00061 static uint8_t txBuffer[LPC18XX_ETH_TX_BUFFER_COUNT][LPC18XX_ETH_TX_BUFFER_SIZE]
00062    __attribute__((aligned(4)));
00063 //Receive buffer
00064 static uint8_t rxBuffer[LPC18XX_ETH_RX_BUFFER_COUNT][LPC18XX_ETH_RX_BUFFER_SIZE]
00065    __attribute__((aligned(4)));
00066 //Transmit DMA descriptors
00067 static Lpc18xxTxDmaDesc txDmaDesc[LPC18XX_ETH_TX_BUFFER_COUNT]
00068    __attribute__((aligned(4)));
00069 //Receive DMA descriptors
00070 static Lpc18xxRxDmaDesc rxDmaDesc[LPC18XX_ETH_RX_BUFFER_COUNT]
00071    __attribute__((aligned(4)));
00072 
00073 #endif
00074 
00075 //Pointer to the current TX DMA descriptor
00076 static Lpc18xxTxDmaDesc *txCurDmaDesc;
00077 //Pointer to the current RX DMA descriptor
00078 static Lpc18xxRxDmaDesc *rxCurDmaDesc;
00079 
00080 
00081 /**
00082  * @brief LPC18xx Ethernet MAC driver
00083  **/
00084 
00085 const NicDriver lpc18xxEthDriver =
00086 {
00087    NIC_TYPE_ETHERNET,
00088    ETH_MTU,
00089    lpc18xxEthInit,
00090    lpc18xxEthTick,
00091    lpc18xxEthEnableIrq,
00092    lpc18xxEthDisableIrq,
00093    lpc18xxEthEventHandler,
00094    lpc18xxEthSendPacket,
00095    lpc18xxEthSetMulticastFilter,
00096    lpc18xxEthUpdateMacConfig,
00097    lpc18xxEthWritePhyReg,
00098    lpc18xxEthReadPhyReg,
00099    TRUE,
00100    TRUE,
00101    TRUE,
00102    FALSE
00103 };
00104 
00105 
00106 /**
00107  * @brief LPC18xx Ethernet MAC initialization
00108  * @param[in] interface Underlying network interface
00109  * @return Error code
00110  **/
00111 
00112 error_t lpc18xxEthInit(NetInterface *interface)
00113 {
00114    error_t error;
00115 
00116    //Debug message
00117    TRACE_INFO("Initializing LPC18xx Ethernet MAC...\r\n");
00118 
00119    //Save underlying network interface
00120    nicDriverInterface = interface;
00121 
00122    //Enable Ethernet peripheral clock
00123    LPC_CCU1->CLK_M3_ETHERNET_CFG |= CCU1_CLK_M3_ETHERNET_CFG_RUN_Msk;
00124    while(!(LPC_CCU1->CLK_M3_ETHERNET_STAT & CCU1_CLK_M3_ETHERNET_STAT_RUN_Msk));
00125 
00126    //Reset DMA
00127    LPC_RGU->RESET_EXT_STAT19 |= RGU_RESET_EXT_STAT19_MASTER_RESET_Msk;
00128    LPC_RGU->RESET_EXT_STAT19 &= ~RGU_RESET_EXT_STAT19_MASTER_RESET_Msk;
00129 
00130    //Reset Ethernet peripheral
00131    LPC_RGU->RESET_EXT_STAT22 |= RGU_RESET_EXT_STAT22_MASTER_RESET_Msk;
00132    LPC_RGU->RESET_EXT_STAT22 &= ~RGU_RESET_EXT_STAT22_MASTER_RESET_Msk;
00133 
00134    //GPIO configuration
00135    lpc18xxEthInitGpio(interface);
00136 
00137    //Reset Ethernet peripheral
00138    LPC_RGU->RESET_CTRL0 = RGU_RESET_CTRL0_ETHERNET_RST_Msk;
00139    while(!(LPC_RGU->RESET_ACTIVE_STATUS0 & RGU_RESET_ACTIVE_STATUS0_ETHERNET_RST_Msk));
00140 
00141    //Perform a software reset
00142    LPC_ETHERNET->DMA_BUS_MODE |= ETHERNET_DMA_BUS_MODE_SWR_Msk;
00143    //Wait for the reset to complete
00144    while(LPC_ETHERNET->DMA_BUS_MODE & ETHERNET_DMA_BUS_MODE_SWR_Msk);
00145 
00146    //Adjust MDC clock range
00147    LPC_ETHERNET->MAC_MII_ADDR = ETHERNET_MAC_MII_ADDR_CR_DIV62;
00148 
00149    //PHY transceiver initialization
00150    error = interface->phyDriver->init(interface);
00151    //Failed to initialize PHY transceiver?
00152    if(error)
00153       return error;
00154 
00155    //Use default MAC configuration
00156    LPC_ETHERNET->MAC_CONFIG = ETHERNET_MAC_CONFIG_DO_Msk;
00157 
00158    //Set the MAC address
00159    LPC_ETHERNET->MAC_ADDR0_LOW = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
00160    LPC_ETHERNET->MAC_ADDR0_HIGH = interface->macAddr.w[2];
00161 
00162    //Initialize hash table
00163    LPC_ETHERNET->MAC_HASHTABLE_LOW = 0;
00164    LPC_ETHERNET->MAC_HASHTABLE_HIGH = 0;
00165 
00166    //Configure the receive filter
00167    LPC_ETHERNET->MAC_FRAME_FILTER = ETHERNET_MAC_FRAME_FILTER_HPF_Msk |
00168       ETHERNET_MAC_FRAME_FILTER_HMC_Msk;
00169 
00170    //Disable flow control
00171    LPC_ETHERNET->MAC_FLOW_CTRL = 0;
00172    //Set the threshold level of the transmit and receive FIFOs
00173    LPC_ETHERNET->DMA_OP_MODE = ETHERNET_DMA_OP_MODE_TTC_64 | ETHERNET_DMA_OP_MODE_RTC_32;
00174 
00175    //Configure DMA bus mode
00176    LPC_ETHERNET->DMA_BUS_MODE = ETHERNET_DMA_BUS_MODE_AAL_Msk | ETHERNET_DMA_BUS_MODE_USP_Msk |
00177       ETHERNET_DMA_BUS_MODE_RPBL_1 | ETHERNET_DMA_BUS_MODE_PR_1_1 |
00178       ETHERNET_DMA_BUS_MODE_PBL_1 | ETHERNET_DMA_BUS_MODE_ATDS_Msk;
00179 
00180    //Initialize DMA descriptor lists
00181    lpc18xxEthInitDmaDesc(interface);
00182 
00183    //Disable MAC interrupts
00184    LPC_ETHERNET->MAC_INTR_MASK = ETHERNET_MAC_INTR_MASK_TSIM_Msk |
00185       ETHERNET_MAC_INTR_MASK_PMTIM_Msk;
00186 
00187    //Enable the desired DMA interrupts
00188    LPC_ETHERNET->DMA_INT_EN = ETHERNET_DMA_INT_EN_NIE_Msk |
00189       ETHERNET_DMA_INT_EN_RIE_Msk | ETHERNET_DMA_INT_EN_TIE_Msk;
00190 
00191    //Set priority grouping (3 bits for pre-emption priority, no bits for subpriority)
00192    NVIC_SetPriorityGrouping(LPC18XX_ETH_IRQ_PRIORITY_GROUPING);
00193 
00194    //Configure Ethernet interrupt priority
00195    NVIC_SetPriority(ETHERNET_IRQn, NVIC_EncodePriority(LPC18XX_ETH_IRQ_PRIORITY_GROUPING,
00196       LPC18XX_ETH_IRQ_GROUP_PRIORITY, LPC18XX_ETH_IRQ_SUB_PRIORITY));
00197 
00198    //Enable MAC transmission and reception
00199    LPC_ETHERNET->MAC_CONFIG |= ETHERNET_MAC_CONFIG_TE_Msk | ETHERNET_MAC_CONFIG_RE_Msk;
00200    //Enable DMA transmission and reception
00201    LPC_ETHERNET->DMA_OP_MODE |= ETHERNET_DMA_OP_MODE_ST_Msk | ETHERNET_DMA_OP_MODE_SR_Msk;
00202 
00203    //Accept any packets from the upper layer
00204    osSetEvent(&interface->nicTxEvent);
00205 
00206    //Successful initialization
00207    return NO_ERROR;
00208 }
00209 
00210 
00211 //LPC1830-Xplorer evaluation board?
00212 #if defined(USE_LPC1830_XPLORER)
00213 
00214 /**
00215  * @brief GPIO configuration
00216  * @param[in] interface Underlying network interface
00217  **/
00218 
00219 void lpc18xxEthInitGpio(NetInterface *interface)
00220 {
00221    //Enable GPIO peripheral clock
00222    LPC_CCU1->CLK_M3_GPIO_CFG |= CCU1_CLK_M3_GPIO_CFG_RUN_Msk;
00223    while(!(LPC_CCU1->CLK_M3_GPIO_STAT & CCU1_CLK_M3_GPIO_STAT_RUN_Msk));
00224 
00225    //Select RMII operation mode
00226    LPC_CREG->CREG6 &= ~CREG_CREG6_ETHMODE_Msk;
00227    LPC_CREG->CREG6 |= CREG6_ETHMODE_RMII;
00228 
00229    //Configure P0.0 (ENET_RXD1)
00230    LPC_SCU->SFSP0_0 = SCU_SFSP0_0_EZI_Msk | SCU_SFSP0_0_EHS_Msk | (2 & SCU_SFSP0_0_MODE_Msk);
00231    //Configure P0.1 (ENET_TX_EN)
00232    LPC_SCU->SFSP0_1 = SCU_SFSP0_1_EHS_Msk | (6 & SCU_SFSP0_1_MODE_Msk);
00233 
00234    //Configure P1.15 (ENET_RXD0)
00235    LPC_SCU->SFSP1_15 = SCU_SFSP1_15_EZI_Msk | SCU_SFSP1_15_EHS_Msk | (3 & SCU_SFSP1_15_MODE_Msk);
00236    //Configure P1.16 (ENET_RX_DV)
00237    LPC_SCU->SFSP1_16 = SCU_SFSP1_16_EZI_Msk | SCU_SFSP1_16_EHS_Msk | (7 & SCU_SFSP1_16_MODE_Msk);
00238    //Configure P1.17 (ENET_MDIO)
00239    LPC_SCU->SFSP1_17 = SCU_SFSP1_17_EZI_Msk | (3 & SCU_SFSP1_17_MODE_Msk);
00240    //Configure P1.18 (ENET_TXD0)
00241    LPC_SCU->SFSP1_18 = SCU_SFSP1_18_EHS_Msk | (3 & SCU_SFSP1_18_MODE_Msk);
00242    //Configure P1.19 (ENET_REF_CLK)
00243    LPC_SCU->SFSP1_19 = SCU_SFSP1_19_EZI_Msk | SCU_SFSP1_19_EHS_Msk | (0 & SCU_SFSP1_19_MODE_Msk);
00244    //Configure P1.20 (ENET_TXD1)
00245    LPC_SCU->SFSP1_20 = SCU_SFSP1_20_EHS_Msk | (3 & SCU_SFSP1_20_MODE_Msk);
00246 
00247    //Configure P2.0 (ENET_MDC)
00248    LPC_SCU->SFSP2_0 = (7 & SCU_SFSP2_0_MODE_Msk);
00249 }
00250 
00251 #endif
00252 
00253 
00254 /**
00255  * @brief Initialize DMA descriptor lists
00256  * @param[in] interface Underlying network interface
00257  **/
00258 
00259 void lpc18xxEthInitDmaDesc(NetInterface *interface)
00260 {
00261    uint_t i;
00262 
00263    //Initialize TX DMA descriptor list
00264    for(i = 0; i < LPC18XX_ETH_TX_BUFFER_COUNT; i++)
00265    {
00266       //Use chain structure rather than ring structure
00267       txDmaDesc[i].tdes0 = ETH_TDES0_IC | ETH_TDES0_TCH;
00268       //Initialize transmit buffer size
00269       txDmaDesc[i].tdes1 = 0;
00270       //Transmit buffer address
00271       txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
00272       //Next descriptor address
00273       txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
00274       //Reserved fields
00275       txDmaDesc[i].tdes4 = 0;
00276       txDmaDesc[i].tdes5 = 0;
00277       //Transmit frame time stamp
00278       txDmaDesc[i].tdes6 = 0;
00279       txDmaDesc[i].tdes7 = 0;
00280    }
00281 
00282    //The last descriptor is chained to the first entry
00283    txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
00284    //Point to the very first descriptor
00285    txCurDmaDesc = &txDmaDesc[0];
00286 
00287    //Initialize RX DMA descriptor list
00288    for(i = 0; i < LPC18XX_ETH_RX_BUFFER_COUNT; i++)
00289    {
00290       //The descriptor is initially owned by the DMA
00291       rxDmaDesc[i].rdes0 = ETH_RDES0_OWN;
00292       //Use chain structure rather than ring structure
00293       rxDmaDesc[i].rdes1 = ETH_RDES1_RCH | (LPC18XX_ETH_RX_BUFFER_SIZE & ETH_RDES1_RBS1);
00294       //Receive buffer address
00295       rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
00296       //Next descriptor address
00297       rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
00298       //Extended status
00299       rxDmaDesc[i].rdes4 = 0;
00300       //Reserved field
00301       rxDmaDesc[i].rdes5 = 0;
00302       //Receive frame time stamp
00303       rxDmaDesc[i].rdes6 = 0;
00304       rxDmaDesc[i].rdes7 = 0;
00305    }
00306 
00307    //The last descriptor is chained to the first entry
00308    rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
00309    //Point to the very first descriptor
00310    rxCurDmaDesc = &rxDmaDesc[0];
00311 
00312    //Start location of the TX descriptor list
00313    LPC_ETHERNET->DMA_TRANS_DES_ADDR = (uint32_t) txDmaDesc;
00314    //Start location of the RX descriptor list
00315    LPC_ETHERNET->DMA_REC_DES_ADDR = (uint32_t) rxDmaDesc;
00316 }
00317 
00318 
00319 /**
00320  * @brief LPC18xx Ethernet MAC timer handler
00321  *
00322  * This routine is periodically called by the TCP/IP stack to
00323  * handle periodic operations such as polling the link state
00324  *
00325  * @param[in] interface Underlying network interface
00326  **/
00327 
00328 void lpc18xxEthTick(NetInterface *interface)
00329 {
00330    //Handle periodic operations
00331    interface->phyDriver->tick(interface);
00332 }
00333 
00334 
00335 /**
00336  * @brief Enable interrupts
00337  * @param[in] interface Underlying network interface
00338  **/
00339 
00340 void lpc18xxEthEnableIrq(NetInterface *interface)
00341 {
00342    //Enable Ethernet MAC interrupts
00343    NVIC_EnableIRQ(ETHERNET_IRQn);
00344    //Enable Ethernet PHY interrupts
00345    interface->phyDriver->enableIrq(interface);
00346 }
00347 
00348 
00349 /**
00350  * @brief Disable interrupts
00351  * @param[in] interface Underlying network interface
00352  **/
00353 
00354 void lpc18xxEthDisableIrq(NetInterface *interface)
00355 {
00356    //Disable Ethernet MAC interrupts
00357    NVIC_DisableIRQ(ETHERNET_IRQn);
00358    //Disable Ethernet PHY interrupts
00359    interface->phyDriver->disableIrq(interface);
00360 }
00361 
00362 
00363 /**
00364  * @brief LPC18xx Ethernet MAC interrupt service routine
00365  **/
00366 
00367 void ETHERNET_IRQHandler(void)
00368 {
00369    bool_t flag;
00370    uint32_t status;
00371 
00372    //Enter interrupt service routine
00373    osEnterIsr();
00374 
00375    //This flag will be set if a higher priority task must be woken
00376    flag = FALSE;
00377 
00378    //Read DMA status register
00379    status = LPC_ETHERNET->DMA_STAT;
00380 
00381    //A packet has been transmitted?
00382    if(status & ETHERNET_DMA_STAT_TI_Msk)
00383    {
00384       //Clear TI interrupt flag
00385       LPC_ETHERNET->DMA_STAT = ETHERNET_DMA_STAT_TI_Msk;
00386 
00387       //Check whether the TX buffer is available for writing
00388       if(!(txCurDmaDesc->tdes0 & ETH_TDES0_OWN))
00389       {
00390          //Notify the TCP/IP stack that the transmitter is ready to send
00391          flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
00392       }
00393    }
00394 
00395    //A packet has been received?
00396    if(status & ETHERNET_DMA_STAT_RI_Msk)
00397    {
00398       //Disable RIE interrupt
00399       LPC_ETHERNET->DMA_INT_EN &= ~ETHERNET_DMA_INT_EN_RIE_Msk;
00400 
00401       //Set event flag
00402       nicDriverInterface->nicEvent = TRUE;
00403       //Notify the TCP/IP stack of the event
00404       flag |= osSetEventFromIsr(&netEvent);
00405    }
00406 
00407    //Clear NIS interrupt flag
00408    LPC_ETHERNET->DMA_STAT = ETHERNET_DMA_STAT_NIS_Msk;
00409 
00410    //Leave interrupt service routine
00411    osExitIsr(flag);
00412 }
00413 
00414 
00415 /**
00416  * @brief LPC18xx Ethernet MAC event handler
00417  * @param[in] interface Underlying network interface
00418  **/
00419 
00420 void lpc18xxEthEventHandler(NetInterface *interface)
00421 {
00422    error_t error;
00423 
00424    //Packet received?
00425    if(LPC_ETHERNET->DMA_STAT & ETHERNET_DMA_STAT_RI_Msk)
00426    {
00427       //Clear interrupt flag
00428       LPC_ETHERNET->DMA_STAT = ETHERNET_DMA_STAT_RI_Msk;
00429 
00430       //Process all pending packets
00431       do
00432       {
00433          //Read incoming packet
00434          error = lpc18xxEthReceivePacket(interface);
00435 
00436          //No more data in the receive buffer?
00437       } while(error != ERROR_BUFFER_EMPTY);
00438    }
00439 
00440    //Re-enable DMA interrupts
00441    LPC_ETHERNET->DMA_INT_EN |= ETHERNET_DMA_INT_EN_NIE_Msk |
00442       ETHERNET_DMA_INT_EN_RIE_Msk | ETHERNET_DMA_INT_EN_TIE_Msk;
00443 }
00444 
00445 
00446 /**
00447  * @brief Send a packet
00448  * @param[in] interface Underlying network interface
00449  * @param[in] buffer Multi-part buffer containing the data to send
00450  * @param[in] offset Offset to the first data byte
00451  * @return Error code
00452  **/
00453 
00454 error_t lpc18xxEthSendPacket(NetInterface *interface,
00455    const NetBuffer *buffer, size_t offset)
00456 {
00457    size_t length;
00458 
00459    //Retrieve the length of the packet
00460    length = netBufferGetLength(buffer) - offset;
00461 
00462    //Check the frame length
00463    if(length > LPC18XX_ETH_TX_BUFFER_SIZE)
00464    {
00465       //The transmitter can accept another packet
00466       osSetEvent(&interface->nicTxEvent);
00467       //Report an error
00468       return ERROR_INVALID_LENGTH;
00469    }
00470 
00471    //Make sure the current buffer is available for writing
00472    if(txCurDmaDesc->tdes0 & ETH_TDES0_OWN)
00473       return ERROR_FAILURE;
00474 
00475    //Copy user data to the transmit buffer
00476    netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
00477 
00478    //Write the number of bytes to send
00479    txCurDmaDesc->tdes1 = length & ETH_TDES1_TBS1;
00480    //Set LS and FS flags as the data fits in a single buffer
00481    txCurDmaDesc->tdes0 |= ETH_TDES0_LS | ETH_TDES0_FS;
00482    //Give the ownership of the descriptor to the DMA
00483    txCurDmaDesc->tdes0 |= ETH_TDES0_OWN;
00484 
00485    //Clear TU flag to resume processing
00486    LPC_ETHERNET->DMA_STAT = ETHERNET_DMA_STAT_TU_Msk;
00487    //Instruct the DMA to poll the transmit descriptor list
00488    LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 0;
00489 
00490    //Point to the next descriptor in the list
00491    txCurDmaDesc = (Lpc18xxTxDmaDesc *) txCurDmaDesc->tdes3;
00492 
00493    //Check whether the next buffer is available for writing
00494    if(!(txCurDmaDesc->tdes0 & ETH_TDES0_OWN))
00495    {
00496       //The transmitter can accept another packet
00497       osSetEvent(&interface->nicTxEvent);
00498    }
00499 
00500    //Data successfully written
00501    return NO_ERROR;
00502 }
00503 
00504 
00505 /**
00506  * @brief Receive a packet
00507  * @param[in] interface Underlying network interface
00508  * @return Error code
00509  **/
00510 
00511 error_t lpc18xxEthReceivePacket(NetInterface *interface)
00512 {
00513    error_t error;
00514    size_t n;
00515 
00516    //The current buffer is available for reading?
00517    if(!(rxCurDmaDesc->rdes0 & ETH_RDES0_OWN))
00518    {
00519       //FS and LS flags should be set
00520       if((rxCurDmaDesc->rdes0 & ETH_RDES0_FS) && (rxCurDmaDesc->rdes0 & ETH_RDES0_LS))
00521       {
00522          //Make sure no error occurred
00523          if(!(rxCurDmaDesc->rdes0 & ETH_RDES0_ES))
00524          {
00525             //Retrieve the length of the frame
00526             n = (rxCurDmaDesc->rdes0 & ETH_RDES0_FL) >> 16;
00527             //Limit the number of data to read
00528             n = MIN(n, LPC18XX_ETH_RX_BUFFER_SIZE);
00529 
00530             //Pass the packet to the upper layer
00531             nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n);
00532 
00533             //Valid packet received
00534             error = NO_ERROR;
00535          }
00536          else
00537          {
00538             //The received packet contains an error
00539             error = ERROR_INVALID_PACKET;
00540          }
00541       }
00542       else
00543       {
00544          //The packet is not valid
00545          error = ERROR_INVALID_PACKET;
00546       }
00547 
00548       //Give the ownership of the descriptor back to the DMA
00549       rxCurDmaDesc->rdes0 = ETH_RDES0_OWN;
00550       //Point to the next descriptor in the list
00551       rxCurDmaDesc = (Lpc18xxRxDmaDesc *) rxCurDmaDesc->rdes3;
00552    }
00553    else
00554    {
00555       //No more data in the receive buffer
00556       error = ERROR_BUFFER_EMPTY;
00557    }
00558 
00559    //Clear RU flag to resume processing
00560    LPC_ETHERNET->DMA_STAT = ETHERNET_DMA_STAT_RU_Msk;
00561    //Instruct the DMA to poll the receive descriptor list
00562    LPC_ETHERNET->DMA_REC_POLL_DEMAND = 0;
00563 
00564    //Return status code
00565    return error;
00566 }
00567 
00568 
00569 /**
00570  * @brief Configure multicast MAC address filtering
00571  * @param[in] interface Underlying network interface
00572  * @return Error code
00573  **/
00574 
00575 error_t lpc18xxEthSetMulticastFilter(NetInterface *interface)
00576 {
00577    uint_t i;
00578    uint_t k;
00579    uint32_t crc;
00580    uint32_t hashTable[2];
00581    MacFilterEntry *entry;
00582 
00583    //Debug message
00584    TRACE_DEBUG("Updating LPC18xx hash table...\r\n");
00585 
00586    //Clear hash table
00587    hashTable[0] = 0;
00588    hashTable[1] = 0;
00589 
00590    //The MAC filter table contains the multicast MAC addresses
00591    //to accept when receiving an Ethernet frame
00592    for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
00593    {
00594       //Point to the current entry
00595       entry = &interface->macMulticastFilter[i];
00596 
00597       //Valid entry?
00598       if(entry->refCount > 0)
00599       {
00600          //Compute CRC over the current MAC address
00601          crc = lpc18xxEthCalcCrc(&entry->addr, sizeof(MacAddr));
00602 
00603          //The upper 6 bits in the CRC register are used to index the
00604          //contents of the hash table
00605          k = (crc >> 26) & 0x3F;
00606 
00607          //Update hash table contents
00608          hashTable[k / 32] |= (1 << (k % 32));
00609       }
00610    }
00611 
00612    //Write the hash table
00613    LPC_ETHERNET->MAC_HASHTABLE_LOW = hashTable[0];
00614    LPC_ETHERNET->MAC_HASHTABLE_HIGH = hashTable[1];
00615 
00616    //Debug message
00617    TRACE_DEBUG("  MAC_HASHTABLE_LOW = %08" PRIX32 "\r\n", LPC_ETHERNET->MAC_HASHTABLE_LOW);
00618    TRACE_DEBUG("  MAC_HASHTABLE_HIGH = %08" PRIX32 "\r\n", LPC_ETHERNET->MAC_HASHTABLE_HIGH);
00619 
00620    //Successful processing
00621    return NO_ERROR;
00622 }
00623 
00624 
00625 /**
00626  * @brief Adjust MAC configuration parameters for proper operation
00627  * @param[in] interface Underlying network interface
00628  * @return Error code
00629  **/
00630 
00631 error_t lpc18xxEthUpdateMacConfig(NetInterface *interface)
00632 {
00633    uint32_t config;
00634 
00635    //Read current MAC configuration
00636    config = LPC_ETHERNET->MAC_CONFIG;
00637 
00638    //10BASE-T or 100BASE-TX operation mode?
00639    if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
00640       config |= ETHERNET_MAC_CONFIG_FES_Msk;
00641    else
00642       config &= ~ETHERNET_MAC_CONFIG_FES_Msk;
00643 
00644    //Half-duplex or full-duplex mode?
00645    if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
00646       config |= ETHERNET_MAC_CONFIG_DM_Msk;
00647    else
00648       config &= ~ETHERNET_MAC_CONFIG_DM_Msk;
00649 
00650    //Update MAC configuration register
00651    LPC_ETHERNET->MAC_CONFIG = config;
00652 
00653    //Successful processing
00654    return NO_ERROR;
00655 }
00656 
00657 
00658 /**
00659  * @brief Write PHY register
00660  * @param[in] phyAddr PHY address
00661  * @param[in] regAddr Register address
00662  * @param[in] data Register value
00663  **/
00664 
00665 void lpc18xxEthWritePhyReg(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
00666 {
00667    uint32_t value;
00668 
00669    //Take care not to alter MDC clock configuration
00670    value = LPC_ETHERNET->MAC_MII_ADDR & ETHERNET_MAC_MII_ADDR_CR_Msk;
00671    //Set up a write operation
00672    value |= ETHERNET_MAC_MII_ADDR_W_Msk | ETHERNET_MAC_MII_ADDR_GB_Msk;
00673    //PHY address
00674    value |= (phyAddr << ETHERNET_MAC_MII_ADDR_PA_Pos) & ETHERNET_MAC_MII_ADDR_PA_Msk;
00675    //Register address
00676    value |= (regAddr << ETHERNET_MAC_MII_ADDR_GR_Pos) & ETHERNET_MAC_MII_ADDR_GR_Msk;
00677 
00678    //Data to be written in the PHY register
00679    LPC_ETHERNET->MAC_MII_DATA = data & ETHERNET_MAC_MII_DATA_GD_Msk;
00680 
00681    //Start a write operation
00682    LPC_ETHERNET->MAC_MII_ADDR = value;
00683    //Wait for the write to complete
00684    while(LPC_ETHERNET->MAC_MII_ADDR & ETHERNET_MAC_MII_ADDR_GB_Msk);
00685 }
00686 
00687 
00688 /**
00689  * @brief Read PHY register
00690  * @param[in] phyAddr PHY address
00691  * @param[in] regAddr Register address
00692  * @return Register value
00693  **/
00694 
00695 uint16_t lpc18xxEthReadPhyReg(uint8_t phyAddr, uint8_t regAddr)
00696 {
00697    uint32_t value;
00698 
00699    //Take care not to alter MDC clock configuration
00700    value = LPC_ETHERNET->MAC_MII_ADDR & ETHERNET_MAC_MII_ADDR_CR_Msk;
00701    //Set up a read operation
00702    value |= ETHERNET_MAC_MII_ADDR_GB_Msk;
00703    //PHY address
00704    value |= (phyAddr << ETHERNET_MAC_MII_ADDR_PA_Pos) & ETHERNET_MAC_MII_ADDR_PA_Msk;
00705    //Register address
00706    value |= (regAddr << ETHERNET_MAC_MII_ADDR_GR_Pos) & ETHERNET_MAC_MII_ADDR_GR_Msk;
00707 
00708    //Start a read operation
00709    LPC_ETHERNET->MAC_MII_ADDR = value;
00710    //Wait for the read to complete
00711    while(LPC_ETHERNET->MAC_MII_ADDR & ETHERNET_MAC_MII_ADDR_GB_Msk);
00712 
00713    //Return PHY register contents
00714    return LPC_ETHERNET->MAC_MII_DATA & ETHERNET_MAC_MII_DATA_GD_Msk;
00715 }
00716 
00717 
00718 /**
00719  * @brief CRC calculation
00720  * @param[in] data Pointer to the data over which to calculate the CRC
00721  * @param[in] length Number of bytes to process
00722  * @return Resulting CRC value
00723  **/
00724 
00725 uint32_t lpc18xxEthCalcCrc(const void *data, size_t length)
00726 {
00727    uint_t i;
00728    uint_t j;
00729 
00730    //Point to the data over which to calculate the CRC
00731    const uint8_t *p = (uint8_t *) data;
00732    //CRC preset value
00733    uint32_t crc = 0xFFFFFFFF;
00734 
00735    //Loop through data
00736    for(i = 0; i < length; i++)
00737    {
00738       //The message is processed bit by bit
00739       for(j = 0; j < 8; j++)
00740       {
00741          //Update CRC value
00742          if(((crc >> 31) ^ (p[i] >> j)) & 0x01)
00743             crc = (crc << 1) ^ 0x04C11DB7;
00744          else
00745             crc = crc << 1;
00746       }
00747    }
00748 
00749    //Return CRC value
00750    return ~crc;
00751 }
00752