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