Nicolas Borla / Mbed OS BBR_1Ebene
Committer:
borlanic
Date:
Mon May 14 11:29:06 2018 +0000
Revision:
0:fbdae7e6d805
BBR

Who changed what in which revision?

UserRevisionLine numberNew contents of line
borlanic 0:fbdae7e6d805 1 /**************************************************************************//**
borlanic 0:fbdae7e6d805 2 * @file emac.c
borlanic 0:fbdae7e6d805 3 * @version V1.00
borlanic 0:fbdae7e6d805 4 * $Revision: 14 $
borlanic 0:fbdae7e6d805 5 * $Date: 14/05/29 1:13p $
borlanic 0:fbdae7e6d805 6 * @brief NUC472/NUC442 EMAC driver source file
borlanic 0:fbdae7e6d805 7 *
borlanic 0:fbdae7e6d805 8 * @note
borlanic 0:fbdae7e6d805 9 * Copyright (C) 2013 Nuvoton Technology Corp. All rights reserved.
borlanic 0:fbdae7e6d805 10 *****************************************************************************/
borlanic 0:fbdae7e6d805 11 #include <stdio.h>
borlanic 0:fbdae7e6d805 12 #include <string.h>
borlanic 0:fbdae7e6d805 13 #include "NUC472_442.h"
borlanic 0:fbdae7e6d805 14
borlanic 0:fbdae7e6d805 15 /** @addtogroup NUC472_442_Device_Driver NUC472/NUC442 Device Driver
borlanic 0:fbdae7e6d805 16 @{
borlanic 0:fbdae7e6d805 17 */
borlanic 0:fbdae7e6d805 18
borlanic 0:fbdae7e6d805 19 /** @addtogroup NUC472_442_EMAC_Driver EMAC Driver
borlanic 0:fbdae7e6d805 20 @{
borlanic 0:fbdae7e6d805 21 */
borlanic 0:fbdae7e6d805 22
borlanic 0:fbdae7e6d805 23
borlanic 0:fbdae7e6d805 24 // Below are structure, definitions, static variables used locally by EMAC driver and does not want to parse by doxygen unless HIDDEN_SYMBOLS is defined
borlanic 0:fbdae7e6d805 25 /// @cond HIDDEN_SYMBOLS
borlanic 0:fbdae7e6d805 26
borlanic 0:fbdae7e6d805 27 /** @addtogroup NUC472_442_EMAC_EXPORTED_CONSTANTS EMAC Exported Constants
borlanic 0:fbdae7e6d805 28 @{
borlanic 0:fbdae7e6d805 29 */
borlanic 0:fbdae7e6d805 30 // Un-comment to print EMAC debug message
borlanic 0:fbdae7e6d805 31 //#define EMAC_DBG
borlanic 0:fbdae7e6d805 32 #ifndef EMAC_DBG
borlanic 0:fbdae7e6d805 33 #define printf(...)
borlanic 0:fbdae7e6d805 34 #endif
borlanic 0:fbdae7e6d805 35
borlanic 0:fbdae7e6d805 36 // PHY Register Description
borlanic 0:fbdae7e6d805 37 #define PHY_CNTL_REG 0x00 ///< PHY control register address
borlanic 0:fbdae7e6d805 38 #define PHY_STATUS_REG 0x01 ///< PHY status register address
borlanic 0:fbdae7e6d805 39 #define PHY_ID1_REG 0x02 ///< PHY ID1 register
borlanic 0:fbdae7e6d805 40 #define PHY_ID2_REG 0x03 ///< PHY ID2 register
borlanic 0:fbdae7e6d805 41 #define PHY_ANA_REG 0x04 ///< PHY auto-negotiation advertisement register
borlanic 0:fbdae7e6d805 42 #define PHY_ANLPA_REG 0x05 ///< PHY auto-negotiation link partner availability register
borlanic 0:fbdae7e6d805 43 #define PHY_ANE_REG 0x06 ///< PHY auto-negotiation expansion register
borlanic 0:fbdae7e6d805 44
borlanic 0:fbdae7e6d805 45 //PHY Control Register
borlanic 0:fbdae7e6d805 46 #define PHY_CNTL_RESET_PHY (1 << 15)
borlanic 0:fbdae7e6d805 47 #define PHY_CNTL_DR_100MB (1 << 13)
borlanic 0:fbdae7e6d805 48 #define PHY_CNTL_ENABLE_AN (1 << 12)
borlanic 0:fbdae7e6d805 49 #define PHY_CNTL_POWER_DOWN (1 << 11)
borlanic 0:fbdae7e6d805 50 #define PHY_CNTL_RESTART_AN (1 << 9)
borlanic 0:fbdae7e6d805 51 #define PHY_CNTL_FULLDUPLEX (1 << 8)
borlanic 0:fbdae7e6d805 52
borlanic 0:fbdae7e6d805 53 // PHY Status Register
borlanic 0:fbdae7e6d805 54 #define PHY_STATUS_AN_COMPLETE (1 << 5)
borlanic 0:fbdae7e6d805 55 #define PHY_STATUS_LINK_VALID (1 << 3)
borlanic 0:fbdae7e6d805 56
borlanic 0:fbdae7e6d805 57 // PHY Auto-negotiation Advertisement Register
borlanic 0:fbdae7e6d805 58 #define PHY_ANA_DR100_TX_FULL (1 << 8)
borlanic 0:fbdae7e6d805 59 #define PHY_ANA_DR100_TX_HALF (1 << 7)
borlanic 0:fbdae7e6d805 60 #define PHY_ANA_DR10_TX_FULL (1 << 6)
borlanic 0:fbdae7e6d805 61 #define PHY_ANA_DR10_TX_HALF (1 << 5)
borlanic 0:fbdae7e6d805 62 #define PHY_ANA_IEEE_802_3_CSMA_CD (1 << 0)
borlanic 0:fbdae7e6d805 63
borlanic 0:fbdae7e6d805 64 // PHY Auto-negotiation Link Partner Advertisement Register
borlanic 0:fbdae7e6d805 65 #define PHY_ANLPA_DR100_TX_FULL (1 << 8)
borlanic 0:fbdae7e6d805 66 #define PHY_ANLPA_DR100_TX_HALF (1 << 7)
borlanic 0:fbdae7e6d805 67 #define PHY_ANLPA_DR10_TX_FULL (1 << 6)
borlanic 0:fbdae7e6d805 68 #define PHY_ANLPA_DR10_TX_HALF (1 << 5)
borlanic 0:fbdae7e6d805 69
borlanic 0:fbdae7e6d805 70 // EMAC Tx/Rx descriptor's owner bit
borlanic 0:fbdae7e6d805 71 #define EMAC_DESC_OWN_EMAC 0x80000000 ///< Set owner to EMAC
borlanic 0:fbdae7e6d805 72 #define EMAC_DESC_OWN_CPU 0x00000000 ///< Set owner to CPU
borlanic 0:fbdae7e6d805 73
borlanic 0:fbdae7e6d805 74 // Rx Frame Descriptor Status
borlanic 0:fbdae7e6d805 75 #define EMAC_RXFD_RTSAS 0x0080 ///< Time Stamp Available
borlanic 0:fbdae7e6d805 76 #define EMAC_RXFD_RP 0x0040 ///< Runt Packet
borlanic 0:fbdae7e6d805 77 #define EMAC_RXFD_ALIE 0x0020 ///< Alignment Error
borlanic 0:fbdae7e6d805 78 #define EMAC_RXFD_RXGD 0x0010 ///< Receiving Good packet received
borlanic 0:fbdae7e6d805 79 #define EMAC_RXFD_PTLE 0x0008 ///< Packet Too Long Error
borlanic 0:fbdae7e6d805 80 #define EMAC_RXFD_CRCE 0x0002 ///< CRC Error
borlanic 0:fbdae7e6d805 81 #define EMAC_RXFD_RXINTR 0x0001 ///< Interrupt on receive
borlanic 0:fbdae7e6d805 82
borlanic 0:fbdae7e6d805 83 // Tx Frame Descriptor's Control bits
borlanic 0:fbdae7e6d805 84 #define EMAC_TXFD_TTSEN 0x08 ///< Tx time stamp enable
borlanic 0:fbdae7e6d805 85 #define EMAC_TXFD_INTEN 0x04 ///< Tx interrupt enable
borlanic 0:fbdae7e6d805 86 #define EMAC_TXFD_CRCAPP 0x02 ///< Append CRC
borlanic 0:fbdae7e6d805 87 #define EMAC_TXFD_PADEN 0x01 ///< Padding mode enable
borlanic 0:fbdae7e6d805 88
borlanic 0:fbdae7e6d805 89 // Tx Frame Descriptor Status
borlanic 0:fbdae7e6d805 90 #define EMAC_TXFD_TXINTR 0x0001 ///< Interrupt on Transmit
borlanic 0:fbdae7e6d805 91 #define EMAC_TXFD_DEF 0x0002 ///< Transmit deferred
borlanic 0:fbdae7e6d805 92 #define EMAC_TXFD_TXCP 0x0008 ///< Transmission Completion
borlanic 0:fbdae7e6d805 93 #define EMAC_TXFD_EXDEF 0x0010 ///< Exceed Deferral
borlanic 0:fbdae7e6d805 94 #define EMAC_TXFD_NCS 0x0020 ///< No Carrier Sense Error
borlanic 0:fbdae7e6d805 95 #define EMAC_TXFD_TXABT 0x0040 ///< Transmission Abort
borlanic 0:fbdae7e6d805 96 #define EMAC_TXFD_LC 0x0080 ///< Late Collision
borlanic 0:fbdae7e6d805 97 #define EMAC_TXFD_TXHA 0x0100 ///< Transmission halted
borlanic 0:fbdae7e6d805 98 #define EMAC_TXFD_PAU 0x0200 ///< Paused
borlanic 0:fbdae7e6d805 99 #define EMAC_TXFD_SQE 0x0400 ///< SQE error
borlanic 0:fbdae7e6d805 100 #define EMAC_TXFD_TTSAS 0x0800 ///< Time Stamp available
borlanic 0:fbdae7e6d805 101
borlanic 0:fbdae7e6d805 102 /*@}*/ /* end of group NUC472_442_EMAC_EXPORTED_CONSTANTS */
borlanic 0:fbdae7e6d805 103
borlanic 0:fbdae7e6d805 104 /** @addtogroup NUC472_442_EMAC_EXPORTED_TYPEDEF EMAC Exported Type Defines
borlanic 0:fbdae7e6d805 105 @{
borlanic 0:fbdae7e6d805 106 */
borlanic 0:fbdae7e6d805 107
borlanic 0:fbdae7e6d805 108 /** Tx/Rx buffer descriptor structure */
borlanic 0:fbdae7e6d805 109 typedef struct {
borlanic 0:fbdae7e6d805 110 uint32_t u32Status1; ///< Status word 1
borlanic 0:fbdae7e6d805 111 uint32_t u32Data; ///< Pointer to data buffer
borlanic 0:fbdae7e6d805 112 uint32_t u32Status2; ///< Status word 2
borlanic 0:fbdae7e6d805 113 uint32_t u32Next; ///< Pointer to next descriptor
borlanic 0:fbdae7e6d805 114 uint32_t u32Backup1; ///< For backup descriptor fields over written by time stamp
borlanic 0:fbdae7e6d805 115 uint32_t u32Backup2; ///< For backup descriptor fields over written by time stamp
borlanic 0:fbdae7e6d805 116 } EMAC_DESCRIPTOR_T;
borlanic 0:fbdae7e6d805 117
borlanic 0:fbdae7e6d805 118 /** Tx/Rx buffer structure */
borlanic 0:fbdae7e6d805 119 typedef struct {
borlanic 0:fbdae7e6d805 120 uint8_t au8Buf[1520];
borlanic 0:fbdae7e6d805 121 } EMAC_FRAME_T;
borlanic 0:fbdae7e6d805 122
borlanic 0:fbdae7e6d805 123 /*@}*/ /* end of group NUC472_442_EMAC_EXPORTED_TYPEDEF */
borlanic 0:fbdae7e6d805 124
borlanic 0:fbdae7e6d805 125 // local variables
borlanic 0:fbdae7e6d805 126 static volatile EMAC_DESCRIPTOR_T rx_desc[EMAC_RX_DESC_SIZE];
borlanic 0:fbdae7e6d805 127 static volatile EMAC_FRAME_T rx_buf[EMAC_RX_DESC_SIZE];
borlanic 0:fbdae7e6d805 128 static volatile EMAC_DESCRIPTOR_T tx_desc[EMAC_TX_DESC_SIZE];
borlanic 0:fbdae7e6d805 129 static volatile EMAC_FRAME_T tx_buf[EMAC_TX_DESC_SIZE];
borlanic 0:fbdae7e6d805 130
borlanic 0:fbdae7e6d805 131
borlanic 0:fbdae7e6d805 132 static uint32_t u32CurrentTxDesc, u32NextTxDesc, u32CurrentRxDesc;
borlanic 0:fbdae7e6d805 133 static uint32_t s_u32EnableTs = 0;
borlanic 0:fbdae7e6d805 134
borlanic 0:fbdae7e6d805 135 /** @addtogroup NUC472_442_EMAC_EXPORTED_FUNCTIONS EMAC Exported Functions
borlanic 0:fbdae7e6d805 136 @{
borlanic 0:fbdae7e6d805 137 */
borlanic 0:fbdae7e6d805 138
borlanic 0:fbdae7e6d805 139 /**
borlanic 0:fbdae7e6d805 140 * @brief Trigger EMAC Rx function
borlanic 0:fbdae7e6d805 141 * @param None
borlanic 0:fbdae7e6d805 142 * @return None
borlanic 0:fbdae7e6d805 143 */
borlanic 0:fbdae7e6d805 144 #define EMAC_TRIGGER_RX() do{EMAC->RXST = 0;}while(0)
borlanic 0:fbdae7e6d805 145
borlanic 0:fbdae7e6d805 146 /**
borlanic 0:fbdae7e6d805 147 * @brief Trigger EMAC Tx function
borlanic 0:fbdae7e6d805 148 * @param None
borlanic 0:fbdae7e6d805 149 * @return None
borlanic 0:fbdae7e6d805 150 */
borlanic 0:fbdae7e6d805 151 #define EMAC_TRIGGER_TX() do{EMAC->TXST = 0;}while(0)
borlanic 0:fbdae7e6d805 152
borlanic 0:fbdae7e6d805 153 /**
borlanic 0:fbdae7e6d805 154 * @brief Write PHY register
borlanic 0:fbdae7e6d805 155 * @param[in] u32Reg PHY register number
borlanic 0:fbdae7e6d805 156 * @param[in] u32Addr PHY address, this address is board dependent
borlanic 0:fbdae7e6d805 157 * @param[in] u32Data data to write to PHY register
borlanic 0:fbdae7e6d805 158 * @return None
borlanic 0:fbdae7e6d805 159 */
borlanic 0:fbdae7e6d805 160 static void EMAC_MdioWrite(uint32_t u32Reg, uint32_t u32Addr, uint32_t u32Data)
borlanic 0:fbdae7e6d805 161 {
borlanic 0:fbdae7e6d805 162 // Set data register
borlanic 0:fbdae7e6d805 163 EMAC->MIIMDAT = u32Data ;
borlanic 0:fbdae7e6d805 164 // Set PHY address, PHY register address, busy bit and write bit
borlanic 0:fbdae7e6d805 165 EMAC->MIIMCTL = u32Reg | (u32Addr << 8) | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_WRITE_Msk | EMAC_MIIMCTL_MDCON_Msk;
borlanic 0:fbdae7e6d805 166 // Wait write complete by polling busy bit.
borlanic 0:fbdae7e6d805 167 while(EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk);
borlanic 0:fbdae7e6d805 168
borlanic 0:fbdae7e6d805 169 }
borlanic 0:fbdae7e6d805 170
borlanic 0:fbdae7e6d805 171 /**
borlanic 0:fbdae7e6d805 172 * @brief Read PHY register
borlanic 0:fbdae7e6d805 173 * @param[in] u32Reg PHY register number
borlanic 0:fbdae7e6d805 174 * @param[in] u32Addr PHY address, this address is board dependent
borlanic 0:fbdae7e6d805 175 * @return Value read from PHY register
borlanic 0:fbdae7e6d805 176 */
borlanic 0:fbdae7e6d805 177 static uint32_t EMAC_MdioRead(uint32_t u32Reg, uint32_t u32Addr)
borlanic 0:fbdae7e6d805 178 {
borlanic 0:fbdae7e6d805 179 // Set PHY address, PHY register address, busy bit
borlanic 0:fbdae7e6d805 180 EMAC->MIIMCTL = u32Reg | (u32Addr << EMAC_MIIMCTL_PHYADDR_Pos) | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk;
borlanic 0:fbdae7e6d805 181 // Wait read complete by polling busy bit
borlanic 0:fbdae7e6d805 182 while(EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk);
borlanic 0:fbdae7e6d805 183 // Get return data
borlanic 0:fbdae7e6d805 184 return EMAC->MIIMDAT;
borlanic 0:fbdae7e6d805 185 }
borlanic 0:fbdae7e6d805 186
borlanic 0:fbdae7e6d805 187
borlanic 0:fbdae7e6d805 188 /**
borlanic 0:fbdae7e6d805 189 * @brief Initialize PHY chip, check for the auto-negotiation result.
borlanic 0:fbdae7e6d805 190 * @param None
borlanic 0:fbdae7e6d805 191 * @return None
borlanic 0:fbdae7e6d805 192 */
borlanic 0:fbdae7e6d805 193 static void EMAC_PhyInit(void)
borlanic 0:fbdae7e6d805 194 {
borlanic 0:fbdae7e6d805 195 uint32_t reg;
borlanic 0:fbdae7e6d805 196
borlanic 0:fbdae7e6d805 197 // Reset Phy Chip
borlanic 0:fbdae7e6d805 198 EMAC_MdioWrite(PHY_CNTL_REG, EMAC_PHY_ADDR, PHY_CNTL_RESET_PHY);
borlanic 0:fbdae7e6d805 199
borlanic 0:fbdae7e6d805 200 // Wait until reset complete
borlanic 0:fbdae7e6d805 201 while (1) {
borlanic 0:fbdae7e6d805 202 reg = EMAC_MdioRead(PHY_CNTL_REG, EMAC_PHY_ADDR) ;
borlanic 0:fbdae7e6d805 203 if ((reg & PHY_CNTL_RESET_PHY)==0)
borlanic 0:fbdae7e6d805 204 break;
borlanic 0:fbdae7e6d805 205 }
borlanic 0:fbdae7e6d805 206
borlanic 0:fbdae7e6d805 207 if(~EMAC_MdioRead(PHY_STATUS_REG, EMAC_PHY_ADDR) && PHY_STATUS_LINK_VALID) { // Cable not connected
borlanic 0:fbdae7e6d805 208 printf("Unplug\n..");
borlanic 0:fbdae7e6d805 209 EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk;
borlanic 0:fbdae7e6d805 210 EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk;
borlanic 0:fbdae7e6d805 211 return;
borlanic 0:fbdae7e6d805 212 }
borlanic 0:fbdae7e6d805 213 // Configure auto negotiation capability
borlanic 0:fbdae7e6d805 214 EMAC_MdioWrite(PHY_ANA_REG, EMAC_PHY_ADDR, PHY_ANA_DR100_TX_FULL |
borlanic 0:fbdae7e6d805 215 PHY_ANA_DR100_TX_HALF |
borlanic 0:fbdae7e6d805 216 PHY_ANA_DR10_TX_FULL |
borlanic 0:fbdae7e6d805 217 PHY_ANA_DR10_TX_HALF |
borlanic 0:fbdae7e6d805 218 PHY_ANA_IEEE_802_3_CSMA_CD);
borlanic 0:fbdae7e6d805 219 // Restart auto negotiation
borlanic 0:fbdae7e6d805 220 EMAC_MdioWrite(PHY_CNTL_REG, EMAC_PHY_ADDR, EMAC_MdioRead(PHY_CNTL_REG, EMAC_PHY_ADDR) | PHY_CNTL_RESTART_AN);
borlanic 0:fbdae7e6d805 221
borlanic 0:fbdae7e6d805 222 // Wait for auto-negotiation complete
borlanic 0:fbdae7e6d805 223 while(!(EMAC_MdioRead(PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_AN_COMPLETE));
borlanic 0:fbdae7e6d805 224
borlanic 0:fbdae7e6d805 225 // Check link valid again. Some PHYs needs to check result after link valid bit set
borlanic 0:fbdae7e6d805 226 while(!(EMAC_MdioRead(PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_LINK_VALID));
borlanic 0:fbdae7e6d805 227
borlanic 0:fbdae7e6d805 228 // Check link partner capability
borlanic 0:fbdae7e6d805 229 reg = EMAC_MdioRead(PHY_ANLPA_REG, EMAC_PHY_ADDR) ;
borlanic 0:fbdae7e6d805 230 if (reg & PHY_ANLPA_DR100_TX_FULL) {
borlanic 0:fbdae7e6d805 231 printf("100F\n");
borlanic 0:fbdae7e6d805 232 EMAC->CTL |= EMAC_CTL_OPMODE_Msk;
borlanic 0:fbdae7e6d805 233 EMAC->CTL |= EMAC_CTL_FUDUP_Msk;
borlanic 0:fbdae7e6d805 234 } else if (reg & PHY_ANLPA_DR100_TX_HALF) {
borlanic 0:fbdae7e6d805 235 printf("100H\n");
borlanic 0:fbdae7e6d805 236 EMAC->CTL |= EMAC_CTL_OPMODE_Msk;
borlanic 0:fbdae7e6d805 237 EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk;
borlanic 0:fbdae7e6d805 238 } else if (reg & PHY_ANLPA_DR10_TX_FULL) {
borlanic 0:fbdae7e6d805 239 printf("10F\n");
borlanic 0:fbdae7e6d805 240 EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk;
borlanic 0:fbdae7e6d805 241 EMAC->CTL |= EMAC_CTL_FUDUP_Msk;
borlanic 0:fbdae7e6d805 242 } else {
borlanic 0:fbdae7e6d805 243 printf("10H\n");
borlanic 0:fbdae7e6d805 244 EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk;
borlanic 0:fbdae7e6d805 245 EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk;
borlanic 0:fbdae7e6d805 246 }
borlanic 0:fbdae7e6d805 247 }
borlanic 0:fbdae7e6d805 248
borlanic 0:fbdae7e6d805 249 /**
borlanic 0:fbdae7e6d805 250 * @brief Initial EMAC Tx descriptors and get Tx descriptor base address
borlanic 0:fbdae7e6d805 251 * @param None
borlanic 0:fbdae7e6d805 252 * @return None
borlanic 0:fbdae7e6d805 253 */
borlanic 0:fbdae7e6d805 254 static void EMAC_TxDescInit(void)
borlanic 0:fbdae7e6d805 255 {
borlanic 0:fbdae7e6d805 256 uint32_t i;
borlanic 0:fbdae7e6d805 257
borlanic 0:fbdae7e6d805 258 // Get Frame descriptor's base address.
borlanic 0:fbdae7e6d805 259 EMAC->TXDSA = (uint32_t)&tx_desc[0];
borlanic 0:fbdae7e6d805 260 u32NextTxDesc = u32CurrentTxDesc = (uint32_t)&tx_desc[0];
borlanic 0:fbdae7e6d805 261
borlanic 0:fbdae7e6d805 262 for(i = 0; i < EMAC_TX_DESC_SIZE; i++) {
borlanic 0:fbdae7e6d805 263
borlanic 0:fbdae7e6d805 264 if(s_u32EnableTs)
borlanic 0:fbdae7e6d805 265 tx_desc[i].u32Status1 = EMAC_TXFD_PADEN | EMAC_TXFD_CRCAPP | EMAC_TXFD_INTEN;
borlanic 0:fbdae7e6d805 266 else
borlanic 0:fbdae7e6d805 267 tx_desc[i].u32Status1 = EMAC_TXFD_PADEN | EMAC_TXFD_CRCAPP | EMAC_TXFD_INTEN | EMAC_TXFD_TTSEN;
borlanic 0:fbdae7e6d805 268
borlanic 0:fbdae7e6d805 269 tx_desc[i].u32Data = (uint32_t)((uint32_t)&tx_buf[i]);
borlanic 0:fbdae7e6d805 270 tx_desc[i].u32Backup1 = tx_desc[i].u32Data;
borlanic 0:fbdae7e6d805 271 tx_desc[i].u32Status2 = 0;
borlanic 0:fbdae7e6d805 272 tx_desc[i].u32Next = (uint32_t)&tx_desc[(i + 1) % EMAC_TX_DESC_SIZE];
borlanic 0:fbdae7e6d805 273 tx_desc[i].u32Backup2 = tx_desc[i].u32Next;
borlanic 0:fbdae7e6d805 274
borlanic 0:fbdae7e6d805 275 }
borlanic 0:fbdae7e6d805 276
borlanic 0:fbdae7e6d805 277 }
borlanic 0:fbdae7e6d805 278
borlanic 0:fbdae7e6d805 279
borlanic 0:fbdae7e6d805 280 /**
borlanic 0:fbdae7e6d805 281 * @brief Initial EMAC Rx descriptors and get Rx descriptor base address
borlanic 0:fbdae7e6d805 282 * @param None
borlanic 0:fbdae7e6d805 283 * @return None
borlanic 0:fbdae7e6d805 284 */
borlanic 0:fbdae7e6d805 285 static void EMAC_RxDescInit(void)
borlanic 0:fbdae7e6d805 286 {
borlanic 0:fbdae7e6d805 287
borlanic 0:fbdae7e6d805 288 uint32_t i;
borlanic 0:fbdae7e6d805 289
borlanic 0:fbdae7e6d805 290 // Get Frame descriptor's base address.
borlanic 0:fbdae7e6d805 291 EMAC->RXDSA = (uint32_t)&rx_desc[0];
borlanic 0:fbdae7e6d805 292 u32CurrentRxDesc = (uint32_t)&rx_desc[0];
borlanic 0:fbdae7e6d805 293
borlanic 0:fbdae7e6d805 294 for(i=0; i < EMAC_RX_DESC_SIZE; i++) {
borlanic 0:fbdae7e6d805 295 rx_desc[i].u32Status1 = EMAC_DESC_OWN_EMAC;
borlanic 0:fbdae7e6d805 296 rx_desc[i].u32Data = (uint32_t)((uint32_t)&rx_buf[i]);
borlanic 0:fbdae7e6d805 297 rx_desc[i].u32Backup1 = rx_desc[i].u32Data;
borlanic 0:fbdae7e6d805 298 rx_desc[i].u32Status2 = 0;
borlanic 0:fbdae7e6d805 299 rx_desc[i].u32Next = (uint32_t)&rx_desc[(i + 1) % EMAC_RX_DESC_SIZE];
borlanic 0:fbdae7e6d805 300 rx_desc[i].u32Backup2 = rx_desc[i].u32Next;
borlanic 0:fbdae7e6d805 301 }
borlanic 0:fbdae7e6d805 302
borlanic 0:fbdae7e6d805 303 }
borlanic 0:fbdae7e6d805 304
borlanic 0:fbdae7e6d805 305 /**
borlanic 0:fbdae7e6d805 306 * @brief Convert subsecond value to nano second
borlanic 0:fbdae7e6d805 307 * @param[in] subsec Subsecond value to be convert
borlanic 0:fbdae7e6d805 308 * @return Nano second
borlanic 0:fbdae7e6d805 309 */
borlanic 0:fbdae7e6d805 310 static uint32_t EMAC_Subsec2Nsec(uint32_t subsec)
borlanic 0:fbdae7e6d805 311 {
borlanic 0:fbdae7e6d805 312 // 2^31 subsec == 10^9 ns
borlanic 0:fbdae7e6d805 313 uint64_t i;
borlanic 0:fbdae7e6d805 314 i = 1000000000ll * subsec;
borlanic 0:fbdae7e6d805 315 i >>= 31;
borlanic 0:fbdae7e6d805 316 return(i);
borlanic 0:fbdae7e6d805 317 }
borlanic 0:fbdae7e6d805 318
borlanic 0:fbdae7e6d805 319 /**
borlanic 0:fbdae7e6d805 320 * @brief Convert nano second to subsecond value
borlanic 0:fbdae7e6d805 321 * @param[in] nsec Nano second to be convert
borlanic 0:fbdae7e6d805 322 * @return Subsecond
borlanic 0:fbdae7e6d805 323 */
borlanic 0:fbdae7e6d805 324 static uint32_t EMAC_Nsec2Subsec(uint32_t nsec)
borlanic 0:fbdae7e6d805 325 {
borlanic 0:fbdae7e6d805 326 // 10^9 ns = 2^31 subsec
borlanic 0:fbdae7e6d805 327 uint64_t i;
borlanic 0:fbdae7e6d805 328 i = (1ll << 31) * nsec;
borlanic 0:fbdae7e6d805 329 i /= 1000000000;
borlanic 0:fbdae7e6d805 330 return(i);
borlanic 0:fbdae7e6d805 331 }
borlanic 0:fbdae7e6d805 332
borlanic 0:fbdae7e6d805 333
borlanic 0:fbdae7e6d805 334 /*@}*/ /* end of group NUC472_442_EMAC_EXPORTED_FUNCTIONS */
borlanic 0:fbdae7e6d805 335
borlanic 0:fbdae7e6d805 336
borlanic 0:fbdae7e6d805 337
borlanic 0:fbdae7e6d805 338 /// @endcond HIDDEN_SYMBOLS
borlanic 0:fbdae7e6d805 339
borlanic 0:fbdae7e6d805 340
borlanic 0:fbdae7e6d805 341 /** @addtogroup NUC472_442_EMAC_EXPORTED_FUNCTIONS EMAC Exported Functions
borlanic 0:fbdae7e6d805 342 @{
borlanic 0:fbdae7e6d805 343 */
borlanic 0:fbdae7e6d805 344
borlanic 0:fbdae7e6d805 345
borlanic 0:fbdae7e6d805 346 // Basic configuration functions
borlanic 0:fbdae7e6d805 347 /**
borlanic 0:fbdae7e6d805 348 * @brief Initialize EMAC interface, including descriptors, MAC address, and PHY.
borlanic 0:fbdae7e6d805 349 * @param[in] pu8MacAddr Pointer to uint8_t array holds MAC address
borlanic 0:fbdae7e6d805 350 * @return None
borlanic 0:fbdae7e6d805 351 * @note This API sets EMAC to work in RMII mode, but could configure to MII mode later with \ref EMAC_ENABLE_MII_INTF macro
borlanic 0:fbdae7e6d805 352 * @note This API configures EMAC to receive all broadcast and multicast packets, but could configure to other settings with
borlanic 0:fbdae7e6d805 353 * \ref EMAC_ENABLE_RECV_BCASTPKT, \ref EMAC_DISABLE_RECV_BCASTPKT, \ref EMAC_ENABLE_RECV_MCASTPKT, and \ref EMAC_DISABLE_RECV_MCASTPKT
borlanic 0:fbdae7e6d805 354 * @note Receive(RX) and transmit(TX) are not enabled yet, application must call \ref EMAC_ENABLE_RX and \ref EMAC_ENABLE_TX to
borlanic 0:fbdae7e6d805 355 * enable receive and transmit function.
borlanic 0:fbdae7e6d805 356 */
borlanic 0:fbdae7e6d805 357 void EMAC_Open(uint8_t *pu8MacAddr)
borlanic 0:fbdae7e6d805 358 {
borlanic 0:fbdae7e6d805 359 // Enable transmit and receive descriptor
borlanic 0:fbdae7e6d805 360 EMAC_TxDescInit();
borlanic 0:fbdae7e6d805 361 EMAC_RxDescInit();
borlanic 0:fbdae7e6d805 362
borlanic 0:fbdae7e6d805 363 // Set the CAM Control register and the MAC address value
borlanic 0:fbdae7e6d805 364 EMAC_SetMacAddr(pu8MacAddr);
borlanic 0:fbdae7e6d805 365
borlanic 0:fbdae7e6d805 366 // Configure the MAC interrupt enable register.
borlanic 0:fbdae7e6d805 367 EMAC->INTEN = EMAC_INTEN_RXIEN_Msk |
borlanic 0:fbdae7e6d805 368 EMAC_INTEN_TXIEN_Msk |
borlanic 0:fbdae7e6d805 369 EMAC_INTEN_RXGDIEN_Msk |
borlanic 0:fbdae7e6d805 370 EMAC_INTEN_TXCPIEN_Msk |
borlanic 0:fbdae7e6d805 371 EMAC_INTEN_RXBEIEN_Msk |
borlanic 0:fbdae7e6d805 372 EMAC_INTEN_TXBEIEN_Msk |
borlanic 0:fbdae7e6d805 373 EMAC_INTEN_RDUIEN_Msk |
borlanic 0:fbdae7e6d805 374 EMAC_INTEN_TSALMIEN_Msk |
borlanic 0:fbdae7e6d805 375 EMAC_INTEN_WOLIEN_Msk;
borlanic 0:fbdae7e6d805 376
borlanic 0:fbdae7e6d805 377 // Configure the MAC control register.
borlanic 0:fbdae7e6d805 378 EMAC->CTL = EMAC_CTL_STRIPCRC_Msk |
borlanic 0:fbdae7e6d805 379 EMAC_CTL_RMIIEN_Msk |
borlanic 0:fbdae7e6d805 380 EMAC_CTL_RMIIRXCTL_Msk;
borlanic 0:fbdae7e6d805 381
borlanic 0:fbdae7e6d805 382 //Accept packets for us and all broadcast and multicast packets
borlanic 0:fbdae7e6d805 383 EMAC->CAMCTL = EMAC_CAMCTL_CMPEN_Msk |
borlanic 0:fbdae7e6d805 384 EMAC_CAMCTL_AMP_Msk |
borlanic 0:fbdae7e6d805 385 EMAC_CAMCTL_ABP_Msk;
borlanic 0:fbdae7e6d805 386
borlanic 0:fbdae7e6d805 387 EMAC_PhyInit();
borlanic 0:fbdae7e6d805 388 }
borlanic 0:fbdae7e6d805 389
borlanic 0:fbdae7e6d805 390 /**
borlanic 0:fbdae7e6d805 391 * @brief This function stop all receive and transmit activity and disable MAC interface
borlanic 0:fbdae7e6d805 392 * @param None
borlanic 0:fbdae7e6d805 393 * @return None
borlanic 0:fbdae7e6d805 394 */
borlanic 0:fbdae7e6d805 395
borlanic 0:fbdae7e6d805 396 void EMAC_Close(void)
borlanic 0:fbdae7e6d805 397 {
borlanic 0:fbdae7e6d805 398 EMAC->CTL |= EMAC_CTL_RST_Msk;
borlanic 0:fbdae7e6d805 399 }
borlanic 0:fbdae7e6d805 400
borlanic 0:fbdae7e6d805 401 /**
borlanic 0:fbdae7e6d805 402 * @brief Set the device MAC address
borlanic 0:fbdae7e6d805 403 * @param[in] pu8MacAddr Pointer to uint8_t array holds MAC address
borlanic 0:fbdae7e6d805 404 * @return None
borlanic 0:fbdae7e6d805 405 */
borlanic 0:fbdae7e6d805 406 void EMAC_SetMacAddr(uint8_t *pu8MacAddr)
borlanic 0:fbdae7e6d805 407 {
borlanic 0:fbdae7e6d805 408 EMAC_EnableCamEntry(0, pu8MacAddr);
borlanic 0:fbdae7e6d805 409
borlanic 0:fbdae7e6d805 410 }
borlanic 0:fbdae7e6d805 411
borlanic 0:fbdae7e6d805 412 /**
borlanic 0:fbdae7e6d805 413 * @brief Fill a CAM entry for MAC address comparison.
borlanic 0:fbdae7e6d805 414 * @param[in] u32Entry MAC entry to fill. Entry 0 is used to store device MAC address, do not overwrite the setting in it.
borlanic 0:fbdae7e6d805 415 * @param[in] pu8MacAddr Pointer to uint8_t array holds MAC address
borlanic 0:fbdae7e6d805 416 * @return None
borlanic 0:fbdae7e6d805 417 */
borlanic 0:fbdae7e6d805 418 void EMAC_EnableCamEntry(uint32_t u32Entry, uint8_t *pu8MacAddr)
borlanic 0:fbdae7e6d805 419 {
borlanic 0:fbdae7e6d805 420 uint32_t u32Lsw, u32Msw;
borlanic 0:fbdae7e6d805 421
borlanic 0:fbdae7e6d805 422 u32Lsw = (pu8MacAddr[4] << 24) |
borlanic 0:fbdae7e6d805 423 (pu8MacAddr[5] << 16);
borlanic 0:fbdae7e6d805 424 u32Msw = (pu8MacAddr[0] << 24)|
borlanic 0:fbdae7e6d805 425 (pu8MacAddr[1] << 16)|
borlanic 0:fbdae7e6d805 426 (pu8MacAddr[2] << 8)|
borlanic 0:fbdae7e6d805 427 pu8MacAddr[3];
borlanic 0:fbdae7e6d805 428
borlanic 0:fbdae7e6d805 429 *(uint32_t volatile *)(&EMAC->CAM0M + u32Entry * 4) = u32Msw;
borlanic 0:fbdae7e6d805 430 *(uint32_t volatile *)(&EMAC->CAM0L + u32Entry * 4) = u32Lsw;
borlanic 0:fbdae7e6d805 431
borlanic 0:fbdae7e6d805 432 EMAC->CAMEN |= (1 << u32Entry);
borlanic 0:fbdae7e6d805 433 }
borlanic 0:fbdae7e6d805 434
borlanic 0:fbdae7e6d805 435 /**
borlanic 0:fbdae7e6d805 436 * @brief Disable a specified CAM entry
borlanic 0:fbdae7e6d805 437 * @param[in] u32Entry CAM entry to be disabled
borlanic 0:fbdae7e6d805 438 * @return None
borlanic 0:fbdae7e6d805 439 */
borlanic 0:fbdae7e6d805 440 void EMAC_DisableCamEntry(uint32_t u32Entry)
borlanic 0:fbdae7e6d805 441 {
borlanic 0:fbdae7e6d805 442 EMAC->CAMEN &= ~(1 << u32Entry);
borlanic 0:fbdae7e6d805 443 }
borlanic 0:fbdae7e6d805 444
borlanic 0:fbdae7e6d805 445 // Receive functions
borlanic 0:fbdae7e6d805 446 /**
borlanic 0:fbdae7e6d805 447 * @brief Receive an Ethernet packet
borlanic 0:fbdae7e6d805 448 * @param[in] pu8Data Pointer to a buffer to store received packet (4 byte CRC removed)
borlanic 0:fbdae7e6d805 449 * @param[in] pu32Size Received packet size (without 4 byte CRC).
borlanic 0:fbdae7e6d805 450 * @return Packet receive success or not
borlanic 0:fbdae7e6d805 451 * @retval 0 No packet available for receive
borlanic 0:fbdae7e6d805 452 * @retval 1 A packet is received
borlanic 0:fbdae7e6d805 453 * @note Return 0 doesn't guarantee the packet will be sent and received successfully.
borlanic 0:fbdae7e6d805 454 */
borlanic 0:fbdae7e6d805 455 uint32_t EMAC_RecvPkt(uint8_t *pu8Data, uint32_t *pu32Size)
borlanic 0:fbdae7e6d805 456 {
borlanic 0:fbdae7e6d805 457 EMAC_DESCRIPTOR_T *desc;
borlanic 0:fbdae7e6d805 458 uint32_t status, reg;
borlanic 0:fbdae7e6d805 459 uint32_t u32Count = 0;
borlanic 0:fbdae7e6d805 460
borlanic 0:fbdae7e6d805 461 // Clear Rx interrupt flags
borlanic 0:fbdae7e6d805 462 reg = EMAC->INTSTS;
borlanic 0:fbdae7e6d805 463 EMAC->INTSTS = reg & 0xFFFF; // Clear all RX related interrupt status
borlanic 0:fbdae7e6d805 464
borlanic 0:fbdae7e6d805 465 if (reg & EMAC_INTSTS_RXBEIF_Msk) {
borlanic 0:fbdae7e6d805 466 // Bus error occurred, this is usually a bad sign about software bug and will occur again...
borlanic 0:fbdae7e6d805 467 printf("RX bus error\n");
borlanic 0:fbdae7e6d805 468 } else {
borlanic 0:fbdae7e6d805 469
borlanic 0:fbdae7e6d805 470 // Get Rx Frame Descriptor
borlanic 0:fbdae7e6d805 471 desc = (EMAC_DESCRIPTOR_T *)u32CurrentRxDesc;
borlanic 0:fbdae7e6d805 472
borlanic 0:fbdae7e6d805 473 // If we reach last recv Rx descriptor, leave the loop
borlanic 0:fbdae7e6d805 474 if(EMAC->CRXDSA == (uint32_t)desc)
borlanic 0:fbdae7e6d805 475 return(0);
borlanic 0:fbdae7e6d805 476 if ((desc->u32Status1 | EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) { // ownership=CPU
borlanic 0:fbdae7e6d805 477
borlanic 0:fbdae7e6d805 478 status = desc->u32Status1 >> 16;
borlanic 0:fbdae7e6d805 479
borlanic 0:fbdae7e6d805 480 // If Rx frame is good, process received frame
borlanic 0:fbdae7e6d805 481 if(status & EMAC_RXFD_RXGD) {
borlanic 0:fbdae7e6d805 482 // lower 16 bit in descriptor status1 stores the Rx packet length
borlanic 0:fbdae7e6d805 483 *pu32Size = desc->u32Status1 & 0xffff;
borlanic 0:fbdae7e6d805 484 memcpy(pu8Data, (uint8_t *)desc->u32Backup1, *pu32Size);
borlanic 0:fbdae7e6d805 485 u32Count = 1;
borlanic 0:fbdae7e6d805 486 } else {
borlanic 0:fbdae7e6d805 487 // Save Error status if necessary
borlanic 0:fbdae7e6d805 488 if (status & EMAC_RXFD_RP) {;}
borlanic 0:fbdae7e6d805 489 if (status & EMAC_RXFD_ALIE) {;}
borlanic 0:fbdae7e6d805 490 if (status & EMAC_RXFD_PTLE) {;}
borlanic 0:fbdae7e6d805 491 if (status & EMAC_RXFD_CRCE) {;}
borlanic 0:fbdae7e6d805 492 }
borlanic 0:fbdae7e6d805 493 }
borlanic 0:fbdae7e6d805 494 }
borlanic 0:fbdae7e6d805 495 return(u32Count);
borlanic 0:fbdae7e6d805 496 }
borlanic 0:fbdae7e6d805 497
borlanic 0:fbdae7e6d805 498 /**
borlanic 0:fbdae7e6d805 499 * @brief Receive an Ethernet packet and the time stamp while it's received
borlanic 0:fbdae7e6d805 500 * @param[out] pu8Data Pointer to a buffer to store received packet (4 byte CRC removed)
borlanic 0:fbdae7e6d805 501 * @param[out] pu32Size Received packet size (without 4 byte CRC).
borlanic 0:fbdae7e6d805 502 * @param[out] pu32Sec Second value while packet sent
borlanic 0:fbdae7e6d805 503 * @param[out] pu32Nsec Nano second value while packet sent
borlanic 0:fbdae7e6d805 504 * @return Packet receive success or not
borlanic 0:fbdae7e6d805 505 * @retval 0 No packet available for receive
borlanic 0:fbdae7e6d805 506 * @retval 1 A packet is received
borlanic 0:fbdae7e6d805 507 * @note Return 0 doesn't guarantee the packet will be sent and received successfully.
borlanic 0:fbdae7e6d805 508 * @note Largest Ethernet packet is 1514 bytes after stripped CRC, application must give
borlanic 0:fbdae7e6d805 509 * a buffer large enough to store such packet
borlanic 0:fbdae7e6d805 510 */
borlanic 0:fbdae7e6d805 511 uint32_t EMAC_RecvPktTS(uint8_t *pu8Data, uint32_t *pu32Size, uint32_t *pu32Sec, uint32_t *pu32Nsec)
borlanic 0:fbdae7e6d805 512 {
borlanic 0:fbdae7e6d805 513 EMAC_DESCRIPTOR_T *desc;
borlanic 0:fbdae7e6d805 514 uint32_t status, reg;
borlanic 0:fbdae7e6d805 515 uint32_t u32Count = 0;
borlanic 0:fbdae7e6d805 516
borlanic 0:fbdae7e6d805 517 // Clear Rx interrupt flags
borlanic 0:fbdae7e6d805 518 reg = EMAC->INTSTS;
borlanic 0:fbdae7e6d805 519 EMAC->INTSTS = reg & 0xFFFF; // Clear all Rx related interrupt status
borlanic 0:fbdae7e6d805 520
borlanic 0:fbdae7e6d805 521 if (reg & EMAC_INTSTS_RXBEIF_Msk) {
borlanic 0:fbdae7e6d805 522 // Bus error occurred, this is usually a bad sign about software bug and will occur again...
borlanic 0:fbdae7e6d805 523 printf("RX bus error\n");
borlanic 0:fbdae7e6d805 524 } else {
borlanic 0:fbdae7e6d805 525
borlanic 0:fbdae7e6d805 526 // Get Rx Frame Descriptor
borlanic 0:fbdae7e6d805 527 desc = (EMAC_DESCRIPTOR_T *)u32CurrentRxDesc;
borlanic 0:fbdae7e6d805 528
borlanic 0:fbdae7e6d805 529 // If we reach last recv Rx descriptor, leave the loop
borlanic 0:fbdae7e6d805 530 if(EMAC->CRXDSA == (uint32_t)desc)
borlanic 0:fbdae7e6d805 531 return(0);
borlanic 0:fbdae7e6d805 532 if ((desc->u32Status1 | EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) { // ownership=CPU
borlanic 0:fbdae7e6d805 533
borlanic 0:fbdae7e6d805 534 status = desc->u32Status1 >> 16;
borlanic 0:fbdae7e6d805 535
borlanic 0:fbdae7e6d805 536 // If Rx frame is good, process received frame
borlanic 0:fbdae7e6d805 537 if(status & EMAC_RXFD_RXGD) {
borlanic 0:fbdae7e6d805 538 // lower 16 bit in descriptor status1 stores the Rx packet length
borlanic 0:fbdae7e6d805 539 *pu32Size = desc->u32Status1 & 0xffff;
borlanic 0:fbdae7e6d805 540 memcpy(pu8Data, (uint8_t *)desc->u32Backup1, *pu32Size);
borlanic 0:fbdae7e6d805 541
borlanic 0:fbdae7e6d805 542 *pu32Sec = desc->u32Next; // second stores in descriptor's NEXT field
borlanic 0:fbdae7e6d805 543 *pu32Nsec = EMAC_Subsec2Nsec(desc->u32Data); // Sub nano second store in DATA field
borlanic 0:fbdae7e6d805 544
borlanic 0:fbdae7e6d805 545 u32Count = 1;
borlanic 0:fbdae7e6d805 546 } else {
borlanic 0:fbdae7e6d805 547 // Save Error status if necessary
borlanic 0:fbdae7e6d805 548 if (status & EMAC_RXFD_RP) {;}
borlanic 0:fbdae7e6d805 549 if (status & EMAC_RXFD_ALIE) {;}
borlanic 0:fbdae7e6d805 550 if (status & EMAC_RXFD_PTLE) {;}
borlanic 0:fbdae7e6d805 551 if (status & EMAC_RXFD_CRCE) {;}
borlanic 0:fbdae7e6d805 552 }
borlanic 0:fbdae7e6d805 553 }
borlanic 0:fbdae7e6d805 554 }
borlanic 0:fbdae7e6d805 555 return(u32Count);
borlanic 0:fbdae7e6d805 556 }
borlanic 0:fbdae7e6d805 557
borlanic 0:fbdae7e6d805 558 /**
borlanic 0:fbdae7e6d805 559 * @brief Clean up process after a packet is received
borlanic 0:fbdae7e6d805 560 * @param None
borlanic 0:fbdae7e6d805 561 * @return None
borlanic 0:fbdae7e6d805 562 * @details EMAC Rx interrupt service routine \b must call this API to release the resource use by receive process
borlanic 0:fbdae7e6d805 563 * @note Application can only call this function once every time \ref EMAC_RecvPkt or \ref EMAC_RecvPktTS returns 1
borlanic 0:fbdae7e6d805 564 */
borlanic 0:fbdae7e6d805 565 void EMAC_RecvPktDone(void)
borlanic 0:fbdae7e6d805 566 {
borlanic 0:fbdae7e6d805 567 EMAC_DESCRIPTOR_T *desc;
borlanic 0:fbdae7e6d805 568 // Get Rx Frame Descriptor
borlanic 0:fbdae7e6d805 569 desc = (EMAC_DESCRIPTOR_T *)u32CurrentRxDesc;
borlanic 0:fbdae7e6d805 570
borlanic 0:fbdae7e6d805 571 // restore descriptor link list and data pointer they will be overwrite if time stamp enabled
borlanic 0:fbdae7e6d805 572 desc->u32Data = desc->u32Backup1;
borlanic 0:fbdae7e6d805 573 desc->u32Next = desc->u32Backup2;
borlanic 0:fbdae7e6d805 574
borlanic 0:fbdae7e6d805 575 // Change ownership to DMA for next use
borlanic 0:fbdae7e6d805 576 desc->u32Status1 |= EMAC_DESC_OWN_EMAC;
borlanic 0:fbdae7e6d805 577
borlanic 0:fbdae7e6d805 578 // Get Next Frame Descriptor pointer to process
borlanic 0:fbdae7e6d805 579 desc = (EMAC_DESCRIPTOR_T *)desc->u32Next;
borlanic 0:fbdae7e6d805 580
borlanic 0:fbdae7e6d805 581 // Save last processed Rx descriptor
borlanic 0:fbdae7e6d805 582 u32CurrentRxDesc = (uint32_t)desc;
borlanic 0:fbdae7e6d805 583
borlanic 0:fbdae7e6d805 584 EMAC_TRIGGER_RX();
borlanic 0:fbdae7e6d805 585 }
borlanic 0:fbdae7e6d805 586
borlanic 0:fbdae7e6d805 587 // Transmit functions
borlanic 0:fbdae7e6d805 588
borlanic 0:fbdae7e6d805 589 /**
borlanic 0:fbdae7e6d805 590 * @brief Send an Ethernet packet
borlanic 0:fbdae7e6d805 591 * @param[in] pu8Data Pointer to a buffer holds the packet to transmit
borlanic 0:fbdae7e6d805 592 * @param[in] u32Size Packet size (without 4 byte CRC).
borlanic 0:fbdae7e6d805 593 * @return Packet transmit success or not
borlanic 0:fbdae7e6d805 594 * @retval 0 Transmit failed due to descriptor unavailable.
borlanic 0:fbdae7e6d805 595 * @retval 1 Packet is copied to descriptor and triggered to transmit.
borlanic 0:fbdae7e6d805 596 * @note Return 1 doesn't guarantee the packet will be sent and received successfully.
borlanic 0:fbdae7e6d805 597 */
borlanic 0:fbdae7e6d805 598 uint32_t EMAC_SendPkt(uint8_t *pu8Data, uint32_t u32Size)
borlanic 0:fbdae7e6d805 599 {
borlanic 0:fbdae7e6d805 600 EMAC_DESCRIPTOR_T *desc;
borlanic 0:fbdae7e6d805 601 uint32_t status;
borlanic 0:fbdae7e6d805 602
borlanic 0:fbdae7e6d805 603 // Get Tx frame descriptor & data pointer
borlanic 0:fbdae7e6d805 604 desc = (EMAC_DESCRIPTOR_T *)u32NextTxDesc;
borlanic 0:fbdae7e6d805 605
borlanic 0:fbdae7e6d805 606 status = desc->u32Status1;
borlanic 0:fbdae7e6d805 607
borlanic 0:fbdae7e6d805 608 // Check descriptor ownership
borlanic 0:fbdae7e6d805 609 if((status & EMAC_DESC_OWN_EMAC))
borlanic 0:fbdae7e6d805 610 return(0);
borlanic 0:fbdae7e6d805 611
borlanic 0:fbdae7e6d805 612 memcpy((uint8_t *)desc->u32Data, pu8Data, u32Size);
borlanic 0:fbdae7e6d805 613
borlanic 0:fbdae7e6d805 614 // Set Tx descriptor transmit byte count
borlanic 0:fbdae7e6d805 615 desc->u32Status2 = u32Size;
borlanic 0:fbdae7e6d805 616
borlanic 0:fbdae7e6d805 617 // Change descriptor ownership to EMAC
borlanic 0:fbdae7e6d805 618 desc->u32Status1 |= EMAC_DESC_OWN_EMAC;
borlanic 0:fbdae7e6d805 619
borlanic 0:fbdae7e6d805 620 // Get next Tx descriptor
borlanic 0:fbdae7e6d805 621 u32NextTxDesc = (uint32_t)(desc->u32Next);
borlanic 0:fbdae7e6d805 622
borlanic 0:fbdae7e6d805 623 // Trigger EMAC to send the packet
borlanic 0:fbdae7e6d805 624 EMAC_TRIGGER_TX();
borlanic 0:fbdae7e6d805 625
borlanic 0:fbdae7e6d805 626 return(1);
borlanic 0:fbdae7e6d805 627 }
borlanic 0:fbdae7e6d805 628
borlanic 0:fbdae7e6d805 629
borlanic 0:fbdae7e6d805 630 /**
borlanic 0:fbdae7e6d805 631 * @brief Clean up process after packet(s) are sent
borlanic 0:fbdae7e6d805 632 * @param None
borlanic 0:fbdae7e6d805 633 * @return Number of packet sent between two function calls
borlanic 0:fbdae7e6d805 634 * @details EMAC Tx interrupt service routine \b must call this API or \ref EMAC_SendPktDoneTS to
borlanic 0:fbdae7e6d805 635 * release the resource use by transmit process
borlanic 0:fbdae7e6d805 636 */
borlanic 0:fbdae7e6d805 637 uint32_t EMAC_SendPktDone(void)
borlanic 0:fbdae7e6d805 638 {
borlanic 0:fbdae7e6d805 639 EMAC_DESCRIPTOR_T *desc;
borlanic 0:fbdae7e6d805 640 uint32_t status, reg;
borlanic 0:fbdae7e6d805 641 uint32_t last_tx_desc;
borlanic 0:fbdae7e6d805 642 uint32_t u32Count = 0;
borlanic 0:fbdae7e6d805 643
borlanic 0:fbdae7e6d805 644 reg = EMAC->INTSTS;
borlanic 0:fbdae7e6d805 645 // Clear Tx interrupt flags
borlanic 0:fbdae7e6d805 646 EMAC->INTSTS = reg & (0xFFFF0000 & ~EMAC_INTSTS_TSALMIF_Msk);
borlanic 0:fbdae7e6d805 647
borlanic 0:fbdae7e6d805 648
borlanic 0:fbdae7e6d805 649 if (reg & EMAC_INTSTS_TXBEIF_Msk) {
borlanic 0:fbdae7e6d805 650 // Bus error occurred, this is usually a bad sign about software bug and will occur again...
borlanic 0:fbdae7e6d805 651 printf("TX bus error\n");
borlanic 0:fbdae7e6d805 652 } else {
borlanic 0:fbdae7e6d805 653 // Process the descriptor(s).
borlanic 0:fbdae7e6d805 654 last_tx_desc = EMAC->CTXDSA ;
borlanic 0:fbdae7e6d805 655 // Get our first descriptor to process
borlanic 0:fbdae7e6d805 656 desc = (EMAC_DESCRIPTOR_T *) u32CurrentTxDesc;
borlanic 0:fbdae7e6d805 657 do {
borlanic 0:fbdae7e6d805 658 // Descriptor ownership is still EMAC, so this packet haven't been send.
borlanic 0:fbdae7e6d805 659 if(desc->u32Status1 & EMAC_DESC_OWN_EMAC)
borlanic 0:fbdae7e6d805 660 break;
borlanic 0:fbdae7e6d805 661 // Get Tx status stored in descriptor
borlanic 0:fbdae7e6d805 662 status = desc->u32Status2 >> 16;
borlanic 0:fbdae7e6d805 663 if (status & EMAC_TXFD_TXCP) {
borlanic 0:fbdae7e6d805 664 u32Count++;
borlanic 0:fbdae7e6d805 665 } else {
borlanic 0:fbdae7e6d805 666 // Do nothing here on error.
borlanic 0:fbdae7e6d805 667 if (status & EMAC_TXFD_TXABT) {;}
borlanic 0:fbdae7e6d805 668 if (status & EMAC_TXFD_DEF) {;}
borlanic 0:fbdae7e6d805 669 if (status & EMAC_TXFD_PAU) {;}
borlanic 0:fbdae7e6d805 670 if (status & EMAC_TXFD_EXDEF) {;}
borlanic 0:fbdae7e6d805 671 if (status & EMAC_TXFD_NCS) {;}
borlanic 0:fbdae7e6d805 672 if (status & EMAC_TXFD_SQE) {;}
borlanic 0:fbdae7e6d805 673 if (status & EMAC_TXFD_LC) {;}
borlanic 0:fbdae7e6d805 674 if (status & EMAC_TXFD_TXHA) {;}
borlanic 0:fbdae7e6d805 675 }
borlanic 0:fbdae7e6d805 676
borlanic 0:fbdae7e6d805 677 // restore descriptor link list and data pointer they will be overwrite if time stamp enabled
borlanic 0:fbdae7e6d805 678 desc->u32Data = desc->u32Backup1;
borlanic 0:fbdae7e6d805 679 desc->u32Next = desc->u32Backup2;
borlanic 0:fbdae7e6d805 680 // go to next descriptor in link
borlanic 0:fbdae7e6d805 681 desc = (EMAC_DESCRIPTOR_T *)desc->u32Next;
borlanic 0:fbdae7e6d805 682 } while (last_tx_desc != (uint32_t)desc); // If we reach last sent Tx descriptor, leave the loop
borlanic 0:fbdae7e6d805 683 // Save last processed Tx descriptor
borlanic 0:fbdae7e6d805 684 u32CurrentTxDesc = (uint32_t)desc;
borlanic 0:fbdae7e6d805 685 }
borlanic 0:fbdae7e6d805 686 return(u32Count);
borlanic 0:fbdae7e6d805 687 }
borlanic 0:fbdae7e6d805 688
borlanic 0:fbdae7e6d805 689 /**
borlanic 0:fbdae7e6d805 690 * @brief Clean up process after a packet is sent, and get the time stamp while packet is sent
borlanic 0:fbdae7e6d805 691 * @param[in] pu32Sec Second value while packet sent
borlanic 0:fbdae7e6d805 692 * @param[in] pu32Nsec Nano second value while packet sent
borlanic 0:fbdae7e6d805 693 * @return If a packet sent successfully
borlanic 0:fbdae7e6d805 694 * @retval 0 No packet sent successfully, and the value in *pu32Sec and *pu32Nsec are meaningless
borlanic 0:fbdae7e6d805 695 * @retval 1 A packet sent successfully, and the value in *pu32Sec and *pu32Nsec is the time stamp while packet sent
borlanic 0:fbdae7e6d805 696 * @details EMAC Tx interrupt service routine \b must call this API or \ref EMAC_SendPktDone to
borlanic 0:fbdae7e6d805 697 * release the resource use by transmit process
borlanic 0:fbdae7e6d805 698 */
borlanic 0:fbdae7e6d805 699 uint32_t EMAC_SendPktDoneTS(uint32_t *pu32Sec, uint32_t *pu32Nsec)
borlanic 0:fbdae7e6d805 700 {
borlanic 0:fbdae7e6d805 701
borlanic 0:fbdae7e6d805 702 EMAC_DESCRIPTOR_T *desc;
borlanic 0:fbdae7e6d805 703 uint32_t status, reg;
borlanic 0:fbdae7e6d805 704 uint32_t u32Count = 0;
borlanic 0:fbdae7e6d805 705
borlanic 0:fbdae7e6d805 706 reg = EMAC->INTSTS;
borlanic 0:fbdae7e6d805 707 // Clear Tx interrupt flags
borlanic 0:fbdae7e6d805 708 EMAC->INTSTS = reg & (0xFFFF0000 & ~EMAC_INTSTS_TSALMIF_Msk);
borlanic 0:fbdae7e6d805 709
borlanic 0:fbdae7e6d805 710
borlanic 0:fbdae7e6d805 711 if (reg & EMAC_INTSTS_TXBEIF_Msk) {
borlanic 0:fbdae7e6d805 712 // Bus error occurred, this is usually a bad sign about software bug and will occur again...
borlanic 0:fbdae7e6d805 713 printf("TX bus error\n");
borlanic 0:fbdae7e6d805 714 } else {
borlanic 0:fbdae7e6d805 715 // Process the descriptor.
borlanic 0:fbdae7e6d805 716 // Get our first descriptor to process
borlanic 0:fbdae7e6d805 717 desc = (EMAC_DESCRIPTOR_T *) u32CurrentTxDesc;
borlanic 0:fbdae7e6d805 718
borlanic 0:fbdae7e6d805 719 // Descriptor ownership is still EMAC, so this packet haven't been send.
borlanic 0:fbdae7e6d805 720 if(desc->u32Status1 & EMAC_DESC_OWN_EMAC)
borlanic 0:fbdae7e6d805 721 return(0);
borlanic 0:fbdae7e6d805 722 // Get Tx status stored in descriptor
borlanic 0:fbdae7e6d805 723 status = desc->u32Status2 >> 16;
borlanic 0:fbdae7e6d805 724 if (status & EMAC_TXFD_TXCP) {
borlanic 0:fbdae7e6d805 725 u32Count = 1;
borlanic 0:fbdae7e6d805 726 *pu32Sec = desc->u32Next; // second stores in descriptor's NEXT field
borlanic 0:fbdae7e6d805 727 *pu32Nsec = EMAC_Subsec2Nsec(desc->u32Data); // Sub nano second store in DATA field
borlanic 0:fbdae7e6d805 728 } else {
borlanic 0:fbdae7e6d805 729 // Do nothing here on error.
borlanic 0:fbdae7e6d805 730 if (status & EMAC_TXFD_TXABT) {;}
borlanic 0:fbdae7e6d805 731 if (status & EMAC_TXFD_DEF) {;}
borlanic 0:fbdae7e6d805 732 if (status & EMAC_TXFD_PAU) {;}
borlanic 0:fbdae7e6d805 733 if (status & EMAC_TXFD_EXDEF) {;}
borlanic 0:fbdae7e6d805 734 if (status & EMAC_TXFD_NCS) {;}
borlanic 0:fbdae7e6d805 735 if (status & EMAC_TXFD_SQE) {;}
borlanic 0:fbdae7e6d805 736 if (status & EMAC_TXFD_LC) {;}
borlanic 0:fbdae7e6d805 737 if (status & EMAC_TXFD_TXHA) {;}
borlanic 0:fbdae7e6d805 738 }
borlanic 0:fbdae7e6d805 739
borlanic 0:fbdae7e6d805 740 // restore descriptor link list and data pointer they will be overwrite if time stamp enabled
borlanic 0:fbdae7e6d805 741 desc->u32Data = desc->u32Backup1;
borlanic 0:fbdae7e6d805 742 desc->u32Next = desc->u32Backup2;
borlanic 0:fbdae7e6d805 743 // go to next descriptor in link
borlanic 0:fbdae7e6d805 744 desc = (EMAC_DESCRIPTOR_T *)desc->u32Next;
borlanic 0:fbdae7e6d805 745
borlanic 0:fbdae7e6d805 746 // Save last processed Tx descriptor
borlanic 0:fbdae7e6d805 747 u32CurrentTxDesc = (uint32_t)desc;
borlanic 0:fbdae7e6d805 748 }
borlanic 0:fbdae7e6d805 749
borlanic 0:fbdae7e6d805 750 return(u32Count);
borlanic 0:fbdae7e6d805 751 }
borlanic 0:fbdae7e6d805 752
borlanic 0:fbdae7e6d805 753 // IEEE 1588 functions
borlanic 0:fbdae7e6d805 754 /**
borlanic 0:fbdae7e6d805 755 * @brief Enable IEEE1588 time stamp function and set current time
borlanic 0:fbdae7e6d805 756 * @param[in] u32Sec Second value
borlanic 0:fbdae7e6d805 757 * @param[in] u32Nsec Nano second value
borlanic 0:fbdae7e6d805 758 * @return None
borlanic 0:fbdae7e6d805 759 */
borlanic 0:fbdae7e6d805 760 void EMAC_EnableTS(uint32_t u32Sec, uint32_t u32Nsec)
borlanic 0:fbdae7e6d805 761 {
borlanic 0:fbdae7e6d805 762 double f;
borlanic 0:fbdae7e6d805 763 uint32_t reg;
borlanic 0:fbdae7e6d805 764 EMAC->TSCTL = EMAC_TSCTL_TSEN_Msk;
borlanic 0:fbdae7e6d805 765 EMAC->UPDSEC = u32Sec; // Assume current time is 0 sec + 0 nano sec
borlanic 0:fbdae7e6d805 766 EMAC->UPDSUBSEC = EMAC_Nsec2Subsec(u32Nsec);
borlanic 0:fbdae7e6d805 767
borlanic 0:fbdae7e6d805 768 // PTP source clock is 84MHz (Real chip using PLL). Each tick is 11.90ns
borlanic 0:fbdae7e6d805 769 // Assume we want to set each tick to 100ns.
borlanic 0:fbdae7e6d805 770 // Increase register = (100 * 2^31) / (10^9) = 214.71 =~ 215 = 0xD7
borlanic 0:fbdae7e6d805 771 // Addend register = 2^32 * tick_freq / (84MHz), where tick_freq = (2^31 / 215) MHz
borlanic 0:fbdae7e6d805 772 // From above equation, addend register = 2^63 / (84M * 215) ~= 510707200 = 0x1E70C600
borlanic 0:fbdae7e6d805 773 // So:
borlanic 0:fbdae7e6d805 774 // EMAC->TSIR = 0xD7;
borlanic 0:fbdae7e6d805 775 // EMAC->TSAR = 0x1E70C600;
borlanic 0:fbdae7e6d805 776 f = (100.0 * 2147483648.0) / (1000000000.0) + 0.5;
borlanic 0:fbdae7e6d805 777 EMAC->TSINC = (reg = (uint32_t)f);
borlanic 0:fbdae7e6d805 778 f = (double)9223372036854775808.0 / ((double)(CLK_GetHCLKFreq()) * (double)reg);
borlanic 0:fbdae7e6d805 779 EMAC->TSADDEND = (uint32_t)f;
borlanic 0:fbdae7e6d805 780 EMAC->TSCTL |= (EMAC_TSCTL_TSUPDATE_Msk | EMAC_TSCTL_TSIEN_Msk | EMAC_TSCTL_TSMODE_Msk); // Fine update
borlanic 0:fbdae7e6d805 781 }
borlanic 0:fbdae7e6d805 782
borlanic 0:fbdae7e6d805 783 /**
borlanic 0:fbdae7e6d805 784 * @brief Disable IEEE1588 time stamp function
borlanic 0:fbdae7e6d805 785 * @param None
borlanic 0:fbdae7e6d805 786 * @return None
borlanic 0:fbdae7e6d805 787 */
borlanic 0:fbdae7e6d805 788 void EMAC_DisableTS(void)
borlanic 0:fbdae7e6d805 789 {
borlanic 0:fbdae7e6d805 790 EMAC->TSCTL = 0;
borlanic 0:fbdae7e6d805 791 }
borlanic 0:fbdae7e6d805 792
borlanic 0:fbdae7e6d805 793 /**
borlanic 0:fbdae7e6d805 794 * @brief Get current time stamp
borlanic 0:fbdae7e6d805 795 * @param[out] pu32Sec Current second value
borlanic 0:fbdae7e6d805 796 * @param[out] pu32Nsec Current nano second value
borlanic 0:fbdae7e6d805 797 * @return None
borlanic 0:fbdae7e6d805 798 */
borlanic 0:fbdae7e6d805 799 void EMAC_GetTime(uint32_t *pu32Sec, uint32_t *pu32Nsec)
borlanic 0:fbdae7e6d805 800 {
borlanic 0:fbdae7e6d805 801 // Must read TSLSR firstly. Hardware will preserve TSMSR value at the time TSLSR read.
borlanic 0:fbdae7e6d805 802 *pu32Nsec = EMAC_Subsec2Nsec(EMAC->TSSUBSEC);
borlanic 0:fbdae7e6d805 803 *pu32Sec = EMAC->TSSEC;
borlanic 0:fbdae7e6d805 804 }
borlanic 0:fbdae7e6d805 805
borlanic 0:fbdae7e6d805 806 /**
borlanic 0:fbdae7e6d805 807 * @brief Set current time stamp
borlanic 0:fbdae7e6d805 808 * @param[in] u32Sec Second value
borlanic 0:fbdae7e6d805 809 * @param[in] u32Nsec Nano second value
borlanic 0:fbdae7e6d805 810 * @return None
borlanic 0:fbdae7e6d805 811 */
borlanic 0:fbdae7e6d805 812 void EMAC_SetTime(uint32_t u32Sec, uint32_t u32Nsec)
borlanic 0:fbdae7e6d805 813 {
borlanic 0:fbdae7e6d805 814 // Disable time stamp counter before update time value (clear EMAC_TSCTL_TSIEN_Msk)
borlanic 0:fbdae7e6d805 815 EMAC->TSCTL = EMAC_TSCTL_TSEN_Msk;
borlanic 0:fbdae7e6d805 816 EMAC->UPDSEC = u32Sec;
borlanic 0:fbdae7e6d805 817 EMAC->UPDSUBSEC = EMAC_Nsec2Subsec(u32Nsec);
borlanic 0:fbdae7e6d805 818 EMAC->TSCTL |= (EMAC_TSCTL_TSIEN_Msk | EMAC_TSCTL_TSMODE_Msk);
borlanic 0:fbdae7e6d805 819
borlanic 0:fbdae7e6d805 820 }
borlanic 0:fbdae7e6d805 821
borlanic 0:fbdae7e6d805 822 /**
borlanic 0:fbdae7e6d805 823 * @brief Enable alarm function and set alarm time
borlanic 0:fbdae7e6d805 824 * @param[in] u32Sec Second value to trigger alarm
borlanic 0:fbdae7e6d805 825 * @param[in] u32Nsec Nano second value to trigger alarm
borlanic 0:fbdae7e6d805 826 * @return None
borlanic 0:fbdae7e6d805 827 */
borlanic 0:fbdae7e6d805 828 void EMAC_EnableAlarm(uint32_t u32Sec, uint32_t u32Nsec)
borlanic 0:fbdae7e6d805 829 {
borlanic 0:fbdae7e6d805 830
borlanic 0:fbdae7e6d805 831 EMAC->ALMSEC = u32Sec;
borlanic 0:fbdae7e6d805 832 EMAC->ALMSUBSEC = EMAC_Nsec2Subsec(u32Nsec);
borlanic 0:fbdae7e6d805 833 EMAC->TSCTL |= EMAC_TSCTL_TSALMEN_Msk;
borlanic 0:fbdae7e6d805 834
borlanic 0:fbdae7e6d805 835 }
borlanic 0:fbdae7e6d805 836
borlanic 0:fbdae7e6d805 837 /**
borlanic 0:fbdae7e6d805 838 * @brief Disable alarm function
borlanic 0:fbdae7e6d805 839 * @param None
borlanic 0:fbdae7e6d805 840 * @return None
borlanic 0:fbdae7e6d805 841 */
borlanic 0:fbdae7e6d805 842 void EMAC_DisableAlarm(void)
borlanic 0:fbdae7e6d805 843 {
borlanic 0:fbdae7e6d805 844
borlanic 0:fbdae7e6d805 845 EMAC->TSCTL &= ~EMAC_TSCTL_TSALMEN_Msk;
borlanic 0:fbdae7e6d805 846
borlanic 0:fbdae7e6d805 847 }
borlanic 0:fbdae7e6d805 848
borlanic 0:fbdae7e6d805 849 /**
borlanic 0:fbdae7e6d805 850 * @brief Add a offset to current time
borlanic 0:fbdae7e6d805 851 * @param[in] u32Neg Offset is negative value (u32Neg == 1) or positive value (u32Neg == 0).
borlanic 0:fbdae7e6d805 852 * @param[in] u32Sec Second value to add to current time
borlanic 0:fbdae7e6d805 853 * @param[in] u32Nsec Nano second value to add to current time
borlanic 0:fbdae7e6d805 854 * @return None
borlanic 0:fbdae7e6d805 855 */
borlanic 0:fbdae7e6d805 856 void EMAC_UpdateTime(uint32_t u32Neg, uint32_t u32Sec, uint32_t u32Nsec)
borlanic 0:fbdae7e6d805 857 {
borlanic 0:fbdae7e6d805 858 EMAC->UPDSEC = u32Sec;
borlanic 0:fbdae7e6d805 859 EMAC->UPDSUBSEC = EMAC_Nsec2Subsec(u32Nsec);
borlanic 0:fbdae7e6d805 860 if(u32Neg)
borlanic 0:fbdae7e6d805 861 EMAC->UPDSUBSEC |= BIT31; // Set bit 31 indicates this is a negative value
borlanic 0:fbdae7e6d805 862
borlanic 0:fbdae7e6d805 863 EMAC->TSCTL |= EMAC_TSCTL_TSUPDATE_Msk;
borlanic 0:fbdae7e6d805 864
borlanic 0:fbdae7e6d805 865 }
borlanic 0:fbdae7e6d805 866
borlanic 0:fbdae7e6d805 867
borlanic 0:fbdae7e6d805 868 /*@}*/ /* end of group NUC472_442_EMAC_EXPORTED_FUNCTIONS */
borlanic 0:fbdae7e6d805 869
borlanic 0:fbdae7e6d805 870 /*@}*/ /* end of group NUC472_442_EMAC_Driver */
borlanic 0:fbdae7e6d805 871
borlanic 0:fbdae7e6d805 872 /*@}*/ /* end of group NUC472_442_Device_Driver */
borlanic 0:fbdae7e6d805 873
borlanic 0:fbdae7e6d805 874 /*** (C) COPYRIGHT 2013 Nuvoton Technology Corp. ***/