NXP's driver library for LPC17xx, ported to mbed's online compiler. Not tested! I had to fix a lot of warings and found a couple of pretty obvious bugs, so the chances are there are more. Original: http://ics.nxp.com/support/documents/microcontrollers/zip/lpc17xx.cmsis.driver.library.zip

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lpc17xx_emac.c Source File

lpc17xx_emac.c

Go to the documentation of this file.
00001 /**
00002  * @file    : lpc17xx_emac.c
00003  * @brief   : Contains all functions support for Ethernet MAC firmware library on LPC17xx
00004  * @version : 1.0
00005  * @date    : 02. Jun. 2009
00006  * @author  : HieuNguyen
00007  **************************************************************************
00008  * Software that is described herein is for illustrative purposes only
00009  * which provides customers with programming information regarding the
00010  * products. This software is supplied "AS IS" without any warranties.
00011  * NXP Semiconductors assumes no responsibility or liability for the
00012  * use of the software, conveys no license or title under any patent,
00013  * copyright, or mask work right to the product. NXP Semiconductors
00014  * reserves the right to make changes in the software without
00015  * notification. NXP Semiconductors also make no representation or
00016  * warranty that such application will be suitable for the specified
00017  * use without further testing or modification.
00018  **********************************************************************/
00019 
00020 /* Peripheral group ----------------------------------------------------------- */
00021 /** @addtogroup EMAC
00022  * @{
00023  */
00024 
00025 /* Includes ------------------------------------------------------------------- */
00026 #include "lpc17xx_emac.h"
00027 #include "lpc17xx_clkpwr.h"
00028 
00029 /* If this source file built with example, the LPC17xx FW library configuration
00030  * file in each example directory ("lpc17xx_libcfg.h") must be included,
00031  * otherwise the default FW library configuration file must be included instead
00032  */
00033 #ifdef __BUILD_WITH_EXAMPLE__
00034 #include "lpc17xx_libcfg.h"
00035 #else
00036 #include "lpc17xx_libcfg_default.h"
00037 #endif /* __BUILD_WITH_EXAMPLE__ */
00038 
00039 
00040 #ifdef _EMAC
00041 
00042 /* Private Variables ---------------------------------------------------------- */
00043 /** @defgroup EMAC_Private_Variables
00044  * @{
00045  */
00046 
00047 /* MII Mgmt Configuration register - Clock divider setting */
00048 const uint8_t EMAC_clkdiv[] = { 4, 6, 8, 10, 14, 20, 28 };
00049 
00050 /* EMAC local DMA Descriptors */
00051 
00052 /** Rx Descriptor data array */
00053 static RX_Desc Rx_Desc[EMAC_NUM_RX_FRAG];
00054 
00055 /** Rx Status data array - Must be 8-Byte aligned */
00056 #if defined ( __CC_ARM   )
00057 static __align(8) RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG];
00058 #elif defined ( __ICCARM__ )
00059 #pragma data_alignment=8
00060 static RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG];
00061 #elif defined   (  __GNUC__  )
00062 static __attribute__ ((aligned (8))) RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG];
00063 #endif
00064 
00065 /** Tx Descriptor data array */
00066 static TX_Desc Tx_Desc[EMAC_NUM_TX_FRAG];
00067 /** Tx Status data array */
00068 static TX_Stat Tx_Stat[EMAC_NUM_TX_FRAG];
00069 
00070 /* EMAC local DMA buffers */
00071 /** Rx buffer data */
00072 static uint32_t rx_buf[EMAC_NUM_RX_FRAG][EMAC_ETH_MAX_FLEN>>2];
00073 /** Tx buffer data */
00074 static uint32_t tx_buf[EMAC_NUM_TX_FRAG][EMAC_ETH_MAX_FLEN>>2];
00075 
00076 /* EMAC call-back function pointer data */
00077 static EMAC_IntCBSType *_pfnIntCbDat[10];
00078 
00079 /**
00080  * @}
00081  */
00082 
00083 
00084 /* Private Functions ---------------------------------------------------------- */
00085 /** @defgroup EMAC_Private_Functions
00086  * @{
00087  */
00088 
00089 static void rx_descr_init (void);
00090 static void tx_descr_init (void);
00091 static int32_t write_PHY (uint32_t PhyReg, uint16_t Value);
00092 static int32_t  read_PHY (uint32_t PhyReg);
00093 
00094 
00095 /*--------------------------- rx_descr_init ---------------------------------*/
00096 
00097 /**
00098  * @brief       Initializes RX Descriptor
00099  * @param[in]   None
00100  * @return      None
00101  */
00102 static void rx_descr_init (void)
00103 {
00104     /* Initialize Receive Descriptor and Status array. */
00105     uint32_t i;
00106 
00107     for (i = 0; i < EMAC_NUM_RX_FRAG; i++) {
00108         Rx_Desc[i].Packet  = (uint32_t)&rx_buf[i];
00109         Rx_Desc[i].Ctrl    = EMAC_RCTRL_INT | (EMAC_ETH_MAX_FLEN - 1);
00110         Rx_Stat[i].Info    = 0;
00111         Rx_Stat[i].HashCRC = 0;
00112     }
00113 
00114     /* Set EMAC Receive Descriptor Registers. */
00115     LPC_EMAC->RxDescriptor       = (uint32_t)&Rx_Desc[0];
00116     LPC_EMAC->RxStatus           = (uint32_t)&Rx_Stat[0];
00117     LPC_EMAC->RxDescriptorNumber = EMAC_NUM_RX_FRAG - 1;
00118 
00119     /* Rx Descriptors Point to 0 */
00120     LPC_EMAC->RxConsumeIndex  = 0;
00121 }
00122 
00123 
00124 /*--------------------------- tx_descr_init ---- ----------------------------*/
00125 /**
00126  * @brief       Initializes TX Descriptor
00127  * @param[in]   None
00128  * @return      None
00129  */
00130 static void tx_descr_init (void) {
00131     /* Initialize Transmit Descriptor and Status array. */
00132     uint32_t i;
00133 
00134     for (i = 0; i < EMAC_NUM_TX_FRAG; i++) {
00135         Tx_Desc[i].Packet = (uint32_t)&tx_buf[i];
00136         Tx_Desc[i].Ctrl   = 0;
00137         Tx_Stat[i].Info   = 0;
00138     }
00139 
00140     /* Set EMAC Transmit Descriptor Registers. */
00141     LPC_EMAC->TxDescriptor       = (uint32_t)&Tx_Desc[0];
00142     LPC_EMAC->TxStatus           = (uint32_t)&Tx_Stat[0];
00143     LPC_EMAC->TxDescriptorNumber = EMAC_NUM_TX_FRAG - 1;
00144 
00145     /* Tx Descriptors Point to 0 */
00146     LPC_EMAC->TxProduceIndex  = 0;
00147 }
00148 
00149 
00150 /*--------------------------- write_PHY -------------------------------------*/
00151 /**
00152  * @brief       Write value to PHY device
00153  * @param[in]   PhyReg PHY Register address
00154  * @param[in]   Value Value to write
00155  * @return      (0) if sucess, otherwise return (-1)
00156  */
00157 static int32_t write_PHY (uint32_t PhyReg, uint16_t Value)
00158 {
00159     /* Write a data 'Value' to PHY register 'PhyReg'. */
00160     uint32_t tout;
00161 
00162     LPC_EMAC->MADR = EMAC_DP83848C_DEF_ADR | PhyReg;
00163     LPC_EMAC->MWTD = Value;
00164 
00165     /* Wait until operation completed */
00166     tout = 0;
00167     for (tout = 0; tout < EMAC_MII_WR_TOUT; tout++) {
00168         if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) {
00169             return (0);
00170         }
00171     }
00172     // Time out!
00173     return (-1);
00174 }
00175 
00176 
00177 /*--------------------------- read_PHY --------------------------------------*/
00178 /**
00179  * @brief       Read value from PHY device
00180  * @param[in]   PhyReg PHY Register address
00181  * @return      Return value if success, otherwise return (-1)
00182  */
00183 static int32_t read_PHY (uint32_t PhyReg)
00184 {
00185     /* Read a PHY register 'PhyReg'. */
00186     uint32_t tout;
00187 
00188     LPC_EMAC->MADR = EMAC_DP83848C_DEF_ADR | PhyReg;
00189     LPC_EMAC->MCMD = EMAC_MCMD_READ;
00190 
00191     /* Wait until operation completed */
00192     tout = 0;
00193     for (tout = 0; tout < EMAC_MII_RD_TOUT; tout++) {
00194         if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) {
00195             LPC_EMAC->MCMD = 0;
00196             return (LPC_EMAC->MRDD);
00197         }
00198     }
00199     // Time out!
00200     return (-1);
00201 }
00202 
00203 /*********************************************************************//**
00204  * @brief       Set Station MAC address for EMAC module
00205  * @param[in]   abStationAddr Pointer to Station address that contains 6-bytes
00206  *              of MAC address (should be in order from MAC Address 1 to MAC Address 6)
00207  * @return      None
00208  **********************************************************************/
00209 void setEmacAddr(uint8_t abStationAddr[])
00210 {
00211     /* Set the Ethernet MAC Address registers */
00212     LPC_EMAC->SA0 = ((uint32_t)abStationAddr[5] << 8) | (uint32_t)abStationAddr[4];
00213     LPC_EMAC->SA1 = ((uint32_t)abStationAddr[3] << 8) | (uint32_t)abStationAddr[2];
00214     LPC_EMAC->SA2 = ((uint32_t)abStationAddr[1] << 8) | (uint32_t)abStationAddr[0];
00215 }
00216 
00217 /**
00218  * @}
00219  */
00220 
00221 
00222 /* Public Functions ----------------------------------------------------------- */
00223 /** @addtogroup EMAC_Public_Functions
00224  * @{
00225  */
00226 
00227 
00228 /*********************************************************************//**
00229  * @brief       Initializes the EMAC peripheral according to the specified
00230 *               parameters in the EMAC_ConfigStruct.
00231  * @param[in]   EMAC_ConfigStruct Pointer to a EMAC_CFG_Type structure
00232 *                    that contains the configuration information for the
00233 *                    specified EMAC peripheral.
00234  * @return      None
00235  *
00236  * Note: This function will initialize EMAC module according to procedure below:
00237  *  - Remove the soft reset condition from the MAC
00238  *  - Configure the PHY via the MIIM interface of the MAC
00239  *  - Select RMII mode
00240  *  - Configure the transmit and receive DMA engines, including the descriptor arrays
00241  *  - Configure the host registers (MAC1,MAC2 etc.) in the MAC
00242  *  - Enable the receive and transmit data paths
00243  *  In default state after initializing, only Rx Done and Tx Done interrupt are enabled,
00244  *  all remain interrupts are disabled
00245  *  (Ref. from LPC17xx UM)
00246  **********************************************************************/
00247 Status EMAC_Init(EMAC_CFG_Type *EMAC_ConfigStruct)
00248 {
00249     /* Initialize the EMAC Ethernet controller. */
00250     int32_t regv,tout, tmp;
00251 
00252     /* Set up clock and power for Ethernet module */
00253     CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, ENABLE);
00254 
00255     /* Reset all EMAC internal modules */
00256     LPC_EMAC->MAC1    = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | EMAC_MAC1_RES_RX |
00257                     EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | EMAC_MAC1_SOFT_RES;
00258 
00259     LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES | EMAC_CR_PASS_RUNT_FRM;
00260 
00261     /* A short delay after reset. */
00262     for (tout = 100; tout; tout--);
00263 
00264     /* Initialize MAC control registers. */
00265     LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL;
00266     LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN;
00267     LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN;
00268     /*
00269      * Find the clock that close to desired target clock
00270      */
00271     tmp = SystemCoreClock / EMAC_MCFG_MII_MAXCLK;
00272     for (tout = 0; tout < sizeof (EMAC_clkdiv); tout++){
00273         if (EMAC_clkdiv[tout] >= tmp) break;
00274     }
00275     tout++;
00276     // Write to MAC configuration register and reset
00277     LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(tout) | EMAC_MCFG_RES_MII;
00278     // release reset
00279     LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII);
00280     LPC_EMAC->CLRT = EMAC_CLRT_DEF;
00281     LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF;
00282 
00283     /* Enable Reduced MII interface. */
00284     LPC_EMAC->Command = EMAC_CR_RMII | EMAC_CR_PASS_RUNT_FRM;
00285 
00286     /* Reset Reduced MII Logic. */
00287     LPC_EMAC->SUPP = EMAC_SUPP_RES_RMII;
00288 
00289     for (tout = 100; tout; tout--);
00290     LPC_EMAC->SUPP = 0;
00291 
00292     /* Put the DP83848C in reset mode */
00293     write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_RESET);
00294 
00295     /* Wait for hardware reset to end. */
00296     for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
00297         regv = read_PHY (EMAC_PHY_REG_BMCR);
00298         if (!(regv & (EMAC_PHY_BMCR_RESET | EMAC_PHY_BMCR_POWERDOWN))) {
00299             /* Reset complete, device not Power Down. */
00300             break;
00301         }
00302         if (tout == 0){
00303             // Time out, return ERROR
00304             return (ERROR);
00305         }
00306     }
00307 
00308     // Set PHY mode
00309     if (EMAC_SetPHYMode(EMAC_ConfigStruct->Mode) < 0){
00310         return (ERROR);
00311     }
00312 
00313     // Set EMAC address
00314     setEmacAddr(EMAC_ConfigStruct->pbEMAC_Addr);
00315 
00316     /* Initialize Tx and Rx DMA Descriptors */
00317     rx_descr_init ();
00318     tx_descr_init ();
00319 
00320     // Set Receive Filter register: enable broadcast and multicast
00321     LPC_EMAC->RxFilterCtrl = EMAC_RFC_MCAST_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN;
00322 
00323     /* Enable Rx Done and Tx Done interrupt for EMAC */
00324     LPC_EMAC->IntEnable = EMAC_INT_RX_DONE | EMAC_INT_TX_DONE;
00325 
00326     /* Reset all interrupts */
00327     LPC_EMAC->IntClear  = 0xFFFF;
00328 
00329     /* Enable receive and transmit mode of MAC Ethernet core */
00330     LPC_EMAC->Command  |= (EMAC_CR_RX_EN | EMAC_CR_TX_EN);
00331     LPC_EMAC->MAC1     |= EMAC_MAC1_REC_EN;
00332 
00333     return SUCCESS;
00334 }
00335 
00336 
00337 /*********************************************************************//**
00338  * @brief       De-initializes the EMAC peripheral registers to their
00339 *                  default reset values.
00340  * @param[in]   None
00341  * @return      None
00342  **********************************************************************/
00343 void EMAC_DeInit(void)
00344 {
00345     // Disable all interrupt
00346     LPC_EMAC->IntEnable = 0x00;
00347     // Clear all pending interrupt
00348     LPC_EMAC->IntClear = (0xFF) | (EMAC_INT_SOFT_INT | EMAC_INT_WAKEUP);
00349 
00350     /* TurnOff clock and power for Ethernet module */
00351     CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, DISABLE);
00352 }
00353 
00354 
00355 /*********************************************************************//**
00356  * @brief       Check specified PHY status in EMAC peripheral
00357  * @param[in]   ulPHYState  Specified PHY Status Type, should be:
00358  *                          - EMAC_PHY_STAT_LINK: Link Status
00359  *                          - EMAC_PHY_STAT_SPEED: Speed Status
00360  *                          - EMAC_PHY_STAT_DUP: Duplex Status
00361  * @return      Status of specified PHY status (0 or 1).
00362  *              (-1) if error.
00363  *
00364  * Note:
00365  * For EMAC_PHY_STAT_LINK, return value:
00366  * - 0: Link Down
00367  * - 1: Link Up
00368  * For EMAC_PHY_STAT_SPEED, return value:
00369  * - 0: 10Mbps
00370  * - 1: 100Mbps
00371  * For EMAC_PHY_STAT_DUP, return value:
00372  * - 0: Half-Duplex
00373  * - 1: Full-Duplex
00374  **********************************************************************/
00375 int32_t EMAC_CheckPHYStatus(uint32_t ulPHYState)
00376 {
00377     int32_t regv, tmp;
00378 
00379     regv = read_PHY (EMAC_PHY_REG_STS);
00380     switch(ulPHYState){
00381     case EMAC_PHY_STAT_LINK:
00382         tmp = (regv & EMAC_PHY_SR_LINK) ? 1 : 0;
00383         break;
00384     case EMAC_PHY_STAT_SPEED:
00385         tmp = (regv & EMAC_PHY_SR_SPEED) ? 0 : 1;
00386         break;
00387     case EMAC_PHY_STAT_DUP:
00388         tmp = (regv & EMAC_PHY_SR_DUP) ? 1 : 0;
00389         break;
00390     default:
00391         tmp = -1;
00392         break;
00393     }
00394     return (tmp);
00395 }
00396 
00397 
00398 /*********************************************************************//**
00399  * @brief       Set specified PHY mode in EMAC peripheral
00400  * @param[in]   ulPHYMode   Specified PHY mode, should be:
00401  *                          - EMAC_MODE_AUTO
00402  *                          - EMAC_MODE_10M_FULL
00403  *                          - EMAC_MODE_10M_HALF
00404  *                          - EMAC_MODE_100M_FULL
00405  *                          - EMAC_MODE_100M_HALF
00406  * @return      Return (0) if no error, otherwise return (-1)
00407  **********************************************************************/
00408 int32_t EMAC_SetPHYMode(uint32_t ulPHYMode)
00409 {
00410     int32_t id1, id2, tout, regv;
00411 
00412     /* Check if this is a DP83848C PHY. */
00413     id1 = read_PHY (EMAC_PHY_REG_IDR1);
00414     id2 = read_PHY (EMAC_PHY_REG_IDR2);
00415 
00416     if (((id1 << 16) | (id2 & 0xFFF0)) == EMAC_DP83848C_ID) {
00417         /* Configure the PHY device */
00418         switch(ulPHYMode){
00419         case EMAC_MODE_AUTO:
00420             /* Use auto-negotiation about the link speed. */
00421             write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG);
00422             /* Wait to complete Auto_Negotiation */
00423             for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
00424                 regv = read_PHY (EMAC_PHY_REG_BMSR);
00425                 if (regv & EMAC_PHY_BMSR_AUTO_DONE) {
00426                     /* Auto-negotiation Complete. */
00427                     break;
00428                 }
00429                 if (tout == 0){
00430                     // Time out, return error
00431                     return (-1);
00432                 }
00433             }
00434             break;
00435         case EMAC_MODE_10M_FULL:
00436             /* Connect at 10MBit full-duplex */
00437             write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_10M);
00438             break;
00439         case EMAC_MODE_10M_HALF:
00440             /* Connect at 10MBit half-duplex */
00441             write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_10M);
00442             break;
00443         case EMAC_MODE_100M_FULL:
00444             /* Connect at 100MBit full-duplex */
00445             write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_100M);
00446             break;
00447         case EMAC_MODE_100M_HALF:
00448             /* Connect at 100MBit half-duplex */
00449             write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_100M);
00450             break;
00451         default:
00452             // un-supported
00453             return (-1);
00454         }
00455     }
00456     // It's not correct module ID
00457     else {
00458         return (-1);
00459     }
00460 
00461     // Update EMAC configuration with current PHY status
00462     if (EMAC_UpdatePHYStatus() < 0){
00463         return (-1);
00464     }
00465 
00466     // Complete
00467     return (0);
00468 }
00469 
00470 
00471 /*********************************************************************//**
00472  * @brief       Auto-Configures value for the EMAC configuration register to
00473  *              match with current PHY mode
00474  * @param[in]   None
00475  * @return      Return (0) if no error, otherwise return (-1)
00476  *
00477  * Note: The EMAC configuration will be auto-configured:
00478  *      - Speed mode.
00479  *      - Half/Full duplex mode
00480  **********************************************************************/
00481 int32_t EMAC_UpdatePHYStatus(void)
00482 {
00483     int32_t regv, tout;
00484 
00485     /* Check the link status. */
00486     for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
00487         regv = read_PHY (EMAC_PHY_REG_STS);
00488         if (regv & EMAC_PHY_SR_LINK) {
00489             /* Link is on. */
00490             break;
00491         }
00492         if (tout == 0){
00493             // time out
00494             return (-1);
00495         }
00496     }
00497 
00498     /* Configure Full/Half Duplex mode. */
00499     if (regv & EMAC_PHY_SR_DUP) {
00500         /* Full duplex is enabled. */
00501         LPC_EMAC->MAC2    |= EMAC_MAC2_FULL_DUP;
00502         LPC_EMAC->Command |= EMAC_CR_FULL_DUP;
00503         LPC_EMAC->IPGT     = EMAC_IPGT_FULL_DUP;
00504     } else {
00505         /* Half duplex mode. */
00506         LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP;
00507     }
00508 
00509     /* Configure 100MBit/10MBit mode. */
00510     if (regv & EMAC_PHY_SR_SPEED) {
00511         /* 10MBit mode. */
00512         LPC_EMAC->SUPP = 0;
00513     } else {
00514         /* 100MBit mode. */
00515         LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
00516     }
00517 
00518     // Complete
00519     return (0);
00520 }
00521 
00522 
00523 /*********************************************************************//**
00524  * @brief       Enable/Disable hash filter functionality for specified destination
00525  *              MAC address in EMAC module
00526  * @param[in]   dstMAC_addr     Pointer to the first MAC destination address, should
00527  *                              be 6-bytes length, in order LSB to the MSB
00528  * @param[in]   NewState        New State of this command, should be:
00529  *                                  - ENABLE.
00530  *                                  - DISABLE.
00531  * @return      None
00532  *
00533  * Note:
00534  * The standard Ethernet cyclic redundancy check (CRC) function is calculated from
00535  * the 6 byte destination address in the Ethernet frame (this CRC is calculated
00536  * anyway as part of calculating the CRC of the whole frame), then bits [28:23] out of
00537  * the 32 bits CRC result are taken to form the hash. The 6 bit hash is used to access
00538  * the hash table: it is used as an index in the 64 bit HashFilter register that has been
00539  * programmed with accept values. If the selected accept value is 1, the frame is
00540  * accepted.
00541  **********************************************************************/
00542 void EMAC_SetHashFilter(uint8_t dstMAC_addr[], FunctionalState NewState)
00543 {
00544     uint32_t *pReg;
00545     uint32_t tmp;
00546     int32_t crc;
00547 
00548     // Calculate the CRC from the destination MAC address
00549     crc = EMAC_CRCCalc(dstMAC_addr, 6);
00550     // Extract the value from CRC to get index value for hash filter table
00551     crc = (crc >> 23) & 0x3F;
00552 
00553     pReg = (crc > 31) ? ((uint32_t *)&LPC_EMAC->HashFilterH) \
00554                                 : ((uint32_t *)&LPC_EMAC->HashFilterL);
00555     tmp = (crc > 31) ? (crc - 32) : crc;
00556     if (NewState == ENABLE) {
00557         (*pReg) |= (1UL << tmp);
00558     } else {
00559         (*pReg) &= ~(1UL << tmp);
00560     }
00561     // Enable Rx Filter
00562     LPC_EMAC->Command &= ~EMAC_CR_PASS_RX_FILT;
00563 }
00564 
00565 
00566 /*********************************************************************//**
00567  * @brief       Calculates CRC code for number of bytes in the frame
00568  * @param[in]   frame_no_fcs    Pointer to the first byte of the frame
00569  * @param[in]   frame_len       length of the frame without the FCS
00570  * @return      the CRC as a 32 bit integer
00571  **********************************************************************/
00572 int32_t EMAC_CRCCalc(uint8_t frame_no_fcs[], int32_t frame_len)
00573 {
00574     int i;      // iterator
00575     int j;      // another iterator
00576     char byte;  // current byte
00577     int crc;    // CRC result
00578     int q0, q1, q2, q3; // temporary variables
00579     crc = 0xFFFFFFFF;
00580     for (i = 0; i < frame_len; i++) {
00581         byte = *frame_no_fcs++;
00582         for (j = 0; j < 2; j++) {
00583             if (((crc >> 28) ^ (byte >> 3)) & 0x00000001) {
00584                 q3 = 0x04C11DB7;
00585             } else {
00586                 q3 = 0x00000000;
00587             }
00588             if (((crc >> 29) ^ (byte >> 2)) & 0x00000001) {
00589                 q2 = 0x09823B6E;
00590             } else {
00591                 q2 = 0x00000000;
00592             }
00593             if (((crc >> 30) ^ (byte >> 1)) & 0x00000001) {
00594                 q1 = 0x130476DC;
00595             } else {
00596                 q1 = 0x00000000;
00597             }
00598             if (((crc >> 31) ^ (byte >> 0)) & 0x00000001) {
00599                 q0 = 0x2608EDB8;
00600             } else {
00601                 q0 = 0x00000000;
00602             }
00603             crc = (crc << 4) ^ q3 ^ q2 ^ q1 ^ q0;
00604             byte >>= 4;
00605         }
00606     }
00607     return crc;
00608 }
00609 
00610 /*********************************************************************//**
00611  * @brief       Enable/Disable Filter mode for each specified type EMAC peripheral
00612  * @param[in]   ulFilterMode    Filter mode, should be:
00613  *                              - EMAC_RFC_UCAST_EN: all frames of unicast types
00614  *                              will be accepted
00615  *                              - EMAC_RFC_BCAST_EN: broadcast frame will be
00616  *                              accepted
00617  *                              - EMAC_RFC_MCAST_EN: all frames of multicast
00618  *                              types will be accepted
00619  *                              - EMAC_RFC_UCAST_HASH_EN: The imperfect hash
00620  *                              filter will be applied to unicast addresses
00621  *                              - EMAC_RFC_MCAST_HASH_EN: The imperfect hash
00622  *                              filter will be applied to multicast addresses
00623  *                              - EMAC_RFC_PERFECT_EN: the destination address
00624  *                              will be compared with the 6 byte station address
00625  *                              programmed in the station address by the filter
00626  *                              - EMAC_RFC_MAGP_WOL_EN: the result of the magic
00627  *                              packet filter will generate a WoL interrupt when
00628  *                              there is a match
00629  *                              - EMAC_RFC_PFILT_WOL_EN: the result of the perfect address
00630  *                              matching filter and the imperfect hash filter will
00631  *                              generate a WoL interrupt when there is a match
00632  * @param[in]   NewState    New State of this command, should be:
00633  *                              - ENABLE
00634  *                              - DISABLE
00635  * @return      None
00636  **********************************************************************/
00637 void EMAC_SetFilterMode(uint32_t ulFilterMode, FunctionalState NewState)
00638 {
00639     if (NewState == ENABLE){
00640         LPC_EMAC->RxFilterCtrl |= ulFilterMode;
00641     } else {
00642         LPC_EMAC->RxFilterCtrl &= ~ulFilterMode;
00643     }
00644 }
00645 
00646 /*********************************************************************//**
00647  * @brief       Get status of Wake On LAN Filter for each specified
00648  *              type in EMAC peripheral, clear this status if it is set
00649  * @param[in]   ulWoLMode   WoL Filter mode, should be:
00650  *                              - EMAC_WOL_UCAST: unicast frames caused WoL
00651  *                              - EMAC_WOL_UCAST: broadcast frame caused WoL
00652  *                              - EMAC_WOL_MCAST: multicast frame caused WoL
00653  *                              - EMAC_WOL_UCAST_HASH: unicast frame that passes the
00654  *                              imperfect hash filter caused WoL
00655  *                              - EMAC_WOL_MCAST_HASH: multicast frame that passes the
00656  *                              imperfect hash filter caused WoL
00657  *                              - EMAC_WOL_PERFECT:perfect address matching filter
00658  *                              caused WoL
00659  *                              - EMAC_WOL_RX_FILTER: the receive filter caused WoL
00660  *                              - EMAC_WOL_MAG_PACKET: the magic packet filter caused WoL
00661  * @return      SET/RESET
00662  **********************************************************************/
00663 FlagStatus EMAC_GetWoLStatus(uint32_t ulWoLMode)
00664 {
00665     if (LPC_EMAC->RxFilterWoLStatus & ulWoLMode) {
00666         LPC_EMAC->RxFilterWoLClear = ulWoLMode;
00667         return SET;
00668     } else {
00669         return RESET;
00670     }
00671 }
00672 
00673 
00674 /*********************************************************************//**
00675  * @brief       Write data to Tx packet data buffer at current index due to
00676  *              TxProduceIndex
00677  * @param[in]   pDataStruct     Pointer to a EMAC_PACKETBUF_Type structure
00678  *                          data that contain specified information about
00679  *                          Packet data buffer.
00680  * @return      None
00681  **********************************************************************/
00682 void EMAC_WritePacketBuffer(EMAC_PACKETBUF_Type *pDataStruct)
00683 {
00684     uint32_t idx,len;
00685     uint32_t *sp,*dp;
00686 
00687     idx = LPC_EMAC->TxProduceIndex;
00688     sp  = (uint32_t *)pDataStruct->pbDataBuf;
00689     dp  = (uint32_t *)Tx_Desc[idx].Packet;
00690     /* Copy frame data to EMAC packet buffers. */
00691     for (len = (pDataStruct->ulDataLen + 3) >> 2; len; len--) {
00692         *dp++ = *sp++;
00693     }
00694     Tx_Desc[idx].Ctrl = (pDataStruct->ulDataLen - 1) | (EMAC_TCTRL_INT | EMAC_TCTRL_LAST);
00695 }
00696 
00697 /*********************************************************************//**
00698  * @brief       Read data from Rx packet data buffer at current index due
00699  *              to RxConsumeIndex
00700  * @param[in]   pDataStruct     Pointer to a EMAC_PACKETBUF_Type structure
00701  *                          data that contain specified information about
00702  *                          Packet data buffer.
00703  * @return      None
00704  **********************************************************************/
00705 void EMAC_ReadPacketBuffer(EMAC_PACKETBUF_Type *pDataStruct)
00706 {
00707     uint32_t idx, len;
00708     uint32_t *dp, *sp;
00709 
00710     idx = LPC_EMAC->RxConsumeIndex;
00711     dp = (uint32_t *)pDataStruct->pbDataBuf;
00712     sp = (uint32_t *)Rx_Desc[idx].Packet;
00713 
00714     if (pDataStruct->pbDataBuf != NULL) {
00715         for (len = (pDataStruct->ulDataLen + 3) >> 2; len; len--) {
00716             *dp++ = *sp++;
00717         }
00718     }
00719 }
00720 
00721 /*********************************************************************//**
00722  * @brief       Standard EMAC IRQ Handler. This sub-routine will check
00723  *              these following interrupt and call the call-back function
00724  *              if they're already installed:
00725  *              - Overrun Error interrupt in RX Queue
00726  *              - Receive Error interrupt: AlignmentError, RangeError,
00727  *              LengthError, SymbolError, CRCError or NoDescriptor or Overrun
00728  *              - RX Finished Process Descriptors interrupt (ProduceIndex == ConsumeIndex)
00729  *              - Receive Done interrupt
00730  *              - Transmit Under-run interrupt
00731  *              - Transmit errors interrupt : LateCollision, ExcessiveCollision
00732  *              and ExcessiveDefer, NoDescriptor or Under-run
00733  *              - TX Finished Process Descriptors interrupt (ProduceIndex == ConsumeIndex)
00734  *              - Transmit Done interrupt
00735  *              - Interrupt triggered by software
00736  *              - Interrupt triggered by a Wakeup event detected by the receive filter
00737  * @param[in]   None
00738  * @return      None
00739  **********************************************************************/
00740 void EMAC_StandardIRQHandler(void)
00741 {
00742     /* EMAC Ethernet Controller Interrupt function. */
00743     uint32_t n, int_stat;
00744 
00745     // Get EMAC interrupt status
00746     while ((int_stat = (LPC_EMAC->IntStatus & LPC_EMAC->IntEnable)) != 0) {
00747         // Clear interrupt status
00748         LPC_EMAC->IntClear = int_stat;
00749         // Execute call-back function
00750         for (n = 0; n <= 7; n++) {
00751             if ((int_stat & (1 << n)) && (_pfnIntCbDat[n] != NULL)) {
00752                 _pfnIntCbDat[n]();
00753             }
00754         }
00755         // Soft interrupt
00756         if ((int_stat & EMAC_INT_SOFT_INT) && (_pfnIntCbDat[8] != NULL)) {
00757             _pfnIntCbDat[8]();
00758         }
00759         // WakeUp interrupt
00760         if ((int_stat & EMAC_INT_WAKEUP) && (_pfnIntCbDat[9] != NULL)) {
00761             // Clear WoL interrupt
00762             LPC_EMAC->RxFilterWoLClear = EMAC_WOL_BITMASK;
00763             _pfnIntCbDat[9]();
00764         }
00765     }
00766 }
00767 
00768 
00769 /*********************************************************************//**
00770  * @brief       Setup/register Call-back function for each interrupt type
00771  *              in EMAC module.
00772  * @param[in]   ulIntType   Interrupt type, should be one of the following:
00773  *                          - EMAC_INT_RX_OVERRUN: Receive Overrun
00774  *                          - EMAC_INT_RX_ERR: Receive Error
00775  *                          - EMAC_INT_RX_FIN: Receive Descriptor Finish
00776  *                          - EMAC_INT_RX_DONE: Receive Done
00777  *                          - EMAC_INT_TX_UNDERRUN: Transmit Under-run
00778  *                          - EMAC_INT_TX_ERR: Transmit Error
00779  *                          - EMAC_INT_TX_FIN: Transmit descriptor finish
00780  *                          - EMAC_INT_TX_DONE: Transmit Done
00781  *                          - EMAC_INT_SOFT_INT: Software interrupt
00782  *                          - EMAC_INT_WAKEUP: Wakeup interrupt
00783  * @param[in]   pfnIntCb    Pointer to Call-back function used for this
00784  *                          interrupt type
00785  * @return      None
00786  **********************************************************************/
00787 void EMAC_SetupIntCBS(uint32_t ulIntType, EMAC_IntCBSType *pfnIntCb)
00788 {
00789     /* EMAC Ethernet Controller Interrupt function. */
00790     uint32_t n;
00791 
00792     if (ulIntType <= EMAC_INT_TX_DONE){
00793         for (n = 0; n <= 7; n++) {
00794             // Found it, install cbs now
00795             if (ulIntType & (1 << n)) {
00796                 _pfnIntCbDat[n] = pfnIntCb;
00797                 // Don't install cbs any more
00798                 break;
00799             }
00800         }
00801     } else if (ulIntType & EMAC_INT_SOFT_INT) {
00802         _pfnIntCbDat[8] = pfnIntCb;
00803     } else if (ulIntType & EMAC_INT_WAKEUP) {
00804         _pfnIntCbDat[9] = pfnIntCb;
00805     }
00806 }
00807 
00808 /*********************************************************************//**
00809  * @brief       Enable/Disable interrupt for each type in EMAC
00810  * @param[in]   ulIntType   Interrupt Type, should be:
00811  *                          - EMAC_INT_RX_OVERRUN: Receive Overrun
00812  *                          - EMAC_INT_RX_ERR: Receive Error
00813  *                          - EMAC_INT_RX_FIN: Receive Descriptor Finish
00814  *                          - EMAC_INT_RX_DONE: Receive Done
00815  *                          - EMAC_INT_TX_UNDERRUN: Transmit Under-run
00816  *                          - EMAC_INT_TX_ERR: Transmit Error
00817  *                          - EMAC_INT_TX_FIN: Transmit descriptor finish
00818  *                          - EMAC_INT_TX_DONE: Transmit Done
00819  *                          - EMAC_INT_SOFT_INT: Software interrupt
00820  *                          - EMAC_INT_WAKEUP: Wakeup interrupt
00821  * @param[in]   NewState    New State of this function, should be:
00822  *                          - ENABLE.
00823  *                          - DISABLE.
00824  * @return      None
00825  **********************************************************************/
00826 void EMAC_IntCmd(uint32_t ulIntType, FunctionalState NewState)
00827 {
00828     if (NewState == ENABLE) {
00829         LPC_EMAC->IntEnable |= ulIntType;
00830     } else {
00831         LPC_EMAC->IntEnable &= ~(ulIntType);
00832     }
00833 }
00834 
00835 /*********************************************************************//**
00836  * @brief       Check whether if specified interrupt flag is set or not
00837  *              for each interrupt type in EMAC and clear interrupt pending
00838  *              if it is set.
00839  * @param[in]   ulIntType   Interrupt Type, should be:
00840  *                          - EMAC_INT_RX_OVERRUN: Receive Overrun
00841  *                          - EMAC_INT_RX_ERR: Receive Error
00842  *                          - EMAC_INT_RX_FIN: Receive Descriptor Finish
00843  *                          - EMAC_INT_RX_DONE: Receive Done
00844  *                          - EMAC_INT_TX_UNDERRUN: Transmit Under-run
00845  *                          - EMAC_INT_TX_ERR: Transmit Error
00846  *                          - EMAC_INT_TX_FIN: Transmit descriptor finish
00847  *                          - EMAC_INT_TX_DONE: Transmit Done
00848  *                          - EMAC_INT_SOFT_INT: Software interrupt
00849  *                          - EMAC_INT_WAKEUP: Wakeup interrupt
00850  * @return      New state of specified interrupt (SET or RESET)
00851  **********************************************************************/
00852 IntStatus EMAC_IntGetStatus(uint32_t ulIntType)
00853 {
00854     if (LPC_EMAC->IntStatus & ulIntType) {
00855         LPC_EMAC->IntClear = ulIntType;
00856         return SET;
00857     } else {
00858         return RESET;
00859     }
00860 }
00861 
00862 
00863 /*********************************************************************//**
00864  * @brief       Check whether if the current RxConsumeIndex is not equal to the
00865  *              current RxProduceIndex.
00866  * @param[in]   None
00867  * @return      TRUE if they're not equal, otherwise return FALSE
00868  *
00869  * Note: In case the RxConsumeIndex is not equal to the RxProduceIndex,
00870  * it means there're available data has been received. They should be read
00871  * out and released the Receive Data Buffer by updating the RxConsumeIndex value.
00872  **********************************************************************/
00873 Bool EMAC_CheckReceiveIndex(void)
00874 {
00875     if (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex) {
00876         return TRUE;
00877     } else {
00878         return FALSE;
00879     }
00880 }
00881 
00882 
00883 /*********************************************************************//**
00884  * @brief       Check whether if the current TxProduceIndex is not equal to the
00885  *              current RxProduceIndex - 1.
00886  * @param[in]   None
00887  * @return      TRUE if they're not equal, otherwise return FALSE
00888  *
00889  * Note: In case the RxConsumeIndex is equal to the RxProduceIndex - 1,
00890  * it means the transmit buffer is available and data can be written to transmit
00891  * buffer to be sent.
00892  **********************************************************************/
00893 Bool EMAC_CheckTransmitIndex(void)
00894 {
00895     uint32_t tmp = LPC_EMAC->TxConsumeIndex -1;
00896     if (LPC_EMAC->TxProduceIndex == tmp) {
00897         return FALSE;
00898     } else {
00899         return TRUE;
00900     }
00901 }
00902 
00903 
00904 /*********************************************************************//**
00905  * @brief       Get current status value of receive data (due to RxConsumeIndex)
00906  * @param[in]   ulRxStatType    Received Status type, should be one of following:
00907  *                          - EMAC_RINFO_CTRL_FRAME: Control Frame
00908  *                          - EMAC_RINFO_VLAN: VLAN Frame
00909  *                          - EMAC_RINFO_FAIL_FILT: RX Filter Failed
00910  *                          - EMAC_RINFO_MCAST: Multicast Frame
00911  *                          - EMAC_RINFO_BCAST: Broadcast Frame
00912  *                          - EMAC_RINFO_CRC_ERR: CRC Error in Frame
00913  *                          - EMAC_RINFO_SYM_ERR: Symbol Error from PHY
00914  *                          - EMAC_RINFO_LEN_ERR: Length Error
00915  *                          - EMAC_RINFO_RANGE_ERR: Range error(exceeded max size)
00916  *                          - EMAC_RINFO_ALIGN_ERR: Alignment error
00917  *                          - EMAC_RINFO_OVERRUN: Receive overrun
00918  *                          - EMAC_RINFO_NO_DESCR: No new Descriptor available
00919  *                          - EMAC_RINFO_LAST_FLAG: last Fragment in Frame
00920  *                          - EMAC_RINFO_ERR: Error Occurred (OR of all error)
00921  * @return      Current value of receive data (due to RxConsumeIndex)
00922  **********************************************************************/
00923 FlagStatus EMAC_CheckReceiveDataStatus(uint32_t ulRxStatType)
00924 {
00925     uint32_t idx;
00926     idx = LPC_EMAC->RxConsumeIndex;
00927     return (((Rx_Stat[idx].Info) & ulRxStatType) ? SET : RESET);
00928 }
00929 
00930 
00931 /*********************************************************************//**
00932  * @brief       Get size of current Received data in received buffer (due to
00933  *              RxConsumeIndex)
00934  * @param[in]   None
00935  * @return      Size of received data
00936  **********************************************************************/
00937 uint32_t EMAC_GetReceiveDataSize(void)
00938 {
00939     uint32_t idx;
00940     idx =LPC_EMAC->RxConsumeIndex;
00941     return ((Rx_Stat[idx].Info) & EMAC_RINFO_SIZE);
00942 }
00943 
00944 /*********************************************************************//**
00945  * @brief       Increase the RxConsumeIndex (after reading the Receive buffer
00946  *              to release the Receive buffer) and wrap-around the index if
00947  *              it reaches the maximum Receive Number
00948  * @param[in]   None
00949  * @return      None
00950  **********************************************************************/
00951 void EMAC_UpdateRxConsumeIndex(void)
00952 {
00953     // Get current Rx consume index
00954     uint32_t idx = LPC_EMAC->RxConsumeIndex;
00955 
00956     /* Release frame from EMAC buffer */
00957     if (++idx == EMAC_NUM_RX_FRAG) idx = 0;
00958     LPC_EMAC->RxConsumeIndex = idx;
00959 }
00960 
00961 /*********************************************************************//**
00962  * @brief       Increase the TxProduceIndex (after writting to the Transmit buffer
00963  *              to enable the Transmit buffer) and wrap-around the index if
00964  *              it reaches the maximum Transmit Number
00965  * @param[in]   None
00966  * @return      None
00967  **********************************************************************/
00968 void EMAC_UpdateTxProduceIndex(void)
00969 {
00970     // Get current Tx produce index
00971     uint32_t idx = LPC_EMAC->TxProduceIndex;
00972 
00973     /* Start frame transmission */
00974     if (++idx == EMAC_NUM_TX_FRAG) idx = 0;
00975     LPC_EMAC->TxProduceIndex = idx;
00976 }
00977 
00978 
00979 /**
00980  * @}
00981  */
00982 
00983 #endif /* _EMAC */
00984 
00985 /**
00986  * @}
00987  */
00988 
00989 /* --------------------------------- End Of File ------------------------------ */