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