123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158 |
- /**************************************************************************//**
- * @file emac.c
- * @version V1.00
- * @brief M480 EMAC driver source file
- *
- * SPDX-License-Identifier: Apache-2.0
- * @copyright (C) 2016-2020 Nuvoton Technology Corp. All rights reserved.
- *****************************************************************************/
- #include <stdio.h>
- #include <string.h>
- #include "NuMicro.h"
- /** @addtogroup Standard_Driver Standard Driver
- @{
- */
- /** @addtogroup EMAC_Driver EMAC Driver
- @{
- */
- /* Below are structure, definitions, static variables used locally by EMAC driver and does not want to parse by doxygen unless HIDDEN_SYMBOLS is defined */
- /** @cond HIDDEN_SYMBOLS */
- /** @addtogroup EMAC_EXPORTED_CONSTANTS EMAC Exported Constants
- @{
- */
- /* PHY Register Description */
- #define PHY_CNTL_REG 0x00UL /*!< PHY control register address */
- #define PHY_STATUS_REG 0x01UL /*!< PHY status register address */
- #define PHY_ID1_REG 0x02UL /*!< PHY ID1 register */
- #define PHY_ID2_REG 0x03UL /*!< PHY ID2 register */
- #define PHY_ANA_REG 0x04UL /*!< PHY auto-negotiation advertisement register */
- #define PHY_ANLPA_REG 0x05UL /*!< PHY auto-negotiation link partner availability register */
- #define PHY_ANE_REG 0x06UL /*!< PHY auto-negotiation expansion register */
- /* PHY Control Register */
- #define PHY_CNTL_RESET_PHY (1UL << 15UL)
- #define PHY_CNTL_DR_100MB (1UL << 13UL)
- #define PHY_CNTL_ENABLE_AN (1UL << 12UL)
- #define PHY_CNTL_POWER_DOWN (1UL << 11UL)
- #define PHY_CNTL_RESTART_AN (1UL << 9UL)
- #define PHY_CNTL_FULLDUPLEX (1UL << 8UL)
- /* PHY Status Register */
- #define PHY_STATUS_AN_COMPLETE (1UL << 5UL)
- #define PHY_STATUS_LINK_VALID (1UL << 2UL)
- /* PHY Auto-negotiation Advertisement Register */
- #define PHY_ANA_DR100_TX_FULL (1UL << 8UL)
- #define PHY_ANA_DR100_TX_HALF (1UL << 7UL)
- #define PHY_ANA_DR10_TX_FULL (1UL << 6UL)
- #define PHY_ANA_DR10_TX_HALF (1UL << 5UL)
- #define PHY_ANA_IEEE_802_3_CSMA_CD (1UL << 0UL)
- /* PHY Auto-negotiation Link Partner Advertisement Register */
- #define PHY_ANLPA_DR100_TX_FULL (1UL << 8UL)
- #define PHY_ANLPA_DR100_TX_HALF (1UL << 7UL)
- #define PHY_ANLPA_DR10_TX_FULL (1UL << 6UL)
- #define PHY_ANLPA_DR10_TX_HALF (1UL << 5UL)
- /* EMAC Tx/Rx descriptor's owner bit */
- #define EMAC_DESC_OWN_EMAC 0x80000000UL /*!< Set owner to EMAC */
- #define EMAC_DESC_OWN_CPU 0x00000000UL /*!< Set owner to CPU */
- /* Rx Frame Descriptor Status */
- #define EMAC_RXFD_RTSAS 0x0080UL /*!< Time Stamp Available */
- #define EMAC_RXFD_RP 0x0040UL /*!< Runt Packet */
- #define EMAC_RXFD_ALIE 0x0020UL /*!< Alignment Error */
- #define EMAC_RXFD_RXGD 0x0010UL /*!< Receiving Good packet received */
- #define EMAC_RXFD_PTLE 0x0008UL /*!< Packet Too Long Error */
- #define EMAC_RXFD_CRCE 0x0002UL /*!< CRC Error */
- #define EMAC_RXFD_RXINTR 0x0001UL /*!< Interrupt on receive */
- /* Tx Frame Descriptor's Control bits */
- #define EMAC_TXFD_TTSEN 0x08UL /*!< Tx time stamp enable */
- #define EMAC_TXFD_INTEN 0x04UL /*!< Tx interrupt enable */
- #define EMAC_TXFD_CRCAPP 0x02UL /*!< Append CRC */
- #define EMAC_TXFD_PADEN 0x01UL /*!< Padding mode enable */
- /* Tx Frame Descriptor Status */
- #define EMAC_TXFD_TXINTR 0x0001UL /*!< Interrupt on Transmit */
- #define EMAC_TXFD_DEF 0x0002UL /*!< Transmit deferred */
- #define EMAC_TXFD_TXCP 0x0008UL /*!< Transmission Completion */
- #define EMAC_TXFD_EXDEF 0x0010UL /*!< Exceed Deferral */
- #define EMAC_TXFD_NCS 0x0020UL /*!< No Carrier Sense Error */
- #define EMAC_TXFD_TXABT 0x0040UL /*!< Transmission Abort */
- #define EMAC_TXFD_LC 0x0080UL /*!< Late Collision */
- #define EMAC_TXFD_TXHA 0x0100UL /*!< Transmission halted */
- #define EMAC_TXFD_PAU 0x0200UL /*!< Paused */
- #define EMAC_TXFD_SQE 0x0400UL /*!< SQE error */
- #define EMAC_TXFD_TTSAS 0x0800UL /*!< Time Stamp available */
- /*@}*/ /* end of group EMAC_EXPORTED_CONSTANTS */
- /** @addtogroup EMAC_EXPORTED_TYPEDEF EMAC Exported Type Defines
- @{
- */
- /*@}*/ /* end of group EMAC_EXPORTED_TYPEDEF */
- /* local variables */
- static uint32_t s_u32EnableTs = 0UL;
- static void EMAC_MdioWrite(EMAC_T *EMAC, uint32_t u32Reg, uint32_t u32Addr, uint32_t u32Data);
- static uint32_t EMAC_MdioRead(EMAC_T *EMAC, uint32_t u32Reg, uint32_t u32Addr);
- static uint32_t EMAC_Subsec2Nsec(uint32_t subsec);
- static uint32_t EMAC_Nsec2Subsec(uint32_t nsec);
- static void EMAC_TxDescInit(EMAC_MEMMGR_T *psMemMgr);
- static void EMAC_RxDescInit(EMAC_MEMMGR_T *psMemMgr);
- /** @addtogroup EMAC_EXPORTED_FUNCTIONS EMAC Exported Functions
- @{
- */
- /**
- * @brief Write PHY register
- * @param[in] u32Reg PHY register number
- * @param[in] u32Addr PHY address, this address is board dependent
- * @param[in] u32Data data to write to PHY register
- * @return None
- */
- static void EMAC_MdioWrite(EMAC_T *EMAC, uint32_t u32Reg, uint32_t u32Addr, uint32_t u32Data)
- {
- /* Set data register */
- EMAC->MIIMDAT = u32Data ;
- /* Set PHY address, PHY register address, busy bit and write bit */
- EMAC->MIIMCTL = u32Reg | (u32Addr << 8) | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_WRITE_Msk | EMAC_MIIMCTL_MDCON_Msk;
- /* Wait write complete by polling busy bit. */
- while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk)
- {
- ;
- }
- }
- /**
- * @brief Read PHY register
- * @param[in] u32Reg PHY register number
- * @param[in] u32Addr PHY address, this address is board dependent
- * @return Value read from PHY register
- */
- static uint32_t EMAC_MdioRead(EMAC_T *EMAC, uint32_t u32Reg, uint32_t u32Addr)
- {
- /* Set PHY address, PHY register address, busy bit */
- EMAC->MIIMCTL = u32Reg | (u32Addr << EMAC_MIIMCTL_PHYADDR_Pos) | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk;
- /* Wait read complete by polling busy bit */
- while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk)
- {
- ;
- }
- /* Get return data */
- return EMAC->MIIMDAT;
- }
- void EMAC_Reset(EMAC_T *EMAC)
- {
- /* Reset MAC */
- EMAC->CTL = 0x1000000;
- }
- /**
- * @brief Initialize PHY chip, check for the auto-negotiation result.
- * @param None
- * @return None
- */
- void EMAC_PhyInit(EMAC_T *EMAC)
- {
- uint32_t reg;
- uint32_t i = 0UL;
- /* Reset Phy Chip */
- EMAC_MdioWrite(EMAC, PHY_CNTL_REG, EMAC_PHY_ADDR, PHY_CNTL_RESET_PHY);
- /* Wait until reset complete */
- while (1)
- {
- reg = EMAC_MdioRead(EMAC, PHY_CNTL_REG, EMAC_PHY_ADDR) ;
- if ((reg & PHY_CNTL_RESET_PHY) == 0UL)
- {
- break;
- }
- }
- while (!(EMAC_MdioRead(EMAC, PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_LINK_VALID))
- {
- if (i++ > 10000UL) /* Cable not connected */
- {
- EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk;
- EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk;
- break;
- }
- }
- if (i <= 10000UL)
- {
- /* Configure auto negotiation capability */
- EMAC_MdioWrite(EMAC, PHY_ANA_REG, EMAC_PHY_ADDR, PHY_ANA_DR100_TX_FULL |
- PHY_ANA_DR100_TX_HALF |
- PHY_ANA_DR10_TX_FULL |
- PHY_ANA_DR10_TX_HALF |
- PHY_ANA_IEEE_802_3_CSMA_CD);
- /* Restart auto negotiation */
- EMAC_MdioWrite(EMAC, PHY_CNTL_REG, EMAC_PHY_ADDR, EMAC_MdioRead(EMAC, PHY_CNTL_REG, EMAC_PHY_ADDR) | PHY_CNTL_RESTART_AN);
- /* Wait for auto-negotiation complete */
- while (!(EMAC_MdioRead(EMAC, PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_AN_COMPLETE))
- {
- ;
- }
- /* Check link valid again. Some PHYs needs to check result after link valid bit set */
- while (!(EMAC_MdioRead(EMAC, PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_LINK_VALID))
- {
- ;
- }
- /* Check link partner capability */
- reg = EMAC_MdioRead(EMAC, PHY_ANLPA_REG, EMAC_PHY_ADDR) ;
- if (reg & PHY_ANLPA_DR100_TX_FULL)
- {
- EMAC->CTL |= EMAC_CTL_OPMODE_Msk;
- EMAC->CTL |= EMAC_CTL_FUDUP_Msk;
- }
- else if (reg & PHY_ANLPA_DR100_TX_HALF)
- {
- EMAC->CTL |= EMAC_CTL_OPMODE_Msk;
- EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk;
- }
- else if (reg & PHY_ANLPA_DR10_TX_FULL)
- {
- EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk;
- EMAC->CTL |= EMAC_CTL_FUDUP_Msk;
- }
- else
- {
- EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk;
- EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk;
- }
- }
- }
- /**
- * @brief Initial EMAC Tx descriptors and get Tx descriptor base address
- * @param EMAC_MEMMGR_T pointer
- * @return None
- */
- static void EMAC_TxDescInit(EMAC_MEMMGR_T *psMemMgr)
- {
- uint32_t i;
- /* Get Frame descriptor's base address. */
- psMemMgr->psNextTxDesc = psMemMgr->psCurrentTxDesc = (EMAC_DESCRIPTOR_T *)((uint32_t)&psMemMgr->psTXDescs[0] | BIT31);
- for (i = 0UL; i < psMemMgr->u32TxDescSize; i++)
- {
- if (s_u32EnableTs)
- {
- psMemMgr->psTXDescs[i].u32Status1 = EMAC_TXFD_PADEN | EMAC_TXFD_CRCAPP | EMAC_TXFD_INTEN;
- }
- else
- {
- psMemMgr->psTXDescs[i].u32Status1 = EMAC_TXFD_PADEN | EMAC_TXFD_CRCAPP | EMAC_TXFD_INTEN | EMAC_TXFD_TTSEN;
- }
- psMemMgr->psTXDescs[i].u32Data = (uint32_t)& psMemMgr->psTXFrames[i] | BIT31;
- psMemMgr->psTXDescs[i].u32Status2 = 0UL;
- psMemMgr->psTXDescs[i].u32Next = (uint32_t)(&psMemMgr->psTXDescs[(i + 1UL) % EMAC_TX_DESC_SIZE]) | BIT31;
- psMemMgr->psTXDescs[i].u32Backup1 = psMemMgr->psTXDescs[i].u32Data;
- psMemMgr->psTXDescs[i].u32Backup2 = psMemMgr->psTXDescs[i].u32Next;
- }
- psMemMgr->psEmac->TXDSA = (uint32_t)psMemMgr->psCurrentTxDesc;
- }
- /**
- * @brief Initial EMAC Rx descriptors and get Rx descriptor base address
- * @param EMAC_MEMMGR_T pointer
- * @return None
- */
- static void EMAC_RxDescInit(EMAC_MEMMGR_T *psMemMgr)
- {
- uint32_t i;
- /* Get Frame descriptor's base address. */
- psMemMgr->psCurrentRxDesc = (EMAC_DESCRIPTOR_T *)((uint32_t)&psMemMgr->psRXDescs[0] | BIT31);
- for (i = 0UL; i < psMemMgr->u32RxDescSize; i++)
- {
- psMemMgr->psRXDescs[i].u32Status1 = EMAC_DESC_OWN_EMAC;
- psMemMgr->psRXDescs[i].u32Data = (uint32_t)&psMemMgr->psRXFrames[i] | BIT31;
- psMemMgr->psRXDescs[i].u32Status2 = 0UL;
- psMemMgr->psRXDescs[i].u32Next = (uint32_t)(&psMemMgr->psRXDescs[(i + 1UL) % EMAC_RX_DESC_SIZE]) | BIT31;
- psMemMgr->psRXDescs[i].u32Backup1 = psMemMgr->psRXDescs[i].u32Data;
- psMemMgr->psRXDescs[i].u32Backup2 = psMemMgr->psRXDescs[i].u32Next;
- }
- psMemMgr->psEmac->RXDSA = (uint32_t)psMemMgr->psCurrentRxDesc;
- }
- /**
- * @brief Convert subsecond value to nano second
- * @param[in] subsec Subsecond value to be convert
- * @return Nano second
- */
- static uint32_t EMAC_Subsec2Nsec(uint32_t subsec)
- {
- /* 2^31 subsec == 10^9 ns */
- uint64_t i;
- i = 1000000000ull * (uint64_t)subsec;
- i >>= 31;
- return ((uint32_t)i);
- }
- /**
- * @brief Convert nano second to subsecond value
- * @param[in] nsec Nano second to be convert
- * @return Subsecond
- */
- static uint32_t EMAC_Nsec2Subsec(uint32_t nsec)
- {
- /* 10^9 ns = 2^31 subsec */
- uint64_t i;
- i = (1ull << 31) * nsec;
- i /= 1000000000ull;
- return ((uint32_t)i);
- }
- /*@}*/ /* end of group EMAC_EXPORTED_FUNCTIONS */
- /** @endcond HIDDEN_SYMBOLS */
- /** @addtogroup EMAC_EXPORTED_FUNCTIONS EMAC Exported Functions
- @{
- */
- /**
- * @brief Initialize EMAC interface, including descriptors, MAC address, and PHY.
- * @param[in] pu8MacAddr Pointer to uint8_t array holds MAC address
- * @return None
- * @note This API configures EMAC to receive all broadcast and multicast packets, but could configure to other settings with
- * \ref EMAC_ENABLE_RECV_BCASTPKT, \ref EMAC_DISABLE_RECV_BCASTPKT, \ref EMAC_ENABLE_RECV_MCASTPKT, and \ref EMAC_DISABLE_RECV_MCASTPKT
- * @note Receive(RX) and transmit(TX) are not enabled yet, application must call \ref EMAC_ENABLE_RX and \ref EMAC_ENABLE_TX to
- * enable receive and transmit function.
- */
- void EMAC_Open(EMAC_MEMMGR_T *psMemMgr, uint8_t *pu8MacAddr)
- {
- EMAC_T *EMAC = psMemMgr->psEmac;
- /* Enable transmit and receive descriptor */
- EMAC_TxDescInit(psMemMgr);
- EMAC_RxDescInit(psMemMgr);
- /* Set the CAM Control register and the MAC address value */
- EMAC_SetMacAddr(EMAC, pu8MacAddr);
- /* Configure the MAC interrupt enable register. */
- EMAC->INTEN = EMAC_INTEN_RXIEN_Msk |
- EMAC_INTEN_TXIEN_Msk |
- EMAC_INTEN_RXGDIEN_Msk |
- EMAC_INTEN_TXCPIEN_Msk |
- EMAC_INTEN_RXBEIEN_Msk |
- EMAC_INTEN_TXBEIEN_Msk |
- EMAC_INTEN_RDUIEN_Msk |
- EMAC_INTEN_TSALMIEN_Msk |
- EMAC_INTEN_WOLIEN_Msk;
- /* Configure the MAC control register. */
- EMAC->CTL = EMAC_CTL_STRIPCRC_Msk |
- EMAC_CTL_RMIIEN_Msk;
- /* Accept packets for us and all broadcast and multicast packets */
- EMAC->CAMCTL = EMAC_CAMCTL_CMPEN_Msk |
- EMAC_CAMCTL_AMP_Msk |
- EMAC_CAMCTL_ABP_Msk;
- /* Limit the max receive frame length */
- EMAC->MRFL = EMAC_MAX_PKT_SIZE;
- }
- /**
- * @brief This function stop all receive and transmit activity and disable MAC interface
- * @param None
- * @return None
- */
- void EMAC_Close(EMAC_T *EMAC)
- {
- EMAC->CTL |= EMAC_CTL_RST_Msk;
- while (EMAC->CTL & EMAC_CTL_RST_Msk) {}
- }
- /**
- * @brief Set the device MAC address
- * @param[in] pu8MacAddr Pointer to uint8_t array holds MAC address
- * @return None
- */
- void EMAC_SetMacAddr(EMAC_T *EMAC, uint8_t *pu8MacAddr)
- {
- EMAC_EnableCamEntry(EMAC, 0UL, pu8MacAddr);
- }
- /**
- * @brief Fill a CAM entry for MAC address comparison.
- * @param[in] u32Entry MAC entry to fill. Entry 0 is used to store device MAC address, do not overwrite the setting in it.
- * @param[in] pu8MacAddr Pointer to uint8_t array holds MAC address
- * @return None
- */
- void EMAC_EnableCamEntry(EMAC_T *EMAC, uint32_t u32Entry, uint8_t pu8MacAddr[])
- {
- uint32_t u32Lsw, u32Msw;
- uint32_t reg;
- u32Lsw = (uint32_t)(((uint32_t)pu8MacAddr[4] << 24) |
- ((uint32_t)pu8MacAddr[5] << 16));
- u32Msw = (uint32_t)(((uint32_t)pu8MacAddr[0] << 24) |
- ((uint32_t)pu8MacAddr[1] << 16) |
- ((uint32_t)pu8MacAddr[2] << 8) |
- (uint32_t)pu8MacAddr[3]);
- reg = (uint32_t)&EMAC->CAM0M + u32Entry * 2UL * 4UL;
- *(uint32_t volatile *)reg = u32Msw;
- reg = (uint32_t)&EMAC->CAM0L + u32Entry * 2UL * 4UL;
- *(uint32_t volatile *)reg = u32Lsw;
- EMAC->CAMEN |= (1UL << u32Entry);
- }
- /**
- * @brief Disable a specified CAM entry
- * @param[in] u32Entry CAM entry to be disabled
- * @return None
- */
- void EMAC_DisableCamEntry(EMAC_T *EMAC, uint32_t u32Entry)
- {
- EMAC->CAMEN &= ~(1UL << u32Entry);
- }
- /**
- * @brief Receive an Ethernet packet
- * @param[in] pu8Data Pointer to a buffer to store received packet (4 byte CRC removed)
- * @param[in] pu32Size Received packet size (without 4 byte CRC).
- * @return Packet receive success or not
- * @retval 0 No packet available for receive
- * @retval 1 A packet is received
- * @note Return 0 doesn't guarantee the packet will be sent and received successfully.
- */
- uint32_t EMAC_RecvPkt(EMAC_MEMMGR_T *psMemMgr, uint8_t *pu8Data, uint32_t *pu32Size)
- {
- uint32_t reg;
- uint32_t u32Count = 0UL;
- EMAC_T *EMAC = psMemMgr->psEmac;
- /* Clear Rx interrupt flags */
- reg = EMAC->INTSTS;
- EMAC->INTSTS = reg & 0xFFFFUL; /* Clear all RX related interrupt status */
- if (reg & EMAC_INTSTS_RXBEIF_Msk)
- {
- /* Bus error occurred, this is usually a bad sign about software bug and will occur again... */
- while (1) {}
- }
- else
- {
- /* Get Rx Frame Descriptor */
- EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentRxDesc;
- /* If we reach last recv Rx descriptor, leave the loop */
- if ((desc->u32Status1 & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) /* ownership=CPU */
- {
- uint32_t status = desc->u32Status1 >> 16;
- /* If Rx frame is good, process received frame */
- if (status & EMAC_RXFD_RXGD)
- {
- /* lower 16 bit in descriptor status1 stores the Rx packet length */
- *pu32Size = desc->u32Status1 & 0xFFFFUL;
- memcpy(pu8Data, (uint8_t *)desc->u32Data, *pu32Size);
- u32Count = 1UL;
- }
- else
- {
- /* Save Error status if necessary */
- if (status & EMAC_RXFD_RP) {}
- if (status & EMAC_RXFD_ALIE) {}
- if (status & EMAC_RXFD_PTLE) {}
- if (status & EMAC_RXFD_CRCE) {}
- }
- }
- }
- return (u32Count);
- }
- /**
- * @brief Receive an Ethernet packet and the time stamp while it's received
- * @param[out] pu8Data Pointer to a buffer to store received packet (4 byte CRC removed)
- * @param[out] pu32Size Received packet size (without 4 byte CRC).
- * @param[out] pu32Sec Second value while packet received
- * @param[out] pu32Nsec Nano second value while packet received
- * @return Packet receive success or not
- * @retval 0 No packet available for receive
- * @retval 1 A packet is received
- * @note Return 0 doesn't guarantee the packet will be sent and received successfully.
- * @note Largest Ethernet packet is 1514 bytes after stripped CRC, application must give
- * a buffer large enough to store such packet
- */
- uint32_t EMAC_RecvPktTS(EMAC_MEMMGR_T *psMemMgr, uint8_t *pu8Data, uint32_t *pu32Size, uint32_t *pu32Sec, uint32_t *pu32Nsec)
- {
- EMAC_T *EMAC = psMemMgr->psEmac;
- uint32_t reg;
- uint32_t u32Count = 0UL;
- /* Clear Rx interrupt flags */
- reg = EMAC->INTSTS;
- EMAC->INTSTS = reg & 0xFFFFUL; /* Clear all Rx related interrupt status */
- if (reg & EMAC_INTSTS_RXBEIF_Msk)
- {
- /* Bus error occurred, this is usually a bad sign about software bug and will occur again... */
- while (1) {}
- }
- else
- {
- /* Get Rx Frame Descriptor */
- EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentRxDesc;
- /* If we reach last recv Rx descriptor, leave the loop */
- if (EMAC->CRXDSA != (uint32_t)desc)
- {
- if ((desc->u32Status1 | EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) /* ownership=CPU */
- {
- uint32_t status = desc->u32Status1 >> 16;
- /* If Rx frame is good, process received frame */
- if (status & EMAC_RXFD_RXGD)
- {
- /* lower 16 bit in descriptor status1 stores the Rx packet length */
- *pu32Size = desc->u32Status1 & 0xFFFFUL;
- memcpy(pu8Data, (uint8_t *)desc->u32Data, *pu32Size);
- *pu32Sec = desc->u32Next; /* second stores in descriptor's NEXT field */
- *pu32Nsec = EMAC_Subsec2Nsec(desc->u32Data); /* Sub nano second store in DATA field */
- u32Count = 1UL;
- }
- else
- {
- /* Save Error status if necessary */
- if (status & EMAC_RXFD_RP) {}
- if (status & EMAC_RXFD_ALIE) {}
- if (status & EMAC_RXFD_PTLE) {}
- if (status & EMAC_RXFD_CRCE) {}
- }
- }
- }
- }
- return (u32Count);
- }
- /**
- * @brief Clean up process after a packet is received
- * @param None
- * @return None
- * @details EMAC Rx interrupt service routine \b must call this API to release the resource use by receive process
- * @note Application can only call this function once every time \ref EMAC_RecvPkt or \ref EMAC_RecvPktTS returns 1
- */
- void EMAC_RecvPktDone(EMAC_MEMMGR_T *psMemMgr)
- {
- EMAC_T *EMAC = psMemMgr->psEmac;
- /* Get Rx Frame Descriptor */
- EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentRxDesc;
- /* Restore descriptor link list and data pointer they will be overwrite if time stamp enabled */
- desc->u32Data = desc->u32Backup1;
- desc->u32Next = desc->u32Backup2;
- /* Change ownership to DMA for next use */
- desc->u32Status1 |= EMAC_DESC_OWN_EMAC;
- /* Get Next Frame Descriptor pointer to process */
- desc = (EMAC_DESCRIPTOR_T *)desc->u32Next;
- /* Save last processed Rx descriptor */
- psMemMgr->psCurrentRxDesc = desc;
- EMAC_TRIGGER_RX(EMAC);
- }
- /**
- * @brief Send an Ethernet packet
- * @param[in] pu8Data Pointer to a buffer holds the packet to transmit
- * @param[in] u32Size Packet size (without 4 byte CRC).
- * @return Packet transmit success or not
- * @retval 0 Transmit failed due to descriptor unavailable.
- * @retval 1 Packet is copied to descriptor and triggered to transmit.
- * @note Return 1 doesn't guarantee the packet will be sent and received successfully.
- */
- uint32_t EMAC_SendPkt(EMAC_MEMMGR_T *psMemMgr, uint8_t *pu8Data, uint32_t u32Size)
- {
- EMAC_T *EMAC = psMemMgr->psEmac;
- /* Get Tx frame descriptor & data pointer */
- EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psNextTxDesc;
- uint32_t status = desc->u32Status1;
- uint32_t ret = 0UL;
- /* Check descriptor ownership */
- if ((status & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC)
- {
- memcpy((uint8_t *)desc->u32Data, pu8Data, u32Size);
- /* Set Tx descriptor transmit byte count */
- desc->u32Status2 = u32Size;
- /* Change descriptor ownership to EMAC */
- desc->u32Status1 |= EMAC_DESC_OWN_EMAC;
- /* Get next Tx descriptor */
- psMemMgr->psNextTxDesc = (EMAC_DESCRIPTOR_T *)(desc->u32Next);
- /* Trigger EMAC to send the packet */
- EMAC_TRIGGER_TX(EMAC);
- ret = 1UL;
- }
- return (ret);
- }
- /**
- * @brief Clean up process after packet(s) are sent
- * @param None
- * @return Number of packet sent between two function calls
- * @details EMAC Tx interrupt service routine \b must call this API or \ref EMAC_SendPktDoneTS to
- * release the resource use by transmit process
- */
- uint32_t EMAC_SendPktDone(EMAC_MEMMGR_T *psMemMgr)
- {
- EMAC_T *EMAC = psMemMgr->psEmac;
- uint32_t status, reg;
- uint32_t last_tx_desc;
- uint32_t u32Count = 0UL;
- reg = EMAC->INTSTS;
- /* Clear Tx interrupt flags */
- EMAC->INTSTS = reg & (0xFFFF0000UL & ~EMAC_INTSTS_TSALMIF_Msk);
- if (reg & EMAC_INTSTS_TXBEIF_Msk)
- {
- /* Bus error occurred, this is usually a bad sign about software bug and will occur again... */
- while (1) {}
- }
- else
- {
- /* Get our first descriptor to process */
- EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentTxDesc;
- /* Process the descriptor(s). */
- last_tx_desc = EMAC->CTXDSA ;
- do
- {
- /* Descriptor ownership is still EMAC, so this packet haven't been send. */
- if (desc->u32Status1 & EMAC_DESC_OWN_EMAC)
- {
- break;
- }
- /* Get Tx status stored in descriptor */
- status = desc->u32Status2 >> 16UL;
- if (status & EMAC_TXFD_TXCP)
- {
- u32Count++;
- }
- else
- {
- /* Do nothing here on error. */
- if (status & EMAC_TXFD_TXABT) {}
- if (status & EMAC_TXFD_DEF) {}
- if (status & EMAC_TXFD_PAU) {}
- if (status & EMAC_TXFD_EXDEF) {}
- if (status & EMAC_TXFD_NCS) {}
- if (status & EMAC_TXFD_SQE) {}
- if (status & EMAC_TXFD_LC) {}
- if (status & EMAC_TXFD_TXHA) {}
- }
- /* restore descriptor link list and data pointer they will be overwrite if time stamp enabled */
- desc->u32Data = desc->u32Backup1;
- desc->u32Next = desc->u32Backup2;
- /* go to next descriptor in link */
- desc = (EMAC_DESCRIPTOR_T *)desc->u32Next;
- }
- while (last_tx_desc != (uint32_t)desc); /* If we reach last sent Tx descriptor, leave the loop */
- /* Save last processed Tx descriptor */
- psMemMgr->psCurrentTxDesc = (EMAC_DESCRIPTOR_T *)desc;
- }
- return (u32Count);
- }
- /**
- * @brief Clean up process after a packet is sent, and get the time stamp while packet is sent
- * @param[in] pu32Sec Second value while packet sent
- * @param[in] pu32Nsec Nano second value while packet sent
- * @return If a packet sent successfully
- * @retval 0 No packet sent successfully, and the value in *pu32Sec and *pu32Nsec are meaningless
- * @retval 1 A packet sent successfully, and the value in *pu32Sec and *pu32Nsec is the time stamp while packet sent
- * @details EMAC Tx interrupt service routine \b must call this API or \ref EMAC_SendPktDone to
- * release the resource use by transmit process
- */
- uint32_t EMAC_SendPktDoneTS(EMAC_MEMMGR_T *psMemMgr, uint32_t *pu32Sec, uint32_t *pu32Nsec)
- {
- EMAC_T *EMAC = psMemMgr->psEmac;
- uint32_t reg;
- uint32_t u32Count = 0UL;
- reg = EMAC->INTSTS;
- /* Clear Tx interrupt flags */
- EMAC->INTSTS = reg & (0xFFFF0000UL & ~EMAC_INTSTS_TSALMIF_Msk);
- if (reg & EMAC_INTSTS_TXBEIF_Msk)
- {
- /* Bus error occurred, this is usually a bad sign about software bug and will occur again... */
- while (1) {}
- }
- else
- {
- /* Process the descriptor.
- Get our first descriptor to process */
- EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentTxDesc;
- /* Descriptor ownership is still EMAC, so this packet haven't been send. */
- if ((desc->u32Status1 & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC)
- {
- /* Get Tx status stored in descriptor */
- uint32_t status = desc->u32Status2 >> 16UL;
- if (status & EMAC_TXFD_TXCP)
- {
- u32Count = 1UL;
- *pu32Sec = desc->u32Next; /* second stores in descriptor's NEXT field */
- *pu32Nsec = EMAC_Subsec2Nsec(desc->u32Data); /* Sub nano second store in DATA field */
- }
- else
- {
- /* Do nothing here on error. */
- if (status & EMAC_TXFD_TXABT) {}
- if (status & EMAC_TXFD_DEF) {}
- if (status & EMAC_TXFD_PAU) {}
- if (status & EMAC_TXFD_EXDEF) {}
- if (status & EMAC_TXFD_NCS) {}
- if (status & EMAC_TXFD_SQE) {}
- if (status & EMAC_TXFD_LC) {}
- if (status & EMAC_TXFD_TXHA) {}
- }
- /* restore descriptor link list and data pointer they will be overwrite if time stamp enabled */
- desc->u32Data = desc->u32Backup1;
- desc->u32Next = desc->u32Backup2;
- /* go to next descriptor in link */
- desc = (EMAC_DESCRIPTOR_T *)desc->u32Next;
- /* Save last processed Tx descriptor */
- psMemMgr->psCurrentTxDesc = desc;
- }
- }
- return (u32Count);
- }
- /**
- * @brief Enable IEEE1588 time stamp function and set current time
- * @param[in] u32Sec Second value
- * @param[in] u32Nsec Nano second value
- * @return None
- */
- void EMAC_EnableTS(EMAC_T *EMAC, uint32_t u32Sec, uint32_t u32Nsec)
- {
- #if 0
- double f;
- uint32_t reg;
- EMAC->TSCTL = EMAC_TSCTL_TSEN_Msk;
- EMAC->UPDSEC = u32Sec; /* Assume current time is 0 sec + 0 nano sec */
- EMAC->UPDSUBSEC = EMAC_Nsec2Subsec(u32Nsec);
- /* PTP source clock is 160MHz (Real chip using PLL). Each tick is 6.25ns
- Assume we want to set each tick to 100ns.
- Increase register = (100 * 2^31) / (10^9) = 214.71 =~ 215 = 0xD7
- Addend register = 2^32 * tick_freq / (160MHz), where tick_freq = (2^31 / 215) MHz
- From above equation, addend register = 2^63 / (160M * 215) ~= 268121280 = 0xFFB34C0
- So:
- EMAC->TSIR = 0xD7;
- EMAC->TSAR = 0x1E70C600; */
- f = (100.0 * 2147483648.0) / (1000000000.0) + 0.5;
- EMAC->TSINC = (reg = (uint32_t)f);
- f = (double)9223372036854775808.0 / ((double)(CLK_GetHCLKFreq()) * (double)reg);
- EMAC->TSADDEND = (uint32_t)f;
- EMAC->TSCTL |= (EMAC_TSCTL_TSUPDATE_Msk | EMAC_TSCTL_TSIEN_Msk | EMAC_TSCTL_TSMODE_Msk); /* Fine update */
- #endif
- }
- /**
- * @brief Disable IEEE1588 time stamp function
- * @param None
- * @return None
- */
- void EMAC_DisableTS(EMAC_T *EMAC)
- {
- #if 0
- EMAC->TSCTL = 0UL;
- #endif
- }
- /**
- * @brief Get current time stamp
- * @param[out] pu32Sec Current second value
- * @param[out] pu32Nsec Current nano second value
- * @return None
- */
- void EMAC_GetTime(EMAC_T *EMAC, uint32_t *pu32Sec, uint32_t *pu32Nsec)
- {
- /* Must read TSLSR firstly. Hardware will preserve TSMSR value at the time TSLSR read. */
- *pu32Nsec = EMAC_Subsec2Nsec(EMAC->TSSUBSEC);
- *pu32Sec = EMAC->TSSEC;
- }
- /**
- * @brief Set current time stamp
- * @param[in] u32Sec Second value
- * @param[in] u32Nsec Nano second value
- * @return None
- */
- void EMAC_SetTime(EMAC_T *EMAC, uint32_t u32Sec, uint32_t u32Nsec)
- {
- /* Disable time stamp counter before update time value (clear EMAC_TSCTL_TSIEN_Msk) */
- EMAC->TSCTL = EMAC_TSCTL_TSEN_Msk;
- EMAC->UPDSEC = u32Sec;
- EMAC->UPDSUBSEC = EMAC_Nsec2Subsec(u32Nsec);
- EMAC->TSCTL |= (EMAC_TSCTL_TSIEN_Msk | EMAC_TSCTL_TSMODE_Msk);
- }
- /**
- * @brief Enable alarm function and set alarm time
- * @param[in] u32Sec Second value to trigger alarm
- * @param[in] u32Nsec Nano second value to trigger alarm
- * @return None
- */
- void EMAC_EnableAlarm(EMAC_T *EMAC, uint32_t u32Sec, uint32_t u32Nsec)
- {
- EMAC->ALMSEC = u32Sec;
- EMAC->ALMSUBSEC = EMAC_Nsec2Subsec(u32Nsec);
- EMAC->TSCTL |= EMAC_TSCTL_TSALMEN_Msk;
- }
- /**
- * @brief Disable alarm function
- * @param None
- * @return None
- */
- void EMAC_DisableAlarm(EMAC_T *EMAC)
- {
- EMAC->TSCTL &= ~EMAC_TSCTL_TSALMEN_Msk;
- }
- /**
- * @brief Add a offset to current time
- * @param[in] u32Neg Offset is negative value (u32Neg == 1) or positive value (u32Neg == 0).
- * @param[in] u32Sec Second value to add to current time
- * @param[in] u32Nsec Nano second value to add to current time
- * @return None
- */
- void EMAC_UpdateTime(EMAC_T *EMAC, uint32_t u32Neg, uint32_t u32Sec, uint32_t u32Nsec)
- {
- EMAC->UPDSEC = u32Sec;
- EMAC->UPDSUBSEC = EMAC_Nsec2Subsec(u32Nsec);
- if (u32Neg)
- {
- EMAC->UPDSUBSEC |= BIT31; /* Set bit 31 indicates this is a negative value */
- }
- EMAC->TSCTL |= EMAC_TSCTL_TSUPDATE_Msk;
- }
- /**
- * @brief Check Ethernet link status
- * @param None
- * @return Current link status, could be one of following value.
- * - \ref EMAC_LINK_DOWN
- * - \ref EMAC_LINK_100F
- * - \ref EMAC_LINK_100H
- * - \ref EMAC_LINK_10F
- * - \ref EMAC_LINK_10H
- * @note This API should be called regularly to sync EMAC setting with real connection status
- */
- uint32_t EMAC_CheckLinkStatus(EMAC_T *EMAC)
- {
- uint32_t reg, ret = EMAC_LINK_DOWN;
- /* Check link valid again */
- if (EMAC_MdioRead(EMAC, PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_LINK_VALID)
- {
- /* Check link partner capability */
- reg = EMAC_MdioRead(EMAC, PHY_ANLPA_REG, EMAC_PHY_ADDR) ;
- if (reg & PHY_ANLPA_DR100_TX_FULL)
- {
- EMAC->CTL |= EMAC_CTL_OPMODE_Msk;
- EMAC->CTL |= EMAC_CTL_FUDUP_Msk;
- ret = EMAC_LINK_100F;
- }
- else if (reg & PHY_ANLPA_DR100_TX_HALF)
- {
- EMAC->CTL |= EMAC_CTL_OPMODE_Msk;
- EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk;
- ret = EMAC_LINK_100H;
- }
- else if (reg & PHY_ANLPA_DR10_TX_FULL)
- {
- EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk;
- EMAC->CTL |= EMAC_CTL_FUDUP_Msk;
- ret = EMAC_LINK_10F;
- }
- else
- {
- EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk;
- EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk;
- ret = EMAC_LINK_10H;
- }
- }
- return ret;
- }
- /**
- * @brief Fill a MAC address to list and enable.
- * @param A MAC address
- * @return The CAM index
- * @retval -1 Failed to fill the MAC address.
- * @retval 0~(EMAC_CAMENTRY_NB-1) The index number of entry location.
- */
- int32_t EMAC_FillCamEntry(EMAC_T *EMAC, uint8_t pu8MacAddr[])
- {
- uint32_t *EMAC_CAMxM;
- uint32_t *EMAC_CAMxL;
- int32_t index;
- uint8_t mac[6];
- for (index = 0; index < EMAC_CAMENTRY_NB; index ++)
- {
- EMAC_CAMxM = (uint32_t *)((uint32_t)&EMAC->CAM0M + (index * 8));
- EMAC_CAMxL = (uint32_t *)((uint32_t)&EMAC->CAM0L + (index * 8));
- mac[0] = (*EMAC_CAMxM >> 24) & 0xff;
- mac[1] = (*EMAC_CAMxM >> 16) & 0xff;
- mac[2] = (*EMAC_CAMxM >> 8) & 0xff;
- mac[3] = (*EMAC_CAMxM) & 0xff;
- mac[4] = (*EMAC_CAMxL >> 24) & 0xff;
- mac[5] = (*EMAC_CAMxL >> 16) & 0xff;
- if (memcmp(mac, pu8MacAddr, sizeof(mac)) == 0)
- {
- goto exit_emac_fillcamentry;
- }
- if (*EMAC_CAMxM == 0 && *EMAC_CAMxL == 0)
- {
- break;
- }
- }
- if (index < EMAC_CAMENTRY_NB)
- {
- EMAC_EnableCamEntry(EMAC, index, pu8MacAddr);
- goto exit_emac_fillcamentry;
- }
- return -1;
- exit_emac_fillcamentry:
- return index;
- }
- /**
- * @brief Send an Ethernet packet
- * @param[in] u32Size Packet size (without 4 byte CRC).
- * @return Packet transmit success or not
- * @retval 0 Transmit failed due to descriptor unavailable.
- * @retval 1 Triggered to transmit.
- * @note Return 1 doesn't guarantee the packet will be sent and received successfully.
- */
- uint32_t EMAC_SendPktWoCopy(EMAC_MEMMGR_T *psMemMgr, uint32_t u32Size)
- {
- EMAC_T *EMAC = psMemMgr->psEmac;
- /* Get Tx frame descriptor & data pointer */
- EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psNextTxDesc;
- uint32_t status = desc->u32Status1;
- uint32_t ret = 0UL;
- /* Check descriptor ownership */
- if ((status & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC)
- {
- /* Set Tx descriptor transmit byte count */
- desc->u32Status2 = u32Size;
- /* Change descriptor ownership to EMAC */
- desc->u32Status1 |= EMAC_DESC_OWN_EMAC;
- /* Get next Tx descriptor */
- psMemMgr->psNextTxDesc = (EMAC_DESCRIPTOR_T *)(desc->u32Next);
- /* Trigger EMAC to send the packet */
- EMAC_TRIGGER_TX(EMAC);
- ret = 1UL;
- }
- return (ret);
- }
- /**
- * @brief Get avaiable TX buffer address
- * @param None
- * @return An avaiable TX buffer.
- * @note This API should be called before EMAC_SendPkt_WoCopy calling. Caller will do data-copy.
- */
- uint8_t *EMAC_ClaimFreeTXBuf(EMAC_MEMMGR_T *psMemMgr)
- {
- EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psNextTxDesc;
- if (desc->u32Status1 & EMAC_DESC_OWN_EMAC)
- {
- return (NULL);
- }
- else
- {
- return (uint8_t *)desc->u32Data;
- }
- }
- /**
- * @brief Get data length of avaiable RX buffer.
- * @param None
- * @return An data length of avaiable RX buffer.
- * @note This API should be called before EMAC_RecvPktDone_WoTrigger calling. Caller will do data-copy.
- */
- uint32_t EMAC_GetAvailRXBufSize(EMAC_MEMMGR_T *psMemMgr, uint8_t **ppuDataBuf)
- {
- EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentRxDesc;
- if ((desc->u32Status1 & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) /* ownership=CPU */
- {
- uint32_t status = desc->u32Status1 >> 16;
- /* It is good and no CRC error. */
- if ((status & EMAC_RXFD_RXGD) && !(status & EMAC_RXFD_CRCE))
- {
- *ppuDataBuf = (uint8_t *)desc->u32Data;
- return desc->u32Status1 & 0xFFFFUL;
- }
- else
- {
- // Drop it
- EMAC_RecvPktDone(psMemMgr);
- }
- }
- return 0;
- }
- /**
- * @brief Clean up process after a packet is received.
- * @param None
- * @return None
- * @details Caller must call the function to release the resource.
- * @note Application can only call this function once every time \ref EMAC_RecvPkt or \ref EMAC_RecvPktTS returns 1
- * @note This function is without doing EMAC_TRIGGER_RX.
- */
- void EMAC_RecvPktDoneWoRxTrigger(EMAC_MEMMGR_T *psMemMgr)
- {
- /* Get Rx Frame Descriptor */
- EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentRxDesc;
- /* Restore descriptor link list and data pointer they will be overwrite if time stamp enabled */
- desc->u32Data = desc->u32Backup1;
- desc->u32Next = desc->u32Backup2;
- /* Change ownership to DMA for next use */
- desc->u32Status1 |= EMAC_DESC_OWN_EMAC;
- /* Get Next Frame Descriptor pointer to process */
- desc = (EMAC_DESCRIPTOR_T *)desc->u32Next;
- /* Save last processed Rx descriptor */
- psMemMgr->psCurrentRxDesc = desc;
- }
- /*@}*/ /* end of group EMAC_EXPORTED_FUNCTIONS */
- /*@}*/ /* end of group EMAC_Driver */
- /*@}*/ /* end of group Standard_Driver */
- /*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/
|