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

Committer:
igorsk
Date:
Wed Feb 17 16:22:39 2010 +0000
Revision:
0:1063a091a062

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
igorsk 0:1063a091a062 1 /**
igorsk 0:1063a091a062 2 * @file : lpc17xx_emac.c
igorsk 0:1063a091a062 3 * @brief : Contains all functions support for Ethernet MAC firmware library on LPC17xx
igorsk 0:1063a091a062 4 * @version : 1.0
igorsk 0:1063a091a062 5 * @date : 02. Jun. 2009
igorsk 0:1063a091a062 6 * @author : HieuNguyen
igorsk 0:1063a091a062 7 **************************************************************************
igorsk 0:1063a091a062 8 * Software that is described herein is for illustrative purposes only
igorsk 0:1063a091a062 9 * which provides customers with programming information regarding the
igorsk 0:1063a091a062 10 * products. This software is supplied "AS IS" without any warranties.
igorsk 0:1063a091a062 11 * NXP Semiconductors assumes no responsibility or liability for the
igorsk 0:1063a091a062 12 * use of the software, conveys no license or title under any patent,
igorsk 0:1063a091a062 13 * copyright, or mask work right to the product. NXP Semiconductors
igorsk 0:1063a091a062 14 * reserves the right to make changes in the software without
igorsk 0:1063a091a062 15 * notification. NXP Semiconductors also make no representation or
igorsk 0:1063a091a062 16 * warranty that such application will be suitable for the specified
igorsk 0:1063a091a062 17 * use without further testing or modification.
igorsk 0:1063a091a062 18 **********************************************************************/
igorsk 0:1063a091a062 19
igorsk 0:1063a091a062 20 /* Peripheral group ----------------------------------------------------------- */
igorsk 0:1063a091a062 21 /** @addtogroup EMAC
igorsk 0:1063a091a062 22 * @{
igorsk 0:1063a091a062 23 */
igorsk 0:1063a091a062 24
igorsk 0:1063a091a062 25 /* Includes ------------------------------------------------------------------- */
igorsk 0:1063a091a062 26 #include "lpc17xx_emac.h"
igorsk 0:1063a091a062 27 #include "lpc17xx_clkpwr.h"
igorsk 0:1063a091a062 28
igorsk 0:1063a091a062 29 /* If this source file built with example, the LPC17xx FW library configuration
igorsk 0:1063a091a062 30 * file in each example directory ("lpc17xx_libcfg.h") must be included,
igorsk 0:1063a091a062 31 * otherwise the default FW library configuration file must be included instead
igorsk 0:1063a091a062 32 */
igorsk 0:1063a091a062 33 #ifdef __BUILD_WITH_EXAMPLE__
igorsk 0:1063a091a062 34 #include "lpc17xx_libcfg.h"
igorsk 0:1063a091a062 35 #else
igorsk 0:1063a091a062 36 #include "lpc17xx_libcfg_default.h"
igorsk 0:1063a091a062 37 #endif /* __BUILD_WITH_EXAMPLE__ */
igorsk 0:1063a091a062 38
igorsk 0:1063a091a062 39
igorsk 0:1063a091a062 40 #ifdef _EMAC
igorsk 0:1063a091a062 41
igorsk 0:1063a091a062 42 /* Private Variables ---------------------------------------------------------- */
igorsk 0:1063a091a062 43 /** @defgroup EMAC_Private_Variables
igorsk 0:1063a091a062 44 * @{
igorsk 0:1063a091a062 45 */
igorsk 0:1063a091a062 46
igorsk 0:1063a091a062 47 /* MII Mgmt Configuration register - Clock divider setting */
igorsk 0:1063a091a062 48 const uint8_t EMAC_clkdiv[] = { 4, 6, 8, 10, 14, 20, 28 };
igorsk 0:1063a091a062 49
igorsk 0:1063a091a062 50 /* EMAC local DMA Descriptors */
igorsk 0:1063a091a062 51
igorsk 0:1063a091a062 52 /** Rx Descriptor data array */
igorsk 0:1063a091a062 53 static RX_Desc Rx_Desc[EMAC_NUM_RX_FRAG];
igorsk 0:1063a091a062 54
igorsk 0:1063a091a062 55 /** Rx Status data array - Must be 8-Byte aligned */
igorsk 0:1063a091a062 56 #if defined ( __CC_ARM )
igorsk 0:1063a091a062 57 static __align(8) RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG];
igorsk 0:1063a091a062 58 #elif defined ( __ICCARM__ )
igorsk 0:1063a091a062 59 #pragma data_alignment=8
igorsk 0:1063a091a062 60 static RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG];
igorsk 0:1063a091a062 61 #elif defined ( __GNUC__ )
igorsk 0:1063a091a062 62 static __attribute__ ((aligned (8))) RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG];
igorsk 0:1063a091a062 63 #endif
igorsk 0:1063a091a062 64
igorsk 0:1063a091a062 65 /** Tx Descriptor data array */
igorsk 0:1063a091a062 66 static TX_Desc Tx_Desc[EMAC_NUM_TX_FRAG];
igorsk 0:1063a091a062 67 /** Tx Status data array */
igorsk 0:1063a091a062 68 static TX_Stat Tx_Stat[EMAC_NUM_TX_FRAG];
igorsk 0:1063a091a062 69
igorsk 0:1063a091a062 70 /* EMAC local DMA buffers */
igorsk 0:1063a091a062 71 /** Rx buffer data */
igorsk 0:1063a091a062 72 static uint32_t rx_buf[EMAC_NUM_RX_FRAG][EMAC_ETH_MAX_FLEN>>2];
igorsk 0:1063a091a062 73 /** Tx buffer data */
igorsk 0:1063a091a062 74 static uint32_t tx_buf[EMAC_NUM_TX_FRAG][EMAC_ETH_MAX_FLEN>>2];
igorsk 0:1063a091a062 75
igorsk 0:1063a091a062 76 /* EMAC call-back function pointer data */
igorsk 0:1063a091a062 77 static EMAC_IntCBSType *_pfnIntCbDat[10];
igorsk 0:1063a091a062 78
igorsk 0:1063a091a062 79 /**
igorsk 0:1063a091a062 80 * @}
igorsk 0:1063a091a062 81 */
igorsk 0:1063a091a062 82
igorsk 0:1063a091a062 83
igorsk 0:1063a091a062 84 /* Private Functions ---------------------------------------------------------- */
igorsk 0:1063a091a062 85 /** @defgroup EMAC_Private_Functions
igorsk 0:1063a091a062 86 * @{
igorsk 0:1063a091a062 87 */
igorsk 0:1063a091a062 88
igorsk 0:1063a091a062 89 static void rx_descr_init (void);
igorsk 0:1063a091a062 90 static void tx_descr_init (void);
igorsk 0:1063a091a062 91 static int32_t write_PHY (uint32_t PhyReg, uint16_t Value);
igorsk 0:1063a091a062 92 static int32_t read_PHY (uint32_t PhyReg);
igorsk 0:1063a091a062 93
igorsk 0:1063a091a062 94
igorsk 0:1063a091a062 95 /*--------------------------- rx_descr_init ---------------------------------*/
igorsk 0:1063a091a062 96
igorsk 0:1063a091a062 97 /**
igorsk 0:1063a091a062 98 * @brief Initializes RX Descriptor
igorsk 0:1063a091a062 99 * @param[in] None
igorsk 0:1063a091a062 100 * @return None
igorsk 0:1063a091a062 101 */
igorsk 0:1063a091a062 102 static void rx_descr_init (void)
igorsk 0:1063a091a062 103 {
igorsk 0:1063a091a062 104 /* Initialize Receive Descriptor and Status array. */
igorsk 0:1063a091a062 105 uint32_t i;
igorsk 0:1063a091a062 106
igorsk 0:1063a091a062 107 for (i = 0; i < EMAC_NUM_RX_FRAG; i++) {
igorsk 0:1063a091a062 108 Rx_Desc[i].Packet = (uint32_t)&rx_buf[i];
igorsk 0:1063a091a062 109 Rx_Desc[i].Ctrl = EMAC_RCTRL_INT | (EMAC_ETH_MAX_FLEN - 1);
igorsk 0:1063a091a062 110 Rx_Stat[i].Info = 0;
igorsk 0:1063a091a062 111 Rx_Stat[i].HashCRC = 0;
igorsk 0:1063a091a062 112 }
igorsk 0:1063a091a062 113
igorsk 0:1063a091a062 114 /* Set EMAC Receive Descriptor Registers. */
igorsk 0:1063a091a062 115 LPC_EMAC->RxDescriptor = (uint32_t)&Rx_Desc[0];
igorsk 0:1063a091a062 116 LPC_EMAC->RxStatus = (uint32_t)&Rx_Stat[0];
igorsk 0:1063a091a062 117 LPC_EMAC->RxDescriptorNumber = EMAC_NUM_RX_FRAG - 1;
igorsk 0:1063a091a062 118
igorsk 0:1063a091a062 119 /* Rx Descriptors Point to 0 */
igorsk 0:1063a091a062 120 LPC_EMAC->RxConsumeIndex = 0;
igorsk 0:1063a091a062 121 }
igorsk 0:1063a091a062 122
igorsk 0:1063a091a062 123
igorsk 0:1063a091a062 124 /*--------------------------- tx_descr_init ---- ----------------------------*/
igorsk 0:1063a091a062 125 /**
igorsk 0:1063a091a062 126 * @brief Initializes TX Descriptor
igorsk 0:1063a091a062 127 * @param[in] None
igorsk 0:1063a091a062 128 * @return None
igorsk 0:1063a091a062 129 */
igorsk 0:1063a091a062 130 static void tx_descr_init (void) {
igorsk 0:1063a091a062 131 /* Initialize Transmit Descriptor and Status array. */
igorsk 0:1063a091a062 132 uint32_t i;
igorsk 0:1063a091a062 133
igorsk 0:1063a091a062 134 for (i = 0; i < EMAC_NUM_TX_FRAG; i++) {
igorsk 0:1063a091a062 135 Tx_Desc[i].Packet = (uint32_t)&tx_buf[i];
igorsk 0:1063a091a062 136 Tx_Desc[i].Ctrl = 0;
igorsk 0:1063a091a062 137 Tx_Stat[i].Info = 0;
igorsk 0:1063a091a062 138 }
igorsk 0:1063a091a062 139
igorsk 0:1063a091a062 140 /* Set EMAC Transmit Descriptor Registers. */
igorsk 0:1063a091a062 141 LPC_EMAC->TxDescriptor = (uint32_t)&Tx_Desc[0];
igorsk 0:1063a091a062 142 LPC_EMAC->TxStatus = (uint32_t)&Tx_Stat[0];
igorsk 0:1063a091a062 143 LPC_EMAC->TxDescriptorNumber = EMAC_NUM_TX_FRAG - 1;
igorsk 0:1063a091a062 144
igorsk 0:1063a091a062 145 /* Tx Descriptors Point to 0 */
igorsk 0:1063a091a062 146 LPC_EMAC->TxProduceIndex = 0;
igorsk 0:1063a091a062 147 }
igorsk 0:1063a091a062 148
igorsk 0:1063a091a062 149
igorsk 0:1063a091a062 150 /*--------------------------- write_PHY -------------------------------------*/
igorsk 0:1063a091a062 151 /**
igorsk 0:1063a091a062 152 * @brief Write value to PHY device
igorsk 0:1063a091a062 153 * @param[in] PhyReg PHY Register address
igorsk 0:1063a091a062 154 * @param[in] Value Value to write
igorsk 0:1063a091a062 155 * @return (0) if sucess, otherwise return (-1)
igorsk 0:1063a091a062 156 */
igorsk 0:1063a091a062 157 static int32_t write_PHY (uint32_t PhyReg, uint16_t Value)
igorsk 0:1063a091a062 158 {
igorsk 0:1063a091a062 159 /* Write a data 'Value' to PHY register 'PhyReg'. */
igorsk 0:1063a091a062 160 uint32_t tout;
igorsk 0:1063a091a062 161
igorsk 0:1063a091a062 162 LPC_EMAC->MADR = EMAC_DP83848C_DEF_ADR | PhyReg;
igorsk 0:1063a091a062 163 LPC_EMAC->MWTD = Value;
igorsk 0:1063a091a062 164
igorsk 0:1063a091a062 165 /* Wait until operation completed */
igorsk 0:1063a091a062 166 tout = 0;
igorsk 0:1063a091a062 167 for (tout = 0; tout < EMAC_MII_WR_TOUT; tout++) {
igorsk 0:1063a091a062 168 if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) {
igorsk 0:1063a091a062 169 return (0);
igorsk 0:1063a091a062 170 }
igorsk 0:1063a091a062 171 }
igorsk 0:1063a091a062 172 // Time out!
igorsk 0:1063a091a062 173 return (-1);
igorsk 0:1063a091a062 174 }
igorsk 0:1063a091a062 175
igorsk 0:1063a091a062 176
igorsk 0:1063a091a062 177 /*--------------------------- read_PHY --------------------------------------*/
igorsk 0:1063a091a062 178 /**
igorsk 0:1063a091a062 179 * @brief Read value from PHY device
igorsk 0:1063a091a062 180 * @param[in] PhyReg PHY Register address
igorsk 0:1063a091a062 181 * @return Return value if success, otherwise return (-1)
igorsk 0:1063a091a062 182 */
igorsk 0:1063a091a062 183 static int32_t read_PHY (uint32_t PhyReg)
igorsk 0:1063a091a062 184 {
igorsk 0:1063a091a062 185 /* Read a PHY register 'PhyReg'. */
igorsk 0:1063a091a062 186 uint32_t tout;
igorsk 0:1063a091a062 187
igorsk 0:1063a091a062 188 LPC_EMAC->MADR = EMAC_DP83848C_DEF_ADR | PhyReg;
igorsk 0:1063a091a062 189 LPC_EMAC->MCMD = EMAC_MCMD_READ;
igorsk 0:1063a091a062 190
igorsk 0:1063a091a062 191 /* Wait until operation completed */
igorsk 0:1063a091a062 192 tout = 0;
igorsk 0:1063a091a062 193 for (tout = 0; tout < EMAC_MII_RD_TOUT; tout++) {
igorsk 0:1063a091a062 194 if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) {
igorsk 0:1063a091a062 195 LPC_EMAC->MCMD = 0;
igorsk 0:1063a091a062 196 return (LPC_EMAC->MRDD);
igorsk 0:1063a091a062 197 }
igorsk 0:1063a091a062 198 }
igorsk 0:1063a091a062 199 // Time out!
igorsk 0:1063a091a062 200 return (-1);
igorsk 0:1063a091a062 201 }
igorsk 0:1063a091a062 202
igorsk 0:1063a091a062 203 /*********************************************************************//**
igorsk 0:1063a091a062 204 * @brief Set Station MAC address for EMAC module
igorsk 0:1063a091a062 205 * @param[in] abStationAddr Pointer to Station address that contains 6-bytes
igorsk 0:1063a091a062 206 * of MAC address (should be in order from MAC Address 1 to MAC Address 6)
igorsk 0:1063a091a062 207 * @return None
igorsk 0:1063a091a062 208 **********************************************************************/
igorsk 0:1063a091a062 209 void setEmacAddr(uint8_t abStationAddr[])
igorsk 0:1063a091a062 210 {
igorsk 0:1063a091a062 211 /* Set the Ethernet MAC Address registers */
igorsk 0:1063a091a062 212 LPC_EMAC->SA0 = ((uint32_t)abStationAddr[5] << 8) | (uint32_t)abStationAddr[4];
igorsk 0:1063a091a062 213 LPC_EMAC->SA1 = ((uint32_t)abStationAddr[3] << 8) | (uint32_t)abStationAddr[2];
igorsk 0:1063a091a062 214 LPC_EMAC->SA2 = ((uint32_t)abStationAddr[1] << 8) | (uint32_t)abStationAddr[0];
igorsk 0:1063a091a062 215 }
igorsk 0:1063a091a062 216
igorsk 0:1063a091a062 217 /**
igorsk 0:1063a091a062 218 * @}
igorsk 0:1063a091a062 219 */
igorsk 0:1063a091a062 220
igorsk 0:1063a091a062 221
igorsk 0:1063a091a062 222 /* Public Functions ----------------------------------------------------------- */
igorsk 0:1063a091a062 223 /** @addtogroup EMAC_Public_Functions
igorsk 0:1063a091a062 224 * @{
igorsk 0:1063a091a062 225 */
igorsk 0:1063a091a062 226
igorsk 0:1063a091a062 227
igorsk 0:1063a091a062 228 /*********************************************************************//**
igorsk 0:1063a091a062 229 * @brief Initializes the EMAC peripheral according to the specified
igorsk 0:1063a091a062 230 * parameters in the EMAC_ConfigStruct.
igorsk 0:1063a091a062 231 * @param[in] EMAC_ConfigStruct Pointer to a EMAC_CFG_Type structure
igorsk 0:1063a091a062 232 * that contains the configuration information for the
igorsk 0:1063a091a062 233 * specified EMAC peripheral.
igorsk 0:1063a091a062 234 * @return None
igorsk 0:1063a091a062 235 *
igorsk 0:1063a091a062 236 * Note: This function will initialize EMAC module according to procedure below:
igorsk 0:1063a091a062 237 * - Remove the soft reset condition from the MAC
igorsk 0:1063a091a062 238 * - Configure the PHY via the MIIM interface of the MAC
igorsk 0:1063a091a062 239 * - Select RMII mode
igorsk 0:1063a091a062 240 * - Configure the transmit and receive DMA engines, including the descriptor arrays
igorsk 0:1063a091a062 241 * - Configure the host registers (MAC1,MAC2 etc.) in the MAC
igorsk 0:1063a091a062 242 * - Enable the receive and transmit data paths
igorsk 0:1063a091a062 243 * In default state after initializing, only Rx Done and Tx Done interrupt are enabled,
igorsk 0:1063a091a062 244 * all remain interrupts are disabled
igorsk 0:1063a091a062 245 * (Ref. from LPC17xx UM)
igorsk 0:1063a091a062 246 **********************************************************************/
igorsk 0:1063a091a062 247 Status EMAC_Init(EMAC_CFG_Type *EMAC_ConfigStruct)
igorsk 0:1063a091a062 248 {
igorsk 0:1063a091a062 249 /* Initialize the EMAC Ethernet controller. */
igorsk 0:1063a091a062 250 int32_t regv,tout, tmp;
igorsk 0:1063a091a062 251
igorsk 0:1063a091a062 252 /* Set up clock and power for Ethernet module */
igorsk 0:1063a091a062 253 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, ENABLE);
igorsk 0:1063a091a062 254
igorsk 0:1063a091a062 255 /* Reset all EMAC internal modules */
igorsk 0:1063a091a062 256 LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | EMAC_MAC1_RES_RX |
igorsk 0:1063a091a062 257 EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | EMAC_MAC1_SOFT_RES;
igorsk 0:1063a091a062 258
igorsk 0:1063a091a062 259 LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES | EMAC_CR_PASS_RUNT_FRM;
igorsk 0:1063a091a062 260
igorsk 0:1063a091a062 261 /* A short delay after reset. */
igorsk 0:1063a091a062 262 for (tout = 100; tout; tout--);
igorsk 0:1063a091a062 263
igorsk 0:1063a091a062 264 /* Initialize MAC control registers. */
igorsk 0:1063a091a062 265 LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL;
igorsk 0:1063a091a062 266 LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN;
igorsk 0:1063a091a062 267 LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN;
igorsk 0:1063a091a062 268 /*
igorsk 0:1063a091a062 269 * Find the clock that close to desired target clock
igorsk 0:1063a091a062 270 */
igorsk 0:1063a091a062 271 tmp = SystemCoreClock / EMAC_MCFG_MII_MAXCLK;
igorsk 0:1063a091a062 272 for (tout = 0; tout < sizeof (EMAC_clkdiv); tout++){
igorsk 0:1063a091a062 273 if (EMAC_clkdiv[tout] >= tmp) break;
igorsk 0:1063a091a062 274 }
igorsk 0:1063a091a062 275 tout++;
igorsk 0:1063a091a062 276 // Write to MAC configuration register and reset
igorsk 0:1063a091a062 277 LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(tout) | EMAC_MCFG_RES_MII;
igorsk 0:1063a091a062 278 // release reset
igorsk 0:1063a091a062 279 LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII);
igorsk 0:1063a091a062 280 LPC_EMAC->CLRT = EMAC_CLRT_DEF;
igorsk 0:1063a091a062 281 LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF;
igorsk 0:1063a091a062 282
igorsk 0:1063a091a062 283 /* Enable Reduced MII interface. */
igorsk 0:1063a091a062 284 LPC_EMAC->Command = EMAC_CR_RMII | EMAC_CR_PASS_RUNT_FRM;
igorsk 0:1063a091a062 285
igorsk 0:1063a091a062 286 /* Reset Reduced MII Logic. */
igorsk 0:1063a091a062 287 LPC_EMAC->SUPP = EMAC_SUPP_RES_RMII;
igorsk 0:1063a091a062 288
igorsk 0:1063a091a062 289 for (tout = 100; tout; tout--);
igorsk 0:1063a091a062 290 LPC_EMAC->SUPP = 0;
igorsk 0:1063a091a062 291
igorsk 0:1063a091a062 292 /* Put the DP83848C in reset mode */
igorsk 0:1063a091a062 293 write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_RESET);
igorsk 0:1063a091a062 294
igorsk 0:1063a091a062 295 /* Wait for hardware reset to end. */
igorsk 0:1063a091a062 296 for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
igorsk 0:1063a091a062 297 regv = read_PHY (EMAC_PHY_REG_BMCR);
igorsk 0:1063a091a062 298 if (!(regv & (EMAC_PHY_BMCR_RESET | EMAC_PHY_BMCR_POWERDOWN))) {
igorsk 0:1063a091a062 299 /* Reset complete, device not Power Down. */
igorsk 0:1063a091a062 300 break;
igorsk 0:1063a091a062 301 }
igorsk 0:1063a091a062 302 if (tout == 0){
igorsk 0:1063a091a062 303 // Time out, return ERROR
igorsk 0:1063a091a062 304 return (ERROR);
igorsk 0:1063a091a062 305 }
igorsk 0:1063a091a062 306 }
igorsk 0:1063a091a062 307
igorsk 0:1063a091a062 308 // Set PHY mode
igorsk 0:1063a091a062 309 if (EMAC_SetPHYMode(EMAC_ConfigStruct->Mode) < 0){
igorsk 0:1063a091a062 310 return (ERROR);
igorsk 0:1063a091a062 311 }
igorsk 0:1063a091a062 312
igorsk 0:1063a091a062 313 // Set EMAC address
igorsk 0:1063a091a062 314 setEmacAddr(EMAC_ConfigStruct->pbEMAC_Addr);
igorsk 0:1063a091a062 315
igorsk 0:1063a091a062 316 /* Initialize Tx and Rx DMA Descriptors */
igorsk 0:1063a091a062 317 rx_descr_init ();
igorsk 0:1063a091a062 318 tx_descr_init ();
igorsk 0:1063a091a062 319
igorsk 0:1063a091a062 320 // Set Receive Filter register: enable broadcast and multicast
igorsk 0:1063a091a062 321 LPC_EMAC->RxFilterCtrl = EMAC_RFC_MCAST_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN;
igorsk 0:1063a091a062 322
igorsk 0:1063a091a062 323 /* Enable Rx Done and Tx Done interrupt for EMAC */
igorsk 0:1063a091a062 324 LPC_EMAC->IntEnable = EMAC_INT_RX_DONE | EMAC_INT_TX_DONE;
igorsk 0:1063a091a062 325
igorsk 0:1063a091a062 326 /* Reset all interrupts */
igorsk 0:1063a091a062 327 LPC_EMAC->IntClear = 0xFFFF;
igorsk 0:1063a091a062 328
igorsk 0:1063a091a062 329 /* Enable receive and transmit mode of MAC Ethernet core */
igorsk 0:1063a091a062 330 LPC_EMAC->Command |= (EMAC_CR_RX_EN | EMAC_CR_TX_EN);
igorsk 0:1063a091a062 331 LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
igorsk 0:1063a091a062 332
igorsk 0:1063a091a062 333 return SUCCESS;
igorsk 0:1063a091a062 334 }
igorsk 0:1063a091a062 335
igorsk 0:1063a091a062 336
igorsk 0:1063a091a062 337 /*********************************************************************//**
igorsk 0:1063a091a062 338 * @brief De-initializes the EMAC peripheral registers to their
igorsk 0:1063a091a062 339 * default reset values.
igorsk 0:1063a091a062 340 * @param[in] None
igorsk 0:1063a091a062 341 * @return None
igorsk 0:1063a091a062 342 **********************************************************************/
igorsk 0:1063a091a062 343 void EMAC_DeInit(void)
igorsk 0:1063a091a062 344 {
igorsk 0:1063a091a062 345 // Disable all interrupt
igorsk 0:1063a091a062 346 LPC_EMAC->IntEnable = 0x00;
igorsk 0:1063a091a062 347 // Clear all pending interrupt
igorsk 0:1063a091a062 348 LPC_EMAC->IntClear = (0xFF) | (EMAC_INT_SOFT_INT | EMAC_INT_WAKEUP);
igorsk 0:1063a091a062 349
igorsk 0:1063a091a062 350 /* TurnOff clock and power for Ethernet module */
igorsk 0:1063a091a062 351 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, DISABLE);
igorsk 0:1063a091a062 352 }
igorsk 0:1063a091a062 353
igorsk 0:1063a091a062 354
igorsk 0:1063a091a062 355 /*********************************************************************//**
igorsk 0:1063a091a062 356 * @brief Check specified PHY status in EMAC peripheral
igorsk 0:1063a091a062 357 * @param[in] ulPHYState Specified PHY Status Type, should be:
igorsk 0:1063a091a062 358 * - EMAC_PHY_STAT_LINK: Link Status
igorsk 0:1063a091a062 359 * - EMAC_PHY_STAT_SPEED: Speed Status
igorsk 0:1063a091a062 360 * - EMAC_PHY_STAT_DUP: Duplex Status
igorsk 0:1063a091a062 361 * @return Status of specified PHY status (0 or 1).
igorsk 0:1063a091a062 362 * (-1) if error.
igorsk 0:1063a091a062 363 *
igorsk 0:1063a091a062 364 * Note:
igorsk 0:1063a091a062 365 * For EMAC_PHY_STAT_LINK, return value:
igorsk 0:1063a091a062 366 * - 0: Link Down
igorsk 0:1063a091a062 367 * - 1: Link Up
igorsk 0:1063a091a062 368 * For EMAC_PHY_STAT_SPEED, return value:
igorsk 0:1063a091a062 369 * - 0: 10Mbps
igorsk 0:1063a091a062 370 * - 1: 100Mbps
igorsk 0:1063a091a062 371 * For EMAC_PHY_STAT_DUP, return value:
igorsk 0:1063a091a062 372 * - 0: Half-Duplex
igorsk 0:1063a091a062 373 * - 1: Full-Duplex
igorsk 0:1063a091a062 374 **********************************************************************/
igorsk 0:1063a091a062 375 int32_t EMAC_CheckPHYStatus(uint32_t ulPHYState)
igorsk 0:1063a091a062 376 {
igorsk 0:1063a091a062 377 int32_t regv, tmp;
igorsk 0:1063a091a062 378
igorsk 0:1063a091a062 379 regv = read_PHY (EMAC_PHY_REG_STS);
igorsk 0:1063a091a062 380 switch(ulPHYState){
igorsk 0:1063a091a062 381 case EMAC_PHY_STAT_LINK:
igorsk 0:1063a091a062 382 tmp = (regv & EMAC_PHY_SR_LINK) ? 1 : 0;
igorsk 0:1063a091a062 383 break;
igorsk 0:1063a091a062 384 case EMAC_PHY_STAT_SPEED:
igorsk 0:1063a091a062 385 tmp = (regv & EMAC_PHY_SR_SPEED) ? 0 : 1;
igorsk 0:1063a091a062 386 break;
igorsk 0:1063a091a062 387 case EMAC_PHY_STAT_DUP:
igorsk 0:1063a091a062 388 tmp = (regv & EMAC_PHY_SR_DUP) ? 1 : 0;
igorsk 0:1063a091a062 389 break;
igorsk 0:1063a091a062 390 default:
igorsk 0:1063a091a062 391 tmp = -1;
igorsk 0:1063a091a062 392 break;
igorsk 0:1063a091a062 393 }
igorsk 0:1063a091a062 394 return (tmp);
igorsk 0:1063a091a062 395 }
igorsk 0:1063a091a062 396
igorsk 0:1063a091a062 397
igorsk 0:1063a091a062 398 /*********************************************************************//**
igorsk 0:1063a091a062 399 * @brief Set specified PHY mode in EMAC peripheral
igorsk 0:1063a091a062 400 * @param[in] ulPHYMode Specified PHY mode, should be:
igorsk 0:1063a091a062 401 * - EMAC_MODE_AUTO
igorsk 0:1063a091a062 402 * - EMAC_MODE_10M_FULL
igorsk 0:1063a091a062 403 * - EMAC_MODE_10M_HALF
igorsk 0:1063a091a062 404 * - EMAC_MODE_100M_FULL
igorsk 0:1063a091a062 405 * - EMAC_MODE_100M_HALF
igorsk 0:1063a091a062 406 * @return Return (0) if no error, otherwise return (-1)
igorsk 0:1063a091a062 407 **********************************************************************/
igorsk 0:1063a091a062 408 int32_t EMAC_SetPHYMode(uint32_t ulPHYMode)
igorsk 0:1063a091a062 409 {
igorsk 0:1063a091a062 410 int32_t id1, id2, tout, regv;
igorsk 0:1063a091a062 411
igorsk 0:1063a091a062 412 /* Check if this is a DP83848C PHY. */
igorsk 0:1063a091a062 413 id1 = read_PHY (EMAC_PHY_REG_IDR1);
igorsk 0:1063a091a062 414 id2 = read_PHY (EMAC_PHY_REG_IDR2);
igorsk 0:1063a091a062 415
igorsk 0:1063a091a062 416 if (((id1 << 16) | (id2 & 0xFFF0)) == EMAC_DP83848C_ID) {
igorsk 0:1063a091a062 417 /* Configure the PHY device */
igorsk 0:1063a091a062 418 switch(ulPHYMode){
igorsk 0:1063a091a062 419 case EMAC_MODE_AUTO:
igorsk 0:1063a091a062 420 /* Use auto-negotiation about the link speed. */
igorsk 0:1063a091a062 421 write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG);
igorsk 0:1063a091a062 422 /* Wait to complete Auto_Negotiation */
igorsk 0:1063a091a062 423 for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
igorsk 0:1063a091a062 424 regv = read_PHY (EMAC_PHY_REG_BMSR);
igorsk 0:1063a091a062 425 if (regv & EMAC_PHY_BMSR_AUTO_DONE) {
igorsk 0:1063a091a062 426 /* Auto-negotiation Complete. */
igorsk 0:1063a091a062 427 break;
igorsk 0:1063a091a062 428 }
igorsk 0:1063a091a062 429 if (tout == 0){
igorsk 0:1063a091a062 430 // Time out, return error
igorsk 0:1063a091a062 431 return (-1);
igorsk 0:1063a091a062 432 }
igorsk 0:1063a091a062 433 }
igorsk 0:1063a091a062 434 break;
igorsk 0:1063a091a062 435 case EMAC_MODE_10M_FULL:
igorsk 0:1063a091a062 436 /* Connect at 10MBit full-duplex */
igorsk 0:1063a091a062 437 write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_10M);
igorsk 0:1063a091a062 438 break;
igorsk 0:1063a091a062 439 case EMAC_MODE_10M_HALF:
igorsk 0:1063a091a062 440 /* Connect at 10MBit half-duplex */
igorsk 0:1063a091a062 441 write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_10M);
igorsk 0:1063a091a062 442 break;
igorsk 0:1063a091a062 443 case EMAC_MODE_100M_FULL:
igorsk 0:1063a091a062 444 /* Connect at 100MBit full-duplex */
igorsk 0:1063a091a062 445 write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_100M);
igorsk 0:1063a091a062 446 break;
igorsk 0:1063a091a062 447 case EMAC_MODE_100M_HALF:
igorsk 0:1063a091a062 448 /* Connect at 100MBit half-duplex */
igorsk 0:1063a091a062 449 write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_100M);
igorsk 0:1063a091a062 450 break;
igorsk 0:1063a091a062 451 default:
igorsk 0:1063a091a062 452 // un-supported
igorsk 0:1063a091a062 453 return (-1);
igorsk 0:1063a091a062 454 }
igorsk 0:1063a091a062 455 }
igorsk 0:1063a091a062 456 // It's not correct module ID
igorsk 0:1063a091a062 457 else {
igorsk 0:1063a091a062 458 return (-1);
igorsk 0:1063a091a062 459 }
igorsk 0:1063a091a062 460
igorsk 0:1063a091a062 461 // Update EMAC configuration with current PHY status
igorsk 0:1063a091a062 462 if (EMAC_UpdatePHYStatus() < 0){
igorsk 0:1063a091a062 463 return (-1);
igorsk 0:1063a091a062 464 }
igorsk 0:1063a091a062 465
igorsk 0:1063a091a062 466 // Complete
igorsk 0:1063a091a062 467 return (0);
igorsk 0:1063a091a062 468 }
igorsk 0:1063a091a062 469
igorsk 0:1063a091a062 470
igorsk 0:1063a091a062 471 /*********************************************************************//**
igorsk 0:1063a091a062 472 * @brief Auto-Configures value for the EMAC configuration register to
igorsk 0:1063a091a062 473 * match with current PHY mode
igorsk 0:1063a091a062 474 * @param[in] None
igorsk 0:1063a091a062 475 * @return Return (0) if no error, otherwise return (-1)
igorsk 0:1063a091a062 476 *
igorsk 0:1063a091a062 477 * Note: The EMAC configuration will be auto-configured:
igorsk 0:1063a091a062 478 * - Speed mode.
igorsk 0:1063a091a062 479 * - Half/Full duplex mode
igorsk 0:1063a091a062 480 **********************************************************************/
igorsk 0:1063a091a062 481 int32_t EMAC_UpdatePHYStatus(void)
igorsk 0:1063a091a062 482 {
igorsk 0:1063a091a062 483 int32_t regv, tout;
igorsk 0:1063a091a062 484
igorsk 0:1063a091a062 485 /* Check the link status. */
igorsk 0:1063a091a062 486 for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
igorsk 0:1063a091a062 487 regv = read_PHY (EMAC_PHY_REG_STS);
igorsk 0:1063a091a062 488 if (regv & EMAC_PHY_SR_LINK) {
igorsk 0:1063a091a062 489 /* Link is on. */
igorsk 0:1063a091a062 490 break;
igorsk 0:1063a091a062 491 }
igorsk 0:1063a091a062 492 if (tout == 0){
igorsk 0:1063a091a062 493 // time out
igorsk 0:1063a091a062 494 return (-1);
igorsk 0:1063a091a062 495 }
igorsk 0:1063a091a062 496 }
igorsk 0:1063a091a062 497
igorsk 0:1063a091a062 498 /* Configure Full/Half Duplex mode. */
igorsk 0:1063a091a062 499 if (regv & EMAC_PHY_SR_DUP) {
igorsk 0:1063a091a062 500 /* Full duplex is enabled. */
igorsk 0:1063a091a062 501 LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP;
igorsk 0:1063a091a062 502 LPC_EMAC->Command |= EMAC_CR_FULL_DUP;
igorsk 0:1063a091a062 503 LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP;
igorsk 0:1063a091a062 504 } else {
igorsk 0:1063a091a062 505 /* Half duplex mode. */
igorsk 0:1063a091a062 506 LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP;
igorsk 0:1063a091a062 507 }
igorsk 0:1063a091a062 508
igorsk 0:1063a091a062 509 /* Configure 100MBit/10MBit mode. */
igorsk 0:1063a091a062 510 if (regv & EMAC_PHY_SR_SPEED) {
igorsk 0:1063a091a062 511 /* 10MBit mode. */
igorsk 0:1063a091a062 512 LPC_EMAC->SUPP = 0;
igorsk 0:1063a091a062 513 } else {
igorsk 0:1063a091a062 514 /* 100MBit mode. */
igorsk 0:1063a091a062 515 LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
igorsk 0:1063a091a062 516 }
igorsk 0:1063a091a062 517
igorsk 0:1063a091a062 518 // Complete
igorsk 0:1063a091a062 519 return (0);
igorsk 0:1063a091a062 520 }
igorsk 0:1063a091a062 521
igorsk 0:1063a091a062 522
igorsk 0:1063a091a062 523 /*********************************************************************//**
igorsk 0:1063a091a062 524 * @brief Enable/Disable hash filter functionality for specified destination
igorsk 0:1063a091a062 525 * MAC address in EMAC module
igorsk 0:1063a091a062 526 * @param[in] dstMAC_addr Pointer to the first MAC destination address, should
igorsk 0:1063a091a062 527 * be 6-bytes length, in order LSB to the MSB
igorsk 0:1063a091a062 528 * @param[in] NewState New State of this command, should be:
igorsk 0:1063a091a062 529 * - ENABLE.
igorsk 0:1063a091a062 530 * - DISABLE.
igorsk 0:1063a091a062 531 * @return None
igorsk 0:1063a091a062 532 *
igorsk 0:1063a091a062 533 * Note:
igorsk 0:1063a091a062 534 * The standard Ethernet cyclic redundancy check (CRC) function is calculated from
igorsk 0:1063a091a062 535 * the 6 byte destination address in the Ethernet frame (this CRC is calculated
igorsk 0:1063a091a062 536 * anyway as part of calculating the CRC of the whole frame), then bits [28:23] out of
igorsk 0:1063a091a062 537 * the 32 bits CRC result are taken to form the hash. The 6 bit hash is used to access
igorsk 0:1063a091a062 538 * the hash table: it is used as an index in the 64 bit HashFilter register that has been
igorsk 0:1063a091a062 539 * programmed with accept values. If the selected accept value is 1, the frame is
igorsk 0:1063a091a062 540 * accepted.
igorsk 0:1063a091a062 541 **********************************************************************/
igorsk 0:1063a091a062 542 void EMAC_SetHashFilter(uint8_t dstMAC_addr[], FunctionalState NewState)
igorsk 0:1063a091a062 543 {
igorsk 0:1063a091a062 544 uint32_t *pReg;
igorsk 0:1063a091a062 545 uint32_t tmp;
igorsk 0:1063a091a062 546 int32_t crc;
igorsk 0:1063a091a062 547
igorsk 0:1063a091a062 548 // Calculate the CRC from the destination MAC address
igorsk 0:1063a091a062 549 crc = EMAC_CRCCalc(dstMAC_addr, 6);
igorsk 0:1063a091a062 550 // Extract the value from CRC to get index value for hash filter table
igorsk 0:1063a091a062 551 crc = (crc >> 23) & 0x3F;
igorsk 0:1063a091a062 552
igorsk 0:1063a091a062 553 pReg = (crc > 31) ? ((uint32_t *)&LPC_EMAC->HashFilterH) \
igorsk 0:1063a091a062 554 : ((uint32_t *)&LPC_EMAC->HashFilterL);
igorsk 0:1063a091a062 555 tmp = (crc > 31) ? (crc - 32) : crc;
igorsk 0:1063a091a062 556 if (NewState == ENABLE) {
igorsk 0:1063a091a062 557 (*pReg) |= (1UL << tmp);
igorsk 0:1063a091a062 558 } else {
igorsk 0:1063a091a062 559 (*pReg) &= ~(1UL << tmp);
igorsk 0:1063a091a062 560 }
igorsk 0:1063a091a062 561 // Enable Rx Filter
igorsk 0:1063a091a062 562 LPC_EMAC->Command &= ~EMAC_CR_PASS_RX_FILT;
igorsk 0:1063a091a062 563 }
igorsk 0:1063a091a062 564
igorsk 0:1063a091a062 565
igorsk 0:1063a091a062 566 /*********************************************************************//**
igorsk 0:1063a091a062 567 * @brief Calculates CRC code for number of bytes in the frame
igorsk 0:1063a091a062 568 * @param[in] frame_no_fcs Pointer to the first byte of the frame
igorsk 0:1063a091a062 569 * @param[in] frame_len length of the frame without the FCS
igorsk 0:1063a091a062 570 * @return the CRC as a 32 bit integer
igorsk 0:1063a091a062 571 **********************************************************************/
igorsk 0:1063a091a062 572 int32_t EMAC_CRCCalc(uint8_t frame_no_fcs[], int32_t frame_len)
igorsk 0:1063a091a062 573 {
igorsk 0:1063a091a062 574 int i; // iterator
igorsk 0:1063a091a062 575 int j; // another iterator
igorsk 0:1063a091a062 576 char byte; // current byte
igorsk 0:1063a091a062 577 int crc; // CRC result
igorsk 0:1063a091a062 578 int q0, q1, q2, q3; // temporary variables
igorsk 0:1063a091a062 579 crc = 0xFFFFFFFF;
igorsk 0:1063a091a062 580 for (i = 0; i < frame_len; i++) {
igorsk 0:1063a091a062 581 byte = *frame_no_fcs++;
igorsk 0:1063a091a062 582 for (j = 0; j < 2; j++) {
igorsk 0:1063a091a062 583 if (((crc >> 28) ^ (byte >> 3)) & 0x00000001) {
igorsk 0:1063a091a062 584 q3 = 0x04C11DB7;
igorsk 0:1063a091a062 585 } else {
igorsk 0:1063a091a062 586 q3 = 0x00000000;
igorsk 0:1063a091a062 587 }
igorsk 0:1063a091a062 588 if (((crc >> 29) ^ (byte >> 2)) & 0x00000001) {
igorsk 0:1063a091a062 589 q2 = 0x09823B6E;
igorsk 0:1063a091a062 590 } else {
igorsk 0:1063a091a062 591 q2 = 0x00000000;
igorsk 0:1063a091a062 592 }
igorsk 0:1063a091a062 593 if (((crc >> 30) ^ (byte >> 1)) & 0x00000001) {
igorsk 0:1063a091a062 594 q1 = 0x130476DC;
igorsk 0:1063a091a062 595 } else {
igorsk 0:1063a091a062 596 q1 = 0x00000000;
igorsk 0:1063a091a062 597 }
igorsk 0:1063a091a062 598 if (((crc >> 31) ^ (byte >> 0)) & 0x00000001) {
igorsk 0:1063a091a062 599 q0 = 0x2608EDB8;
igorsk 0:1063a091a062 600 } else {
igorsk 0:1063a091a062 601 q0 = 0x00000000;
igorsk 0:1063a091a062 602 }
igorsk 0:1063a091a062 603 crc = (crc << 4) ^ q3 ^ q2 ^ q1 ^ q0;
igorsk 0:1063a091a062 604 byte >>= 4;
igorsk 0:1063a091a062 605 }
igorsk 0:1063a091a062 606 }
igorsk 0:1063a091a062 607 return crc;
igorsk 0:1063a091a062 608 }
igorsk 0:1063a091a062 609
igorsk 0:1063a091a062 610 /*********************************************************************//**
igorsk 0:1063a091a062 611 * @brief Enable/Disable Filter mode for each specified type EMAC peripheral
igorsk 0:1063a091a062 612 * @param[in] ulFilterMode Filter mode, should be:
igorsk 0:1063a091a062 613 * - EMAC_RFC_UCAST_EN: all frames of unicast types
igorsk 0:1063a091a062 614 * will be accepted
igorsk 0:1063a091a062 615 * - EMAC_RFC_BCAST_EN: broadcast frame will be
igorsk 0:1063a091a062 616 * accepted
igorsk 0:1063a091a062 617 * - EMAC_RFC_MCAST_EN: all frames of multicast
igorsk 0:1063a091a062 618 * types will be accepted
igorsk 0:1063a091a062 619 * - EMAC_RFC_UCAST_HASH_EN: The imperfect hash
igorsk 0:1063a091a062 620 * filter will be applied to unicast addresses
igorsk 0:1063a091a062 621 * - EMAC_RFC_MCAST_HASH_EN: The imperfect hash
igorsk 0:1063a091a062 622 * filter will be applied to multicast addresses
igorsk 0:1063a091a062 623 * - EMAC_RFC_PERFECT_EN: the destination address
igorsk 0:1063a091a062 624 * will be compared with the 6 byte station address
igorsk 0:1063a091a062 625 * programmed in the station address by the filter
igorsk 0:1063a091a062 626 * - EMAC_RFC_MAGP_WOL_EN: the result of the magic
igorsk 0:1063a091a062 627 * packet filter will generate a WoL interrupt when
igorsk 0:1063a091a062 628 * there is a match
igorsk 0:1063a091a062 629 * - EMAC_RFC_PFILT_WOL_EN: the result of the perfect address
igorsk 0:1063a091a062 630 * matching filter and the imperfect hash filter will
igorsk 0:1063a091a062 631 * generate a WoL interrupt when there is a match
igorsk 0:1063a091a062 632 * @param[in] NewState New State of this command, should be:
igorsk 0:1063a091a062 633 * - ENABLE
igorsk 0:1063a091a062 634 * - DISABLE
igorsk 0:1063a091a062 635 * @return None
igorsk 0:1063a091a062 636 **********************************************************************/
igorsk 0:1063a091a062 637 void EMAC_SetFilterMode(uint32_t ulFilterMode, FunctionalState NewState)
igorsk 0:1063a091a062 638 {
igorsk 0:1063a091a062 639 if (NewState == ENABLE){
igorsk 0:1063a091a062 640 LPC_EMAC->RxFilterCtrl |= ulFilterMode;
igorsk 0:1063a091a062 641 } else {
igorsk 0:1063a091a062 642 LPC_EMAC->RxFilterCtrl &= ~ulFilterMode;
igorsk 0:1063a091a062 643 }
igorsk 0:1063a091a062 644 }
igorsk 0:1063a091a062 645
igorsk 0:1063a091a062 646 /*********************************************************************//**
igorsk 0:1063a091a062 647 * @brief Get status of Wake On LAN Filter for each specified
igorsk 0:1063a091a062 648 * type in EMAC peripheral, clear this status if it is set
igorsk 0:1063a091a062 649 * @param[in] ulWoLMode WoL Filter mode, should be:
igorsk 0:1063a091a062 650 * - EMAC_WOL_UCAST: unicast frames caused WoL
igorsk 0:1063a091a062 651 * - EMAC_WOL_UCAST: broadcast frame caused WoL
igorsk 0:1063a091a062 652 * - EMAC_WOL_MCAST: multicast frame caused WoL
igorsk 0:1063a091a062 653 * - EMAC_WOL_UCAST_HASH: unicast frame that passes the
igorsk 0:1063a091a062 654 * imperfect hash filter caused WoL
igorsk 0:1063a091a062 655 * - EMAC_WOL_MCAST_HASH: multicast frame that passes the
igorsk 0:1063a091a062 656 * imperfect hash filter caused WoL
igorsk 0:1063a091a062 657 * - EMAC_WOL_PERFECT:perfect address matching filter
igorsk 0:1063a091a062 658 * caused WoL
igorsk 0:1063a091a062 659 * - EMAC_WOL_RX_FILTER: the receive filter caused WoL
igorsk 0:1063a091a062 660 * - EMAC_WOL_MAG_PACKET: the magic packet filter caused WoL
igorsk 0:1063a091a062 661 * @return SET/RESET
igorsk 0:1063a091a062 662 **********************************************************************/
igorsk 0:1063a091a062 663 FlagStatus EMAC_GetWoLStatus(uint32_t ulWoLMode)
igorsk 0:1063a091a062 664 {
igorsk 0:1063a091a062 665 if (LPC_EMAC->RxFilterWoLStatus & ulWoLMode) {
igorsk 0:1063a091a062 666 LPC_EMAC->RxFilterWoLClear = ulWoLMode;
igorsk 0:1063a091a062 667 return SET;
igorsk 0:1063a091a062 668 } else {
igorsk 0:1063a091a062 669 return RESET;
igorsk 0:1063a091a062 670 }
igorsk 0:1063a091a062 671 }
igorsk 0:1063a091a062 672
igorsk 0:1063a091a062 673
igorsk 0:1063a091a062 674 /*********************************************************************//**
igorsk 0:1063a091a062 675 * @brief Write data to Tx packet data buffer at current index due to
igorsk 0:1063a091a062 676 * TxProduceIndex
igorsk 0:1063a091a062 677 * @param[in] pDataStruct Pointer to a EMAC_PACKETBUF_Type structure
igorsk 0:1063a091a062 678 * data that contain specified information about
igorsk 0:1063a091a062 679 * Packet data buffer.
igorsk 0:1063a091a062 680 * @return None
igorsk 0:1063a091a062 681 **********************************************************************/
igorsk 0:1063a091a062 682 void EMAC_WritePacketBuffer(EMAC_PACKETBUF_Type *pDataStruct)
igorsk 0:1063a091a062 683 {
igorsk 0:1063a091a062 684 uint32_t idx,len;
igorsk 0:1063a091a062 685 uint32_t *sp,*dp;
igorsk 0:1063a091a062 686
igorsk 0:1063a091a062 687 idx = LPC_EMAC->TxProduceIndex;
igorsk 0:1063a091a062 688 sp = (uint32_t *)pDataStruct->pbDataBuf;
igorsk 0:1063a091a062 689 dp = (uint32_t *)Tx_Desc[idx].Packet;
igorsk 0:1063a091a062 690 /* Copy frame data to EMAC packet buffers. */
igorsk 0:1063a091a062 691 for (len = (pDataStruct->ulDataLen + 3) >> 2; len; len--) {
igorsk 0:1063a091a062 692 *dp++ = *sp++;
igorsk 0:1063a091a062 693 }
igorsk 0:1063a091a062 694 Tx_Desc[idx].Ctrl = (pDataStruct->ulDataLen - 1) | (EMAC_TCTRL_INT | EMAC_TCTRL_LAST);
igorsk 0:1063a091a062 695 }
igorsk 0:1063a091a062 696
igorsk 0:1063a091a062 697 /*********************************************************************//**
igorsk 0:1063a091a062 698 * @brief Read data from Rx packet data buffer at current index due
igorsk 0:1063a091a062 699 * to RxConsumeIndex
igorsk 0:1063a091a062 700 * @param[in] pDataStruct Pointer to a EMAC_PACKETBUF_Type structure
igorsk 0:1063a091a062 701 * data that contain specified information about
igorsk 0:1063a091a062 702 * Packet data buffer.
igorsk 0:1063a091a062 703 * @return None
igorsk 0:1063a091a062 704 **********************************************************************/
igorsk 0:1063a091a062 705 void EMAC_ReadPacketBuffer(EMAC_PACKETBUF_Type *pDataStruct)
igorsk 0:1063a091a062 706 {
igorsk 0:1063a091a062 707 uint32_t idx, len;
igorsk 0:1063a091a062 708 uint32_t *dp, *sp;
igorsk 0:1063a091a062 709
igorsk 0:1063a091a062 710 idx = LPC_EMAC->RxConsumeIndex;
igorsk 0:1063a091a062 711 dp = (uint32_t *)pDataStruct->pbDataBuf;
igorsk 0:1063a091a062 712 sp = (uint32_t *)Rx_Desc[idx].Packet;
igorsk 0:1063a091a062 713
igorsk 0:1063a091a062 714 if (pDataStruct->pbDataBuf != NULL) {
igorsk 0:1063a091a062 715 for (len = (pDataStruct->ulDataLen + 3) >> 2; len; len--) {
igorsk 0:1063a091a062 716 *dp++ = *sp++;
igorsk 0:1063a091a062 717 }
igorsk 0:1063a091a062 718 }
igorsk 0:1063a091a062 719 }
igorsk 0:1063a091a062 720
igorsk 0:1063a091a062 721 /*********************************************************************//**
igorsk 0:1063a091a062 722 * @brief Standard EMAC IRQ Handler. This sub-routine will check
igorsk 0:1063a091a062 723 * these following interrupt and call the call-back function
igorsk 0:1063a091a062 724 * if they're already installed:
igorsk 0:1063a091a062 725 * - Overrun Error interrupt in RX Queue
igorsk 0:1063a091a062 726 * - Receive Error interrupt: AlignmentError, RangeError,
igorsk 0:1063a091a062 727 * LengthError, SymbolError, CRCError or NoDescriptor or Overrun
igorsk 0:1063a091a062 728 * - RX Finished Process Descriptors interrupt (ProduceIndex == ConsumeIndex)
igorsk 0:1063a091a062 729 * - Receive Done interrupt
igorsk 0:1063a091a062 730 * - Transmit Under-run interrupt
igorsk 0:1063a091a062 731 * - Transmit errors interrupt : LateCollision, ExcessiveCollision
igorsk 0:1063a091a062 732 * and ExcessiveDefer, NoDescriptor or Under-run
igorsk 0:1063a091a062 733 * - TX Finished Process Descriptors interrupt (ProduceIndex == ConsumeIndex)
igorsk 0:1063a091a062 734 * - Transmit Done interrupt
igorsk 0:1063a091a062 735 * - Interrupt triggered by software
igorsk 0:1063a091a062 736 * - Interrupt triggered by a Wakeup event detected by the receive filter
igorsk 0:1063a091a062 737 * @param[in] None
igorsk 0:1063a091a062 738 * @return None
igorsk 0:1063a091a062 739 **********************************************************************/
igorsk 0:1063a091a062 740 void EMAC_StandardIRQHandler(void)
igorsk 0:1063a091a062 741 {
igorsk 0:1063a091a062 742 /* EMAC Ethernet Controller Interrupt function. */
igorsk 0:1063a091a062 743 uint32_t n, int_stat;
igorsk 0:1063a091a062 744
igorsk 0:1063a091a062 745 // Get EMAC interrupt status
igorsk 0:1063a091a062 746 while ((int_stat = (LPC_EMAC->IntStatus & LPC_EMAC->IntEnable)) != 0) {
igorsk 0:1063a091a062 747 // Clear interrupt status
igorsk 0:1063a091a062 748 LPC_EMAC->IntClear = int_stat;
igorsk 0:1063a091a062 749 // Execute call-back function
igorsk 0:1063a091a062 750 for (n = 0; n <= 7; n++) {
igorsk 0:1063a091a062 751 if ((int_stat & (1 << n)) && (_pfnIntCbDat[n] != NULL)) {
igorsk 0:1063a091a062 752 _pfnIntCbDat[n]();
igorsk 0:1063a091a062 753 }
igorsk 0:1063a091a062 754 }
igorsk 0:1063a091a062 755 // Soft interrupt
igorsk 0:1063a091a062 756 if ((int_stat & EMAC_INT_SOFT_INT) && (_pfnIntCbDat[8] != NULL)) {
igorsk 0:1063a091a062 757 _pfnIntCbDat[8]();
igorsk 0:1063a091a062 758 }
igorsk 0:1063a091a062 759 // WakeUp interrupt
igorsk 0:1063a091a062 760 if ((int_stat & EMAC_INT_WAKEUP) && (_pfnIntCbDat[9] != NULL)) {
igorsk 0:1063a091a062 761 // Clear WoL interrupt
igorsk 0:1063a091a062 762 LPC_EMAC->RxFilterWoLClear = EMAC_WOL_BITMASK;
igorsk 0:1063a091a062 763 _pfnIntCbDat[9]();
igorsk 0:1063a091a062 764 }
igorsk 0:1063a091a062 765 }
igorsk 0:1063a091a062 766 }
igorsk 0:1063a091a062 767
igorsk 0:1063a091a062 768
igorsk 0:1063a091a062 769 /*********************************************************************//**
igorsk 0:1063a091a062 770 * @brief Setup/register Call-back function for each interrupt type
igorsk 0:1063a091a062 771 * in EMAC module.
igorsk 0:1063a091a062 772 * @param[in] ulIntType Interrupt type, should be one of the following:
igorsk 0:1063a091a062 773 * - EMAC_INT_RX_OVERRUN: Receive Overrun
igorsk 0:1063a091a062 774 * - EMAC_INT_RX_ERR: Receive Error
igorsk 0:1063a091a062 775 * - EMAC_INT_RX_FIN: Receive Descriptor Finish
igorsk 0:1063a091a062 776 * - EMAC_INT_RX_DONE: Receive Done
igorsk 0:1063a091a062 777 * - EMAC_INT_TX_UNDERRUN: Transmit Under-run
igorsk 0:1063a091a062 778 * - EMAC_INT_TX_ERR: Transmit Error
igorsk 0:1063a091a062 779 * - EMAC_INT_TX_FIN: Transmit descriptor finish
igorsk 0:1063a091a062 780 * - EMAC_INT_TX_DONE: Transmit Done
igorsk 0:1063a091a062 781 * - EMAC_INT_SOFT_INT: Software interrupt
igorsk 0:1063a091a062 782 * - EMAC_INT_WAKEUP: Wakeup interrupt
igorsk 0:1063a091a062 783 * @param[in] pfnIntCb Pointer to Call-back function used for this
igorsk 0:1063a091a062 784 * interrupt type
igorsk 0:1063a091a062 785 * @return None
igorsk 0:1063a091a062 786 **********************************************************************/
igorsk 0:1063a091a062 787 void EMAC_SetupIntCBS(uint32_t ulIntType, EMAC_IntCBSType *pfnIntCb)
igorsk 0:1063a091a062 788 {
igorsk 0:1063a091a062 789 /* EMAC Ethernet Controller Interrupt function. */
igorsk 0:1063a091a062 790 uint32_t n;
igorsk 0:1063a091a062 791
igorsk 0:1063a091a062 792 if (ulIntType <= EMAC_INT_TX_DONE){
igorsk 0:1063a091a062 793 for (n = 0; n <= 7; n++) {
igorsk 0:1063a091a062 794 // Found it, install cbs now
igorsk 0:1063a091a062 795 if (ulIntType & (1 << n)) {
igorsk 0:1063a091a062 796 _pfnIntCbDat[n] = pfnIntCb;
igorsk 0:1063a091a062 797 // Don't install cbs any more
igorsk 0:1063a091a062 798 break;
igorsk 0:1063a091a062 799 }
igorsk 0:1063a091a062 800 }
igorsk 0:1063a091a062 801 } else if (ulIntType & EMAC_INT_SOFT_INT) {
igorsk 0:1063a091a062 802 _pfnIntCbDat[8] = pfnIntCb;
igorsk 0:1063a091a062 803 } else if (ulIntType & EMAC_INT_WAKEUP) {
igorsk 0:1063a091a062 804 _pfnIntCbDat[9] = pfnIntCb;
igorsk 0:1063a091a062 805 }
igorsk 0:1063a091a062 806 }
igorsk 0:1063a091a062 807
igorsk 0:1063a091a062 808 /*********************************************************************//**
igorsk 0:1063a091a062 809 * @brief Enable/Disable interrupt for each type in EMAC
igorsk 0:1063a091a062 810 * @param[in] ulIntType Interrupt Type, should be:
igorsk 0:1063a091a062 811 * - EMAC_INT_RX_OVERRUN: Receive Overrun
igorsk 0:1063a091a062 812 * - EMAC_INT_RX_ERR: Receive Error
igorsk 0:1063a091a062 813 * - EMAC_INT_RX_FIN: Receive Descriptor Finish
igorsk 0:1063a091a062 814 * - EMAC_INT_RX_DONE: Receive Done
igorsk 0:1063a091a062 815 * - EMAC_INT_TX_UNDERRUN: Transmit Under-run
igorsk 0:1063a091a062 816 * - EMAC_INT_TX_ERR: Transmit Error
igorsk 0:1063a091a062 817 * - EMAC_INT_TX_FIN: Transmit descriptor finish
igorsk 0:1063a091a062 818 * - EMAC_INT_TX_DONE: Transmit Done
igorsk 0:1063a091a062 819 * - EMAC_INT_SOFT_INT: Software interrupt
igorsk 0:1063a091a062 820 * - EMAC_INT_WAKEUP: Wakeup interrupt
igorsk 0:1063a091a062 821 * @param[in] NewState New State of this function, should be:
igorsk 0:1063a091a062 822 * - ENABLE.
igorsk 0:1063a091a062 823 * - DISABLE.
igorsk 0:1063a091a062 824 * @return None
igorsk 0:1063a091a062 825 **********************************************************************/
igorsk 0:1063a091a062 826 void EMAC_IntCmd(uint32_t ulIntType, FunctionalState NewState)
igorsk 0:1063a091a062 827 {
igorsk 0:1063a091a062 828 if (NewState == ENABLE) {
igorsk 0:1063a091a062 829 LPC_EMAC->IntEnable |= ulIntType;
igorsk 0:1063a091a062 830 } else {
igorsk 0:1063a091a062 831 LPC_EMAC->IntEnable &= ~(ulIntType);
igorsk 0:1063a091a062 832 }
igorsk 0:1063a091a062 833 }
igorsk 0:1063a091a062 834
igorsk 0:1063a091a062 835 /*********************************************************************//**
igorsk 0:1063a091a062 836 * @brief Check whether if specified interrupt flag is set or not
igorsk 0:1063a091a062 837 * for each interrupt type in EMAC and clear interrupt pending
igorsk 0:1063a091a062 838 * if it is set.
igorsk 0:1063a091a062 839 * @param[in] ulIntType Interrupt Type, should be:
igorsk 0:1063a091a062 840 * - EMAC_INT_RX_OVERRUN: Receive Overrun
igorsk 0:1063a091a062 841 * - EMAC_INT_RX_ERR: Receive Error
igorsk 0:1063a091a062 842 * - EMAC_INT_RX_FIN: Receive Descriptor Finish
igorsk 0:1063a091a062 843 * - EMAC_INT_RX_DONE: Receive Done
igorsk 0:1063a091a062 844 * - EMAC_INT_TX_UNDERRUN: Transmit Under-run
igorsk 0:1063a091a062 845 * - EMAC_INT_TX_ERR: Transmit Error
igorsk 0:1063a091a062 846 * - EMAC_INT_TX_FIN: Transmit descriptor finish
igorsk 0:1063a091a062 847 * - EMAC_INT_TX_DONE: Transmit Done
igorsk 0:1063a091a062 848 * - EMAC_INT_SOFT_INT: Software interrupt
igorsk 0:1063a091a062 849 * - EMAC_INT_WAKEUP: Wakeup interrupt
igorsk 0:1063a091a062 850 * @return New state of specified interrupt (SET or RESET)
igorsk 0:1063a091a062 851 **********************************************************************/
igorsk 0:1063a091a062 852 IntStatus EMAC_IntGetStatus(uint32_t ulIntType)
igorsk 0:1063a091a062 853 {
igorsk 0:1063a091a062 854 if (LPC_EMAC->IntStatus & ulIntType) {
igorsk 0:1063a091a062 855 LPC_EMAC->IntClear = ulIntType;
igorsk 0:1063a091a062 856 return SET;
igorsk 0:1063a091a062 857 } else {
igorsk 0:1063a091a062 858 return RESET;
igorsk 0:1063a091a062 859 }
igorsk 0:1063a091a062 860 }
igorsk 0:1063a091a062 861
igorsk 0:1063a091a062 862
igorsk 0:1063a091a062 863 /*********************************************************************//**
igorsk 0:1063a091a062 864 * @brief Check whether if the current RxConsumeIndex is not equal to the
igorsk 0:1063a091a062 865 * current RxProduceIndex.
igorsk 0:1063a091a062 866 * @param[in] None
igorsk 0:1063a091a062 867 * @return TRUE if they're not equal, otherwise return FALSE
igorsk 0:1063a091a062 868 *
igorsk 0:1063a091a062 869 * Note: In case the RxConsumeIndex is not equal to the RxProduceIndex,
igorsk 0:1063a091a062 870 * it means there're available data has been received. They should be read
igorsk 0:1063a091a062 871 * out and released the Receive Data Buffer by updating the RxConsumeIndex value.
igorsk 0:1063a091a062 872 **********************************************************************/
igorsk 0:1063a091a062 873 Bool EMAC_CheckReceiveIndex(void)
igorsk 0:1063a091a062 874 {
igorsk 0:1063a091a062 875 if (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex) {
igorsk 0:1063a091a062 876 return TRUE;
igorsk 0:1063a091a062 877 } else {
igorsk 0:1063a091a062 878 return FALSE;
igorsk 0:1063a091a062 879 }
igorsk 0:1063a091a062 880 }
igorsk 0:1063a091a062 881
igorsk 0:1063a091a062 882
igorsk 0:1063a091a062 883 /*********************************************************************//**
igorsk 0:1063a091a062 884 * @brief Check whether if the current TxProduceIndex is not equal to the
igorsk 0:1063a091a062 885 * current RxProduceIndex - 1.
igorsk 0:1063a091a062 886 * @param[in] None
igorsk 0:1063a091a062 887 * @return TRUE if they're not equal, otherwise return FALSE
igorsk 0:1063a091a062 888 *
igorsk 0:1063a091a062 889 * Note: In case the RxConsumeIndex is equal to the RxProduceIndex - 1,
igorsk 0:1063a091a062 890 * it means the transmit buffer is available and data can be written to transmit
igorsk 0:1063a091a062 891 * buffer to be sent.
igorsk 0:1063a091a062 892 **********************************************************************/
igorsk 0:1063a091a062 893 Bool EMAC_CheckTransmitIndex(void)
igorsk 0:1063a091a062 894 {
igorsk 0:1063a091a062 895 uint32_t tmp = LPC_EMAC->TxConsumeIndex -1;
igorsk 0:1063a091a062 896 if (LPC_EMAC->TxProduceIndex == tmp) {
igorsk 0:1063a091a062 897 return FALSE;
igorsk 0:1063a091a062 898 } else {
igorsk 0:1063a091a062 899 return TRUE;
igorsk 0:1063a091a062 900 }
igorsk 0:1063a091a062 901 }
igorsk 0:1063a091a062 902
igorsk 0:1063a091a062 903
igorsk 0:1063a091a062 904 /*********************************************************************//**
igorsk 0:1063a091a062 905 * @brief Get current status value of receive data (due to RxConsumeIndex)
igorsk 0:1063a091a062 906 * @param[in] ulRxStatType Received Status type, should be one of following:
igorsk 0:1063a091a062 907 * - EMAC_RINFO_CTRL_FRAME: Control Frame
igorsk 0:1063a091a062 908 * - EMAC_RINFO_VLAN: VLAN Frame
igorsk 0:1063a091a062 909 * - EMAC_RINFO_FAIL_FILT: RX Filter Failed
igorsk 0:1063a091a062 910 * - EMAC_RINFO_MCAST: Multicast Frame
igorsk 0:1063a091a062 911 * - EMAC_RINFO_BCAST: Broadcast Frame
igorsk 0:1063a091a062 912 * - EMAC_RINFO_CRC_ERR: CRC Error in Frame
igorsk 0:1063a091a062 913 * - EMAC_RINFO_SYM_ERR: Symbol Error from PHY
igorsk 0:1063a091a062 914 * - EMAC_RINFO_LEN_ERR: Length Error
igorsk 0:1063a091a062 915 * - EMAC_RINFO_RANGE_ERR: Range error(exceeded max size)
igorsk 0:1063a091a062 916 * - EMAC_RINFO_ALIGN_ERR: Alignment error
igorsk 0:1063a091a062 917 * - EMAC_RINFO_OVERRUN: Receive overrun
igorsk 0:1063a091a062 918 * - EMAC_RINFO_NO_DESCR: No new Descriptor available
igorsk 0:1063a091a062 919 * - EMAC_RINFO_LAST_FLAG: last Fragment in Frame
igorsk 0:1063a091a062 920 * - EMAC_RINFO_ERR: Error Occurred (OR of all error)
igorsk 0:1063a091a062 921 * @return Current value of receive data (due to RxConsumeIndex)
igorsk 0:1063a091a062 922 **********************************************************************/
igorsk 0:1063a091a062 923 FlagStatus EMAC_CheckReceiveDataStatus(uint32_t ulRxStatType)
igorsk 0:1063a091a062 924 {
igorsk 0:1063a091a062 925 uint32_t idx;
igorsk 0:1063a091a062 926 idx = LPC_EMAC->RxConsumeIndex;
igorsk 0:1063a091a062 927 return (((Rx_Stat[idx].Info) & ulRxStatType) ? SET : RESET);
igorsk 0:1063a091a062 928 }
igorsk 0:1063a091a062 929
igorsk 0:1063a091a062 930
igorsk 0:1063a091a062 931 /*********************************************************************//**
igorsk 0:1063a091a062 932 * @brief Get size of current Received data in received buffer (due to
igorsk 0:1063a091a062 933 * RxConsumeIndex)
igorsk 0:1063a091a062 934 * @param[in] None
igorsk 0:1063a091a062 935 * @return Size of received data
igorsk 0:1063a091a062 936 **********************************************************************/
igorsk 0:1063a091a062 937 uint32_t EMAC_GetReceiveDataSize(void)
igorsk 0:1063a091a062 938 {
igorsk 0:1063a091a062 939 uint32_t idx;
igorsk 0:1063a091a062 940 idx =LPC_EMAC->RxConsumeIndex;
igorsk 0:1063a091a062 941 return ((Rx_Stat[idx].Info) & EMAC_RINFO_SIZE);
igorsk 0:1063a091a062 942 }
igorsk 0:1063a091a062 943
igorsk 0:1063a091a062 944 /*********************************************************************//**
igorsk 0:1063a091a062 945 * @brief Increase the RxConsumeIndex (after reading the Receive buffer
igorsk 0:1063a091a062 946 * to release the Receive buffer) and wrap-around the index if
igorsk 0:1063a091a062 947 * it reaches the maximum Receive Number
igorsk 0:1063a091a062 948 * @param[in] None
igorsk 0:1063a091a062 949 * @return None
igorsk 0:1063a091a062 950 **********************************************************************/
igorsk 0:1063a091a062 951 void EMAC_UpdateRxConsumeIndex(void)
igorsk 0:1063a091a062 952 {
igorsk 0:1063a091a062 953 // Get current Rx consume index
igorsk 0:1063a091a062 954 uint32_t idx = LPC_EMAC->RxConsumeIndex;
igorsk 0:1063a091a062 955
igorsk 0:1063a091a062 956 /* Release frame from EMAC buffer */
igorsk 0:1063a091a062 957 if (++idx == EMAC_NUM_RX_FRAG) idx = 0;
igorsk 0:1063a091a062 958 LPC_EMAC->RxConsumeIndex = idx;
igorsk 0:1063a091a062 959 }
igorsk 0:1063a091a062 960
igorsk 0:1063a091a062 961 /*********************************************************************//**
igorsk 0:1063a091a062 962 * @brief Increase the TxProduceIndex (after writting to the Transmit buffer
igorsk 0:1063a091a062 963 * to enable the Transmit buffer) and wrap-around the index if
igorsk 0:1063a091a062 964 * it reaches the maximum Transmit Number
igorsk 0:1063a091a062 965 * @param[in] None
igorsk 0:1063a091a062 966 * @return None
igorsk 0:1063a091a062 967 **********************************************************************/
igorsk 0:1063a091a062 968 void EMAC_UpdateTxProduceIndex(void)
igorsk 0:1063a091a062 969 {
igorsk 0:1063a091a062 970 // Get current Tx produce index
igorsk 0:1063a091a062 971 uint32_t idx = LPC_EMAC->TxProduceIndex;
igorsk 0:1063a091a062 972
igorsk 0:1063a091a062 973 /* Start frame transmission */
igorsk 0:1063a091a062 974 if (++idx == EMAC_NUM_TX_FRAG) idx = 0;
igorsk 0:1063a091a062 975 LPC_EMAC->TxProduceIndex = idx;
igorsk 0:1063a091a062 976 }
igorsk 0:1063a091a062 977
igorsk 0:1063a091a062 978
igorsk 0:1063a091a062 979 /**
igorsk 0:1063a091a062 980 * @}
igorsk 0:1063a091a062 981 */
igorsk 0:1063a091a062 982
igorsk 0:1063a091a062 983 #endif /* _EMAC */
igorsk 0:1063a091a062 984
igorsk 0:1063a091a062 985 /**
igorsk 0:1063a091a062 986 * @}
igorsk 0:1063a091a062 987 */
igorsk 0:1063a091a062 988
igorsk 0:1063a091a062 989 /* --------------------------------- End Of File ------------------------------ */