12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043 |
- /**********************************************************************
- * $Id$ lpc_emac.c 2011-06-02
- *//**
- * @file lpc_emac.c
- * @brief Contains all functions support for Ethernet MAC firmware
- * library on LPC
- * @version 1.0
- * @date 02. June. 2011
- * @author NXP MCU SW Application Team
- *
- * Copyright(C) 2011, NXP Semiconductor
- * All rights reserved.
- *
- ***********************************************************************
- * Software that is described herein is for illustrative purposes only
- * which provides customers with programming information regarding the
- * products. This software is supplied "AS IS" without any warranties.
- * NXP Semiconductors assumes no responsibility or liability for the
- * use of the software, conveys no license or title under any patent,
- * copyright, or mask work right to the product. NXP Semiconductors
- * reserves the right to make changes in the software without
- * notification. NXP Semiconductors also make no representation or
- * warranty that such application will be suitable for the specified
- * use without further testing or modification.
- * Permission to use, copy, modify, and distribute this software and its
- * documentation is hereby granted, under NXP Semiconductors'
- * relevant copyright in the software, without fee, provided that it
- * is used in conjunction with NXP Semiconductors microcontrollers. This
- * copyright, permission, and disclaimer notice must appear in all copies of
- * this code.
- **********************************************************************/
- #ifdef __BUILD_WITH_EXAMPLE__
- #include "lpc_libcfg.h"
- #else
- #include "lpc_libcfg_default.h"
- #endif /* __BUILD_WITH_EXAMPLE__ */
- #ifdef _EMAC
- #include "lpc_emac.h"
- #include "lpc_clkpwr.h"
- #include "lpc_pinsel.h"
- /* Peripheral group ----------------------------------------------------------- */
- /** @addtogroup EMAC
- * @{
- */
-
- /************************** PRIVATE VARIABLES *************************/
- /* MII Mgmt Configuration register - Clock divider setting */
- const uint8_t EMAC_clkdiv[] = { 4, 6, 8, 10, 14, 20, 28, 36, 40, 44, 48, 52, 56, 60, 64 };
- /* EMAC Config data */
- static EMAC_CFG_Type EMAC_Configs;
- /* EMAC local DMA Descriptors */
- #ifdef __IAR_SYSTEMS_ICC__
- /* Global Tx Buffer data */
- #pragma data_alignment=4
- static uint16_t saFrameBuffers[EMAC_MAX_FRAME_NUM][EMAC_MAX_FRAME_SIZE];
- #else
- /* Global Rx Buffer data */
- static uint16_t __attribute__ ((aligned (4))) saFrameBuffers[EMAC_MAX_FRAME_NUM][EMAC_MAX_FRAME_SIZE];
- #endif
- static uint32_t sulCurrFrameSz = 0;
- static uint8_t sbCurrFrameID = 0;
- /***************************** PRIVATE FUNCTION *****************************/
- static void EMAC_UpdateRxConsumeIndex(void);
- static void EMAC_UpdateTxProduceIndex(void);
- static uint32_t EMAC_AllocTxBuff(uint16_t nFrameSize, uint8_t bLastFrame);
- static uint32_t EMAC_GetRxFrameSize(void);
- /*********************************************************************//**
- * @brief
- * @param[in]
- * @return
- **********************************************************************/
- void rx_descr_init (void)
- {
- unsigned int i;
- for (i = 0; i < EMAC_NUM_RX_FRAG; i++)
- {
- RX_DESC_PACKET(i) = RX_BUF(i);
- RX_DESC_CTRL(i) = EMAC_RCTRL_INT | (EMAC_ETH_MAX_FLEN-1);
- RX_STAT_INFO(i) = 0;
- RX_STAT_HASHCRC(i) = 0;
- }
- /* Set EMAC Receive Descriptor Registers. */
- LPC_EMAC->RxDescriptor = RX_DESC_BASE;
- LPC_EMAC->RxStatus = RX_STAT_BASE;
- LPC_EMAC->RxDescriptorNumber = EMAC_NUM_RX_FRAG-1;
- /* Rx Descriptors Point to 0 */
- LPC_EMAC->RxConsumeIndex = 0;
- }
- /*********************************************************************//**
- * @brief
- * @param[in]
- * @return
- **********************************************************************/
- void tx_descr_init (void)
- {
- unsigned int i;
- for (i = 0; i < EMAC_NUM_TX_FRAG; i++)
- {
- TX_DESC_PACKET(i) = TX_BUF(i);
- TX_DESC_CTRL(i) = 0;
- TX_STAT_INFO(i) = 0;
- }
- /* Set EMAC Transmit Descriptor Registers. */
- LPC_EMAC->TxDescriptor = TX_DESC_BASE;
- LPC_EMAC->TxStatus = TX_STAT_BASE;
- LPC_EMAC->TxDescriptorNumber = EMAC_NUM_TX_FRAG-1;
- /* Tx Descriptors Point to 0 */
- LPC_EMAC->TxProduceIndex = 0;
- }
- /*********************************************************************//**
- * @brief Set Station MAC address for EMAC module
- * @param[in] abStationAddr Pointer to Station address that contains 6-bytes
- * of MAC address.
- * @return None
- **********************************************************************/
- void setEmacAddr(uint8_t abStationAddr[])
- {
- /* Set the Ethernet MAC Address registers */
- LPC_EMAC->SA0 = ((uint32_t)abStationAddr[5] << 8) | (uint32_t)abStationAddr[4];
- LPC_EMAC->SA1 = ((uint32_t)abStationAddr[3] << 8) | (uint32_t)abStationAddr[2];
- LPC_EMAC->SA2 = ((uint32_t)abStationAddr[1] << 8) | (uint32_t)abStationAddr[0];
- }
- /************************** GLOBAL/PUBLIC FUNCTIONS *************************/
- /** @defgroup EMAC_Public_Functions
- * @{
- */
- /*********************************************************************//**
- * @brief Write data to PHY
- * @param[in] PhyReg PHY register address
- * @param[in] Value Register Value
- * @return None
- **********************************************************************/
- void EMAC_Write_PHY (uint8_t PhyReg, uint16_t Value)
- {
- unsigned int tout;
- LPC_EMAC->MADR = ((EMAC_Configs.bPhyAddr & 0x1F) << 8 )| (PhyReg & 0x1F);
- LPC_EMAC->MWTD = Value;
- /* Wait utill operation completed */
- tout = 0;
- for (tout = 0; tout < EMAC_MII_WR_TOUT; tout++)
- {
- if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0)
- {
- break;
- }
- }
- }
- /*********************************************************************//**
- * @brief Read data from PHY register
- * @param[in] PhyReg PHY register address
- * @return Register value
- **********************************************************************/
- uint16_t EMAC_Read_PHY (uint8_t PhyReg)
- {
- unsigned int tout;
- LPC_EMAC->MADR = ((EMAC_Configs.bPhyAddr & 0x1F) << 8 )| (PhyReg & 0x1F);
- LPC_EMAC->MCMD = EMAC_MCMD_READ;
- /* Wait until operation completed */
- tout = 0;
- for (tout = 0; tout < EMAC_MII_RD_TOUT; tout++)
- {
- if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0)
- {
- break;
- }
- }
- LPC_EMAC->MCMD = 0;
- return (LPC_EMAC->MRDD);
- }
- /*********************************************************************//**
- * @brief Set Full/Half Duplex Mode
- * @param[in] full_duplex 0: Half-duplex, 1: Full-duplex
- * @return None
- **********************************************************************/
- void EMAC_SetFullDuplexMode(uint8_t full_duplex)
- {
- if(full_duplex)
- {
- LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP;
- LPC_EMAC->Command |= EMAC_CR_FULL_DUP;
- LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP;
- }
- else
- {
- LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP;
- }
- }
- /*********************************************************************//**
- * @brief Set PHY Speed
- * @param[in] mode_100Mbps 0: 10Mbps, 1: 100Mbps
- * @return None
- **********************************************************************/
- void EMAC_SetPHYSpeed(uint8_t mode_100Mbps)
- {
- if(mode_100Mbps)
- {
- LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
- }
- else
- {
- LPC_EMAC->SUPP = 0;
- }
- }
- /*********************************************************************//**
- * @brief Initializes the EMAC peripheral according to the specified
- * parameters in the EMAC_ConfigStruct.
- * @param[in] EMAC_ConfigStruct Pointer to a EMAC_CFG_Type structure
- * that contains the configuration information for the
- * specified EMAC peripheral.
- * @return None
- *
- * Note: This function will initialize EMAC module according to procedure below:
- * - Remove the soft reset condition from the MAC
- * - Configure the PHY via the MIIM interface of the MAC
- * - Select RMII mode
- * - Configure the transmit and receive DMA engines, including the descriptor arrays
- * - Configure the host registers (MAC1,MAC2 etc.) in the MAC
- * - Enable the receive and transmit data paths
- * In default state after initializing, Rx Done and Tx Done interrupt are enabled,
- * nad all interrupts are also enabled
- * (Ref. from LPC17xx UM)
- **********************************************************************/
- int32_t EMAC_Init(EMAC_CFG_Type *EMAC_ConfigStruct)
- {
- /* Initialize the EMAC Ethernet controller. */
- volatile int32_t tout, tmp;
- EMAC_Configs = *EMAC_ConfigStruct;
- /* Set up power for Ethernet module */
- CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, ENABLE);
- /* Enable P1 Ethernet Pins. */
- /* Reset all EMAC internal modules */
- LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | EMAC_MAC1_RES_RX |
- EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | EMAC_MAC1_SOFT_RES;
- LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES | EMAC_CR_PASS_RUNT_FRM;
- /* A short delay after reset. */
- for (tout = 100; tout; tout--);
- /* Initialize MAC control registers. */
- LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL;
- LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN;
- LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN;
- /*
- * Find the clock that close to desired target clock
- */
- tmp = CLKPWR_GetCLK(CLKPWR_CLKTYPE_CPU)/ EMAC_MCFG_MII_MAXCLK;
- for (tout = 0; tout < sizeof (EMAC_clkdiv); tout++)
- {
- if (EMAC_clkdiv[tout] >= tmp)
- break;
- }
- if(tout >= sizeof (EMAC_clkdiv))
- return ERROR;
- tout++;
- // Set Frame size
- LPC_EMAC->MAXF = EMAC_ConfigStruct->nMaxFrameSize;
- // Write to MAC configuration register and reset
- LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(tout) | EMAC_MCFG_RES_MII;
- // release reset
- LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII);
- LPC_EMAC->CLRT = EMAC_CLRT_DEF;
- LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF;
- /* Enable Reduced MII interface. */
- LPC_EMAC->Command = EMAC_CR_RMII | EMAC_CR_PASS_RUNT_FRM;
- // Initilialize PHY
- if(EMAC_ConfigStruct->pfnPHYInit != NULL)
- {
- if(EMAC_ConfigStruct->pfnPHYInit(&EMAC_ConfigStruct->PhyCfg) != SUCCESS)
- {
- return ERROR;
- }
- }
- // Set EMAC address
- setEmacAddr(EMAC_ConfigStruct->pbEMAC_Addr);
- /* Initialize Tx and Rx DMA Descriptors */
- rx_descr_init ();
- tx_descr_init ();
- // Set Receive Filter register: enable broadcast and multicast
- LPC_EMAC->RxFilterCtrl = EMAC_RFC_MCAST_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN;
- /* Enable Rx Done and Tx Done interrupt for EMAC */
- EMAC_IntCmd((EMAC_INT_RX_OVERRUN | EMAC_INT_RX_ERR | EMAC_INT_RX_FIN \
- | EMAC_INT_RX_DONE | EMAC_INT_TX_UNDERRUN | EMAC_INT_TX_ERR \
- | EMAC_INT_TX_FIN | EMAC_INT_TX_DONE), ENABLE);
- /* Reset all interrupts */
- LPC_EMAC->IntClear = 0xFFFF;
- /* Enable receive and transmit mode of MAC Ethernet core */
- EMAC_TxEnable();
- EMAC_RxEnable();
- NVIC_EnableIRQ(ENET_IRQn);
- return SUCCESS;
- }
- /*********************************************************************//**
- * @brief De-initializes the EMAC peripheral registers to their
- * default reset values.
- * @param[in] None
- * @return None
- **********************************************************************/
- void EMAC_DeInit(void)
- {
- // Disable all interrupt
- LPC_EMAC->IntEnable = 0x00;
- // Clear all pending interrupt
- LPC_EMAC->IntClear = (0xFF) | (EMAC_INT_SOFT_INT | EMAC_INT_WAKEUP);
- LPC_EMAC->Command = 0;
- /* TurnOff power for Ethernet module */
- CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, DISABLE);
- }
- /*********************************************************************//**
- * @brief EMAC TX API modules
- * @param[in] None
- * @return None
- **********************************************************************/
- void EMAC_TxEnable( void )
- {
- LPC_EMAC->Command |= EMAC_CR_TX_EN;
- return;
- }
- /*********************************************************************//**
- * @brief EMAC RX API modules
- * @param[in] None
- * @return None
- **********************************************************************/
- void EMAC_TxDisable( void )
- {
- LPC_EMAC->Command &= ~EMAC_CR_TX_EN;
- return;
- }
- /*********************************************************************//**
- * @brief EMAC RX API modules
- * @param[in] None
- * @return None
- **********************************************************************/
- void EMAC_RxEnable( void )
- {
- LPC_EMAC->Command |= EMAC_CR_RX_EN;
- LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
- return;
- }
- /*********************************************************************//**
- * @brief EMAC RX API modules
- * @param[in] None
- * @return None
- **********************************************************************/
- void EMAC_RxDisable( void )
- {
- LPC_EMAC->Command &= ~EMAC_CR_RX_EN;
- LPC_EMAC->MAC1 &= ~EMAC_MAC1_REC_EN;
- return;
- }
- /*********************************************************************//**
- * @brief Get the status of given buffer.
- * @param[in] idx Buffer index
- * @return EMAC_BUFF_AVAILABLE/EMAC_BUFF_FULL/EMAC_BUFF_PARTIAL_FULL
- *
- **********************************************************************/
- EMAC_BUFF_STATUS EMAC_GetBufferSts(EMAC_BUFF_IDX idx)
- {
- uint32_t consume_idx, produce_idx;
- uint32_t max_frag_num;
- // Get the consume index, produce index and the buffer size
- if(idx == EMAC_TX_BUFF)
- {
- consume_idx = LPC_EMAC->TxConsumeIndex;
- produce_idx = LPC_EMAC->TxProduceIndex;
- max_frag_num = LPC_EMAC->TxDescriptorNumber + 1;
- }
- else
- {
- consume_idx = LPC_EMAC->RxConsumeIndex;
- produce_idx = LPC_EMAC->RxProduceIndex;
- max_frag_num = LPC_EMAC->RxDescriptorNumber + 1;
- }
- // empty
- if(consume_idx == produce_idx)
- return EMAC_BUFF_EMPTY;
- // Full
- if(consume_idx == 0 &&
- produce_idx == max_frag_num - 1)
- return EMAC_BUFF_FULL;
-
- // Wrap-around
- if(consume_idx == produce_idx + 1)
- return EMAC_BUFF_FULL;
- return EMAC_BUFF_PARTIAL_FULL;
- }
- /*********************************************************************//**
- * @brief Allocate a descriptor for sending frame and get the coressponding buffer address
- * @param[in] FrameSize The size of frame you want to send
- * @return Address of the TX_DESC_PACKET buffer
- **********************************************************************/
- uint32_t EMAC_AllocTxBuff(uint16_t nFrameSize, uint8_t bLastFrame)
- {
- uint32_t idx;
- uint32_t dp;
- volatile uint32_t i;
- idx = LPC_EMAC->TxProduceIndex;
- while(EMAC_GetBufferSts(EMAC_TX_BUFF) == EMAC_BUFF_FULL)
- {
- for(i = 0; i < 1000000; i++) ;
- }
- dp = TX_DESC_PACKET(idx);
- if(bLastFrame)
- TX_DESC_CTRL(idx) = ((nFrameSize-1) & EMAC_TCTRL_SIZE) | (EMAC_TCTRL_INT | EMAC_TCTRL_LAST);
- else
- TX_DESC_CTRL(idx) = ((nFrameSize-1) & EMAC_TCTRL_SIZE) | (EMAC_TCTRL_INT);
- return dp;
- }
- /*********************************************************************//**
- * @brief Increase the TxProduceIndex (after writting to the Transmit buffer
- * to enable the Transmit buffer) and wrap-around the index if
- * it reaches the maximum Transmit Number
- * @param[in] None
- * @return None
- **********************************************************************/
- void EMAC_UpdateTxProduceIndex(void)
- {
- // Get current Tx produce index
- uint32_t idx = LPC_EMAC->TxProduceIndex;
- /* Start frame transmission */
- if (++idx == LPC_EMAC->TxDescriptorNumber + 1) idx = 0;
- LPC_EMAC->TxProduceIndex = idx;
- }
- /*********************************************************************//**
- * @brief Get current status value of receive data (due to TxProduceIndex)
- * @param[in] None
- * @return Current value of receive data (due to TxProduceIndex)
- **********************************************************************/
- uint32_t EMAC_GetTxFrameStatus(void)
- {
- uint32_t idx;
- idx = LPC_EMAC->TxProduceIndex;
- return (TX_STAT_INFO(idx));
- }
- /*********************************************************************//**
- * @brief Write data to Tx packet data buffer at current index due to
- * TxProduceIndex
- * @param[in] pDataStruct store the address and the size of buffer that saves data.
- * @return None
- **********************************************************************/
- void EMAC_WritePacketBuffer(EMAC_PACKETBUF_Type *pDataStruct)
- {
- uint16_t* pDest;
- uint16_t* pSource = (uint16_t*)pDataStruct->pbDataBuf;
- uint32_t size = pDataStruct->ulDataLen;
- int32_t frame_num;
- uint32_t tmp;
- uint32_t max_frame_size = LPC_EMAC->MAXF;
-
- size = (size + 1) & 0xFFFE; // round Size up to next even number
- frame_num = size/max_frame_size;
- if(size == 0)
- return;
- while(frame_num >= 0)
- {
- tmp = (frame_num > 0)? max_frame_size:size;
- if(tmp == 0)
- break;
-
- // Setup descriptors and data
- if(frame_num == 0)
- pDest = (uint16_t*)EMAC_AllocTxBuff(tmp, 1); // last frame
- else
- pDest = (uint16_t*)EMAC_AllocTxBuff(tmp, 0);
-
- // Copy data
- while (tmp > 0)
- {
- *pDest++ = *pSource++;
- tmp -= 2;
- }
- frame_num--;
- size -= tmp;
- // Update produce index
- EMAC_UpdateTxProduceIndex();
- }
- }
- /*********************************************************************//**
- * @brief Get current status value of receive data (due to RxConsumeIndex)
- * @param[in] None
- * @return Current value of receive data (due to RxConsumeIndex)
- **********************************************************************/
- uint32_t EMAC_GetRxFrameStatus(void)
- {
- uint32_t idx;
- idx = LPC_EMAC->RxConsumeIndex;
- return (RX_STAT_INFO(idx));
- }
- /*********************************************************************//**
- * @brief Get size of current Received data in received buffer (due to
- * RxConsumeIndex)
- * @param[in] None
- * @return Size of received data
- **********************************************************************/
- uint32_t EMAC_GetRxFrameSize(void)
- {
- uint32_t idx;
- idx = LPC_EMAC->RxConsumeIndex;
- return (((RX_STAT_INFO(idx)) & EMAC_RINFO_SIZE)+1);
- }
- /*********************************************************************//**
- * @brief Get the address of TX_DESC_PACKET buffer so that user can access from application
- * @param[in] None
- * @return Address of the TX_DESC_PACKET buffer
- **********************************************************************/
- uint32_t EMAC_GetRxBuffer(void)
- {
- uint32_t idx;
- idx = LPC_EMAC->RxConsumeIndex;
- return RX_DESC_PACKET(idx);
- }
- /*********************************************************************//**
- * @brief Increase the RxConsumeIndex (after reading the Receive buffer
- * to release the Receive buffer) and wrap-around the index if
- * it reaches the maximum Receive Number
- * @param[in] None
- * @return None
- **********************************************************************/
- void EMAC_UpdateRxConsumeIndex(void)
- {
- // Get current Rx consume index
- uint32_t idx = LPC_EMAC->RxConsumeIndex;
- /* Release frame from EMAC buffer */
- if (++idx == EMAC_NUM_RX_FRAG) idx = 0;
- LPC_EMAC->RxConsumeIndex = idx;
- }
- /*********************************************************************//**
- * @brief Standard EMAC IRQ Handler. This sub-routine will check
- * these following interrupt and call the call-back function
- * if they're already installed:
- * - Overrun Error interrupt in RX Queue
- * - Receive Error interrupt: AlignmentError, RangeError,
- * LengthError, SymbolError, CRCError or NoDescriptor or Overrun
- * - RX Finished Process Descriptors interrupt (ProduceIndex == ConsumeIndex)
- * - Receive Done interrupt: Read received frame to the internal buffer
- * - Transmit Under-run interrupt
- * - Transmit errors interrupt : LateCollision, ExcessiveCollision
- * and ExcessiveDefer, NoDescriptor or Under-run
- * - TX Finished Process Descriptors interrupt (ProduceIndex == ConsumeIndex)
- * - Transmit Done interrupt
- * - Interrupt triggered by software
- * - Interrupt triggered by a Wakeup event detected by the receive filter
- * @param[in] None
- * @return None
- **********************************************************************/
- void ENET_IRQHandler(void)
- {
- /* EMAC Ethernet Controller Interrupt function. */
- uint32_t int_stat;
- int32_t RxLen;
-
- // Get EMAC interrupt status
- while ((int_stat = (LPC_EMAC->IntStatus & LPC_EMAC->IntEnable)) != 0)
- {
- // Clear interrupt status
- LPC_EMAC->IntClear = int_stat;
-
- if(int_stat & (EMAC_INT_RX_OVERRUN |EMAC_INT_RX_ERR ))
- {
- uint32_t ulFrameSts = EMAC_GetRxFrameStatus();
- uint32_t ulErrCode = 0;
- ulErrCode |= (ulFrameSts & EMAC_RINFO_CRC_ERR) ? EMAC_CRC_ERR:0;
- ulErrCode |= (ulFrameSts & EMAC_RINFO_SYM_ERR) ? EMAC_SYMBOL_ERR:0;
- ulErrCode |= (ulFrameSts & EMAC_RINFO_LEN_ERR) ? EMAC_LENGTH_ERR:0;
- ulErrCode |= (ulFrameSts & EMAC_RINFO_ALIGN_ERR) ? EMAC_ALIGN_ERR:0;
- ulErrCode |= (ulFrameSts & EMAC_RINFO_OVERRUN) ? EMAC_OVERRUN_ERR:0;
- ulErrCode |= (ulFrameSts & EMAC_RINFO_NO_DESCR) ? EMAC_RX_NO_DESC_ERR:0;
- ulErrCode |= (ulFrameSts & EMAC_RINFO_FAIL_FILT) ? EMAC_FILTER_FAILED_ERR:0;
-
- if(ulErrCode == 0)
- {
- /* Note:
- * The EMAC doesn't distinguish the frame type and frame length,
- * so, e.g. when the IP(0x8000) or ARP(0x0806) packets are received,
- * it compares the frame type with the max length and gives the
- * "Range" error. In fact, this bit is not an error indication,
- * but simply a statement by the chip regarding the status of
- * the received frame
- */
- int_stat &= ~EMAC_INT_RX_ERR;
- }
- else
- {
- if(EMAC_Configs.pfnErrorReceive != NULL)
- EMAC_Configs.pfnErrorReceive(ulErrCode);
- }
- }
- if(int_stat & (EMAC_INT_TX_UNDERRUN|EMAC_INT_TX_ERR ))
- {
- uint32_t ulFrameSts = EMAC_GetTxFrameStatus();
- uint32_t ulErrCode = 0;
- ulErrCode |= (ulFrameSts & EMAC_TINFO_EXCESS_DEF) ? EMAC_EXCESSIVE_DEFER_ERR:0;
- ulErrCode |= (ulFrameSts & EMAC_TINFO_EXCESS_COL) ? EMAC_EXCESSIVE_COLLISION_ERR:0;
- ulErrCode |= (ulFrameSts & EMAC_TINFO_LATE_COL) ? EMAC_LATE_COLLISION_ERR:0;
- ulErrCode |= (ulFrameSts & EMAC_TINFO_UNDERRUN) ? EMAC_UNDERRUN_ERR:0;
- ulErrCode |= (ulFrameSts & EMAC_TINFO_NO_DESCR) ? EMAC_TX_NO_DESC_ERR:0;
- if(EMAC_Configs.pfnErrorReceive != NULL)
- EMAC_Configs.pfnErrorReceive(ulErrCode);
- }
-
- if(int_stat & EMAC_INT_RX_DONE)
- {
- /* Packet received. */
- if(EMAC_GetBufferSts(EMAC_RX_BUFF) != EMAC_BUFF_EMPTY)
- {
- // Get data size
- RxLen = EMAC_GetRxFrameSize();
- if(RxLen > 0)
- {
- // trip out 4-bytes CRC field, note that length in (-1) style format
- RxLen -= 3;
-
- if((EMAC_GetRxFrameStatus() & EMAC_RINFO_ERR_MASK )== 0)
- {
- uint16_t *pDest = (uint16_t*) &saFrameBuffers[sbCurrFrameID][sulCurrFrameSz];
- uint16_t *pSource = (uint16_t*)EMAC_GetRxBuffer();
- sulCurrFrameSz += RxLen;
-
- if(sulCurrFrameSz >= EMAC_MAX_FRAME_SIZE)
- {
- sulCurrFrameSz = 0;
- if(EMAC_Configs.pfnErrorReceive != NULL)
- EMAC_Configs.pfnErrorReceive(EMAC_LENGTH_ERR);
- }
- else
- {
- // Copy data
- while (RxLen > 0)
- {
- *pDest++ = *pSource++;
- RxLen -= 2;
- }
- if(EMAC_GetRxFrameStatus() & EMAC_RINFO_LAST_FLAG)
- {
-
- if(EMAC_Configs.pfnFrameReceive != NULL)
- {
- EMAC_Configs.pfnFrameReceive((uint16_t*)saFrameBuffers[sbCurrFrameID], sulCurrFrameSz);
- }
- sulCurrFrameSz = 0;
- sbCurrFrameID ++;
- if(sbCurrFrameID >= EMAC_MAX_FRAME_NUM)
- sbCurrFrameID = 0;
- }
- /* Release frame from EMAC buffer */
- EMAC_UpdateRxConsumeIndex();
- }
- }
- }
- }
-
- }
-
- if(int_stat & EMAC_INT_TX_FIN && (EMAC_Configs.pfnTransmitFinish != NULL))
- {
- EMAC_Configs.pfnTransmitFinish();
- }
- if(int_stat & EMAC_INT_SOFT_INT && (EMAC_Configs.pfnSoftInt!= NULL))
- {
- EMAC_Configs.pfnSoftInt();
- }
- if(int_stat & EMAC_INT_WAKEUP && (EMAC_Configs.pfnWakeup!= NULL))
- {
- EMAC_Configs.pfnWakeup();
- }
-
- }
- }
- /*********************************************************************//**
- * @brief Enable/Disable hash filter functionality for specified destination
- * MAC address in EMAC module
- * @param[in] dstMAC_addr Pointer to the first MAC destination address, should
- * be 6-bytes length, in order LSB to the MSB
- * @param[in] NewState New State of this command, should be:
- * - ENABLE.
- * - DISABLE.
- * @return None
- *
- * Note:
- * The standard Ethernet cyclic redundancy check (CRC) function is calculated from
- * the 6 byte destination address in the Ethernet frame (this CRC is calculated
- * anyway as part of calculating the CRC of the whole frame), then bits [28:23] out of
- * the 32 bits CRC result are taken to form the hash. The 6 bit hash is used to access
- * the hash table: it is used as an index in the 64 bit HashFilter register that has been
- * programmed with accept values. If the selected accept value is 1, the frame is
- * accepted.
- **********************************************************************/
- void EMAC_SetHashFilter(uint8_t dstMAC_addr[], FunctionalState NewState)
- {
- uint32_t *pReg;
- uint32_t tmp;
- int32_t crc;
- // Calculate the CRC from the destination MAC address
- crc = EMAC_CRCCalc(dstMAC_addr, 6);
- // Extract the value from CRC to get index value for hash filter table
- crc = (crc >> 23) & 0x3F;
- pReg = (crc > 31) ? ((uint32_t *)&LPC_EMAC->HashFilterH) \
- : ((uint32_t *)&LPC_EMAC->HashFilterL);
- tmp = (crc > 31) ? (crc - 32) : crc;
- if (NewState == ENABLE)
- {
- (*pReg) |= (1UL << tmp);
- }
- else
- {
- (*pReg) &= ~(1UL << tmp);
- }
-
- }
- /*********************************************************************//**
- * @brief Calculates CRC code for number of bytes in the frame
- * @param[in] frame_no_fcs Pointer to the first byte of the frame
- * @param[in] frame_len length of the frame without the FCS
- * @return the CRC as a 32 bit integer
- **********************************************************************/
- int32_t EMAC_CRCCalc(uint8_t frame_no_fcs[], int32_t frame_len)
- {
- int i; // iterator
- int j; // another iterator
- char byte; // current byte
- int crc; // CRC result
- int q0, q1, q2, q3; // temporary variables
- crc = 0xFFFFFFFF;
- for (i = 0; i < frame_len; i++)
- {
- byte = *frame_no_fcs++;
- for (j = 0; j < 2; j++)
- {
- if (((crc >> 28) ^ (byte >> 3)) & 0x00000001)
- {
- q3 = 0x04C11DB7;
- }
- else
- {
- q3 = 0x00000000;
- }
- if (((crc >> 29) ^ (byte >> 2)) & 0x00000001)
- {
- q2 = 0x09823B6E;
- }
- else
- {
- q2 = 0x00000000;
- }
- if (((crc >> 30) ^ (byte >> 1)) & 0x00000001)
- {
- q1 = 0x130476DC;
- }
- else
- {
- q1 = 0x00000000;
- }
- if (((crc >> 31) ^ (byte >> 0)) & 0x00000001)
- {
- q0 = 0x2608EDB8;
- }
- else
- {
- q0 = 0x00000000;
- }
- crc = (crc << 4) ^ q3 ^ q2 ^ q1 ^ q0;
- byte >>= 4;
- }
- }
- return crc;
- }
- /*********************************************************************//**
- * @brief Enable/Disable Filter mode for each specified type EMAC peripheral
- * @param[in] ulFilterMode Filter mode, should be:
- * - EMAC_RFC_UCAST_EN: all frames of unicast types
- * will be accepted
- * - EMAC_RFC_BCAST_EN: broadcast frame will be
- * accepted
- * - EMAC_RFC_MCAST_EN: all frames of multicast
- * types will be accepted
- * - EMAC_RFC_UCAST_HASH_EN: The imperfect hash
- * filter will be applied to unicast addresses
- * - EMAC_RFC_MCAST_HASH_EN: The imperfect hash
- * filter will be applied to multicast addresses
- * - EMAC_RFC_PERFECT_EN: the destination address
- * will be compared with the 6 byte station address
- * programmed in the station address by the filter
- * - EMAC_RFC_MAGP_WOL_EN: the result of the magic
- * packet filter will generate a WoL interrupt when
- * there is a match
- * - EMAC_RFC_PFILT_WOL_EN: the result of the perfect address
- * matching filter and the imperfect hash filter will
- * generate a WoL interrupt when there is a match
- * @param[in] NewState New State of this command, should be:
- * - ENABLE
- * - DISABLE
- * @return None
- **********************************************************************/
- void EMAC_SetFilterMode(uint32_t ulFilterMode, FunctionalState NewState)
- {
- if (NewState == ENABLE)
- {
- LPC_EMAC->RxFilterCtrl |= ulFilterMode;
- if((ulFilterMode & EMAC_RFC_MCAST_HASH_EN) &&
- ((ulFilterMode & EMAC_RFC_MCAST_EN) == 0))
- {
- LPC_EMAC->RxFilterCtrl &= ~EMAC_RFC_MCAST_EN;
- }
- if((ulFilterMode & EMAC_RFC_UCAST_HASH_EN) &&
- ((ulFilterMode & EMAC_RFC_UCAST_EN) == 0))
- {
- LPC_EMAC->RxFilterCtrl &= ~EMAC_RFC_UCAST_EN;
- }
- }
- else
- {
- LPC_EMAC->RxFilterCtrl &= ~ulFilterMode;
- }
- }
- /*********************************************************************//**
- * @brief Get status of Wake On LAN Filter for each specified
- * type in EMAC peripheral, clear this status if it is set
- * @param[in] ulFilterMode WoL Filter mode, should be:
- * - EMAC_WOL_UCAST: unicast frames caused WoL
- * - EMAC_WOL_UCAST: broadcast frame caused WoL
- * - EMAC_WOL_MCAST: multicast frame caused WoL
- * - EMAC_WOL_UCAST_HASH: unicast frame that passes the
- * imperfect hash filter caused WoL
- * - EMAC_WOL_MCAST_HASH: multicast frame that passes the
- * imperfect hash filter caused WoL
- * - EMAC_WOL_PERFECT:perfect address matching filter
- * caused WoL
- * - EMAC_WOL_RX_FILTER: the receive filter caused WoL
- * - EMAC_WOL_MAG_PACKET: the magic packet filter caused WoL
- * @return SET/RESET
- **********************************************************************/
- FlagStatus EMAC_GetWoLStatus(uint32_t ulWoLMode)
- {
- if (LPC_EMAC->RxFilterWoLStatus & ulWoLMode)
- {
- LPC_EMAC->RxFilterWoLClear = ulWoLMode;
- return SET;
- }
- else
- {
- return RESET;
- }
- }
- /*********************************************************************//**
- * @brief Enable/Disable interrupt for each type in EMAC
- * @param[in] ulIntType Interrupt Type, should be:
- * - EMAC_INT_RX_OVERRUN: Receive Overrun
- * - EMAC_INT_RX_ERR: Receive Error
- * - EMAC_INT_RX_FIN: Receive Descriptor Finish
- * - EMAC_INT_RX_DONE: Receive Done
- * - EMAC_INT_TX_UNDERRUN: Transmit Under-run
- * - EMAC_INT_TX_ERR: Transmit Error
- * - EMAC_INT_TX_FIN: Transmit descriptor finish
- * - EMAC_INT_TX_DONE: Transmit Done
- * - EMAC_INT_SOFT_INT: Software interrupt
- * - EMAC_INT_WAKEUP: Wakeup interrupt
- * @param[in] NewState New State of this function, should be:
- * - ENABLE.
- * - DISABLE.
- * @return None
- **********************************************************************/
- void EMAC_IntCmd(uint32_t ulIntType, FunctionalState NewState)
- {
- if (NewState == ENABLE)
- {
- LPC_EMAC->IntEnable |= ulIntType;
- }
- else
- {
- LPC_EMAC->IntEnable &= ~(ulIntType);
- }
- }
- /*********************************************************************//**
- * @brief Check whether if specified interrupt flag is set or not
- * for each interrupt type in EMAC and clear interrupt pending
- * if it is set.
- * @param[in] ulIntType Interrupt Type, should be:
- * - EMAC_INT_RX_OVERRUN: Receive Overrun
- * - EMAC_INT_RX_ERR: Receive Error
- * - EMAC_INT_RX_FIN: Receive Descriptor Finish
- * - EMAC_INT_RX_DONE: Receive Done
- * - EMAC_INT_TX_UNDERRUN: Transmit Under-run
- * - EMAC_INT_TX_ERR: Transmit Error
- * - EMAC_INT_TX_FIN: Transmit descriptor finish
- * - EMAC_INT_TX_DONE: Transmit Done
- * - EMAC_INT_SOFT_INT: Software interrupt
- * - EMAC_INT_WAKEUP: Wakeup interrupt
- * @return New state of specified interrupt (SET or RESET)
- **********************************************************************/
- IntStatus EMAC_IntGetStatus(uint32_t ulIntType)
- {
- if (LPC_EMAC->IntStatus & ulIntType)
- {
- LPC_EMAC->IntClear = ulIntType;
- return SET;
- }
- else
- {
- return RESET;
- }
- }
- /**
- * @}
- */
- /**
- * @}
- */
- #endif /*_EMAC*/
|