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
source/lpc17xx_emac.c@0:1063a091a062, 2010-02-17 (annotated)
- Committer:
- igorsk
- Date:
- Wed Feb 17 16:22:39 2010 +0000
- Revision:
- 0:1063a091a062
Who changed what in which revision?
User | Revision | Line number | New 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 ------------------------------ */ |