Rewrite from scratch a TCP/IP stack for mbed. So far the following parts are usable: Drivers: - EMAC driver (from CMSIS 2.0) Protocols: - Ethernet protocol - ARP over ethernet for IPv4 - IPv4 over Ethernet - ICMPv4 over IPv4 - UDPv4 over IPv4 APIs: - Sockets for UDPv4 The structure of this stack is designed to be very modular. Each protocol can register one or more protocol to handle its payload, and in each protocol, an API can be hooked (like Sockets for example). This is an early release.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lpc17xx_emac.cpp Source File

lpc17xx_emac.cpp

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