/* ********************************************************************************************************* * uC/TCP-IP * The Embedded TCP/IP Suite * * (c) Copyright 2003-2006; Micrium, Inc.; Weston, FL * * All rights reserved. Protected by international copyright laws. * * uC/TCP-IP is provided in source form for FREE evaluation, for educational * use or peaceful research. If you plan on using uC/TCP-IP in a commercial * product you need to contact Micrium to properly license its use in your * product. We provide ALL the source code for your convenience and to help * you experience uC/TCP-IP. The fact that the source code is provided does * NOT mean that you can use it without paying a licensing fee. * * Network Interface Card (NIC) port files provided, as is, for FREE and do * NOT require any additional licensing or licensing fee. * * Knowledge of the source code may NOT be used to develop a similar product. * * Please help us continue to provide the Embedded community with the finest * software available. Your honesty is greatly appreciated. ********************************************************************************************************* */ /* ********************************************************************************************************* * * NETWORK INTERFACE CARD * * LPC23XX/LPC24XX EMAC * * Filename : net_nic.c * Version : V1.89 * Programmer(s) : EHS ********************************************************************************************************* * Note(s) : (1) Supports EMAC section of NXP's LPC23XX and LPC24XX microcontrollers * as described in * * NXP Corporation (NXP; http://www.nxp.com). * (a) "LPC2364/6/8/78 User Manual" (UM10211) Revision 01 ( 6 October 2006) * (b) "LPC2468 User Manual" (UM10237) Revision 01 (18 December 2006) * * (2) REQUIREs Ethernet Network Interface Layer located in the following network directory : * * \\IF\Ether\ * * where * directory path for network protocol suite. * * (2) Since the EMAC module is integrated into either an LPC23XX or LPC24XX microcontroller, * the endianness of the registers is the same as the CPU, which is little endian by * default. ********************************************************************************************************* */ /* ********************************************************************************************************* * INCLUDE FILES ********************************************************************************************************* */ #define NET_NIC_MODULE #include #include #include /* ********************************************************************************************************* * NXP LPC23xx/LPC24xx REGISTERS ********************************************************************************************************* */ #define PCONP (*((volatile CPU_INT32U *)0xE01FC0C4)) /* ********************************************************************************************************* * NXP LPC23xx/LPC24xx EMAC REGISTERS * * Note(s) : (1) See NXP LPC23XX or NXP LPC24XX documentation for register summary. * * (2) Since the EMAC module is integrated into either a LPC23XX or LPC24XX microcontroller, * the endianness of the registers is the same as the CPU, which is little endian by default. ********************************************************************************************************* */ /* ------------- MAC REGISTERS ---------------- */ #define MAC1 (*((volatile CPU_INT32U *)0xFFE00000)) /* MAC Configuration Register 1 */ #define MAC2 (*((volatile CPU_INT32U *)0xFFE00004)) /* MAC Configuration Register 2 */ #define IPGT (*((volatile CPU_INT32U *)0xFFE00008)) /* Back-to-Back Inter-Packet-Gap Register */ #define IPGR (*((volatile CPU_INT32U *)0xFFE0000C)) /* Non Back-to-Back Inter-Packet-Gap Register */ #define CLRT (*((volatile CPU_INT32U *)0xFFE00010)) /* Collision Window/Retyr Register */ #define MAXF (*((volatile CPU_INT32U *)0xFFE00014)) /* Maximum Frame Register */ #define SUPP (*((volatile CPU_INT32U *)0xFFE00018)) /* PHY Support Register */ #define TEST (*((volatile CPU_INT32U *)0xFFE0001C)) /* Test Register */ #define MCFG (*((volatile CPU_INT32U *)0xFFE00020)) /* MII Mgmt Configuration Register */ #define MCMD (*((volatile CPU_INT32U *)0xFFE00024)) /* MII Mgmt Command Register */ #define MADR (*((volatile CPU_INT32U *)0xFFE00028)) /* MII Mgmt Address Register */ #define MWTD (*((volatile CPU_INT32U *)0xFFE0002C)) /* MII Mgmt Write Data Register */ #define MRDD (*((volatile CPU_INT32U *)0xFFE00030)) /* MII Mgmt Read Data Register */ #define MIND (*((volatile CPU_INT32U *)0xFFE00034)) /* MII Mgmt Indicators Register */ #define SA0 (*((volatile CPU_INT32U *)0xFFE00040)) /* Station Address 0 Register */ #define SA1 (*((volatile CPU_INT32U *)0xFFE00044)) /* Station Address 1 Register */ #define SA2 (*((volatile CPU_INT32U *)0xFFE00048)) /* Station Address 2 Register */ /* ----------- CONTROL REGISTERS -------------- */ #define COMMAND (*((volatile CPU_INT32U *)0xFFE00100)) /* Command Register */ #define STATUS (*((volatile CPU_INT32U *)0xFFE00104)) /* Status Register */ #define RXDESCRIPTOR (*((volatile CPU_INT32U *)0xFFE00108)) /* Receive Descriptor Base Address Register */ #define RXSTATUS (*((volatile CPU_INT32U *)0xFFE0010C)) /* Receive Status Base Address Register */ #define RXDESCRIPTORNUMBER (*((volatile CPU_INT32U *)0xFFE00110)) /* Receive Number of Descriptors Register */ #define RXPRODUCEINDEX (*((volatile CPU_INT32U *)0xFFE00114)) /* Receive Produce Index Register */ #define RXCONSUMEINDEX (*((volatile CPU_INT32U *)0xFFE00118)) /* Receive Consume Index Register */ #define TXDESCRIPTOR (*((volatile CPU_INT32U *)0xFFE0011C)) /* Transmit Descriptor Base Address Register */ #define TXSTATUS (*((volatile CPU_INT32U *)0xFFE00120)) /* Transmit Status Base Address Register */ #define TXDESCRIPTORNUMBER (*((volatile CPU_INT32U *)0xFFE00124)) /* Transmit Number of Descriptors Register */ #define TXPRODUCEINDEX (*((volatile CPU_INT32U *)0xFFE00128)) /* Transmit Produce Index Register */ #define TXCONSUMEINDEX (*((volatile CPU_INT32U *)0xFFE0012C)) /* Transmit Consume Index Register */ #define TSV0 (*((volatile CPU_INT32U *)0xFFE00158)) /* Transmit Status Vector 0 Register */ #define TSV1 (*((volatile CPU_INT32U *)0xFFE0015C)) /* Transmit Status Vector 1 Register */ #define RSV (*((volatile CPU_INT32U *)0xFFE00160)) /* Receive Status Vector Register */ #define FLOWCONTROLCOUNTER (*((volatile CPU_INT32U *)0xFFE00170)) /* Flow Control Counter Register */ #define FLOWCONTROLSTATUS (*((volatile CPU_INT32U *)0xFFE00174)) /* Flow Control Status Register */ /* ---------- RX FILTER REGISTERS ------------- */ #define RXFILTERCTRL (*((volatile CPU_INT32U *)0xFFE00200)) /* Receive Filter Control Register */ #define RXFILTERWOLSTATUS (*((volatile CPU_INT32U *)0xFFE00204)) /* Receive Filter WoL Status Register */ #define RXFILTERWOLCLEAR (*((volatile CPU_INT32U *)0xFFE00208)) /* Receive Filter WoL Clear Register */ #define HASHFILTERL (*((volatile CPU_INT32U *)0xFFE00210)) /* Hash Filter Table LSBs Register */ #define HASHFILTERH (*((volatile CPU_INT32U *)0xFFE00214)) /* Hash Filter Table MSBs Register */ /* -------- MODULE CONTROL REGISTERS ---------- */ #define INTSTATUS (*((volatile CPU_INT32U *)0xFFE00FE0)) /* Interrupt status register */ #define INTENABLE (*((volatile CPU_INT32U *)0xFFE00FE4)) /* Interrupt enable register */ #define INTCLEAR (*((volatile CPU_INT32U *)0xFFE00FE8)) /* Interrupt clear register */ #define INTSET (*((volatile CPU_INT32U *)0xFFE00FEC)) /* Interrupt set register */ #define POWERDOWN (*((volatile CPU_INT32U *)0xFFE00FF4)) /* Power-down register */ /* ********************************************************************************************************* * NXP LPC23xx/LPC24xx EMAC REGISTER BITS ********************************************************************************************************* */ /* ----------------- MAC1 bits ---------------- */ #define MAC1_RX_ENABLE DEF_BIT_00 #define MAC1_PASS_ALL_FRAMES DEF_BIT_01 #define MAC1_RESET_TX DEF_BIT_08 #define MAC1_RESET_MCS_TX DEF_BIT_09 #define MAC1_RESET_RX DEF_BIT_10 #define MAC1_RESET_MCS_RX DEF_BIT_11 #define MAC1_RESET_SIM DEF_BIT_14 #define MAC1_RESET_SOFT DEF_BIT_15 /* ----------------- MAC2 bits ---------------- */ #define MAC2_FULL_DUPLEX DEF_BIT_00 #define MAC2_CRC_EN DEF_BIT_08 #define MAC2_PAD_EN DEF_BIT_09 /* ----------------- IPGT bits ---------------- */ #define IPG_HALF_DUP 0x0012 #define IPG_FULL_DUP 0x0015 /* ----------------- SUPP bits ---------------- */ #define SUPP_SPEED DEF_BIT_08 /* ----------------- MCFG bits ---------------- */ #define MCFG_CLKSEL_DIV4 0x0000 #define MCFG_CLKSEL_DIV6 0x0008 #define MCFG_CLKSEL_DIV8 0x000C #define MCFG_CLKSEL_DIV10 0x0010 #define MCFG_CLKSEL_DIV14 0x0014 #define MCFG_CLKSEL_DIV20 0x0018 #define MCFG_CLKSEL_DIV28 0x001C #define MCFG_RESET_MII_MGMT DEF_BIT_15 /* ----------------- MCMD bits ---------------- */ #define MCMD_WRITE DEF_BIT_NONE #define MCMD_READ DEF_BIT_00 /* --------------- COMMAND bits --------------- */ #define COMMAND_RX_EN DEF_BIT_00 #define COMMAND_TX_EN DEF_BIT_01 #define COMMAND_RESET_REG DEF_BIT_03 #define COMMAND_RESET_TX DEF_BIT_04 #define COMMAND_RESET_RX DEF_BIT_05 #define COMMAND_PASS_RUNT_FRAMES DEF_BIT_06 #define COMMAND_PASS_ALL_FRAMES DEF_BIT_07 #define COMMAND_RMII DEF_BIT_09 #define COMMAND_FULL_DUPLEX DEF_BIT_10 /* -------------- INTENABLE bits -------------- */ /* -------------- INTSTATUS bits -------------- */ /* -------------- INTCLEAR bits -------------- */ /* -------------- INTSET bits -------------- */ #define INT_RX_OVERRUN DEF_BIT_00 #define INT_RX_ERROR DEF_BIT_01 #define INT_RX_FINISHED DEF_BIT_02 #define INT_RX_DONE DEF_BIT_03 #define INT_TX_UNDERRUN DEF_BIT_04 #define INT_TX_ERROR DEF_BIT_05 #define INT_TX_FINISHED DEF_BIT_06 #define INT_TX_DONE DEF_BIT_07 #define INT_SOFT DEF_BIT_12 #define INT_WAKEUP DEF_BIT_13 /* ------------- RXFILTERCTRL bits ------------ */ #define ACCEPT_BROADCAST DEF_BIT_01 #define ACCEPT_PERFECT DEF_BIT_05 /* ********************************************************************************************************* * DESCRIPTOR CONTROL AND STATUS BIT DEFINITIONS ********************************************************************************************************* */ #define EMAC_TX_DESC_INT 0x80000000 /* EMAC Descriptor Tx and Rx Control bits */ #define EMAC_TX_DESC_LAST 0x40000000 #define EMAC_TX_DESC_CRC 0x20000000 #define EMAC_TX_DESC_PAD 0x10000000 #define EMAC_TX_DESC_HUGE 0x08000000 #define EMAC_TX_DESC_OVERRIDE 0x04000000 #define EMAC_RX_DESC_INT 0x80000000 #define TX_DESC_STATUS_ERR 0x80000000 /* EMAC Tx Status bits */ #define TX_DESC_STATUS_NODESC 0x40000000 #define TX_DESC_STATUS_UNDERRUN 0x20000000 #define TX_DESC_STATUS_LCOL 0x10000000 #define TX_DESC_STATUS_ECOL 0x08000000 #define TX_DESC_STATUS_EDEFER 0x04000000 #define TX_DESC_STATUS_DEFER 0x02000000 #define TX_DESC_STATUS_COLCNT 0x01E00000 #define RX_DESC_STATUS_ERR 0x80000000 /* EMAC Rx Status bits */ #define RX_DESC_STATUS_LAST 0x40000000 #define RX_DESC_STATUS_NODESC 0x20000000 #define RX_DESC_STATUS_OVERRUN 0x10000000 #define RX_DESC_STATUS_ALGNERR 0x08000000 #define RX_DESC_STATUS_RNGERR 0x04000000 #define RX_DESC_STATUS_LENERR 0x02000000 #define RX_DESC_STATUS_SYMERR 0x01000000 #define RX_DESC_STATUS_CRCERR 0x00800000 #define RX_DESC_STATUS_BCAST 0x00400000 #define RX_DESC_STATUS_MCAST 0x00200000 #define RX_DESC_STATUS_FAILFLT 0x00100000 #define RX_DESC_STATUS_VLAN 0x00080000 #define RX_DESC_STATUS_CTLFRAM 0x00040000 #define RX_DESC_STATUS_SIZE_MASK 0x000007FF /* Determine addresses of descriptor lists */ #define EMAC_RX_DESC_BASE_ADDR (EMAC_RAM_BASE_ADDR) #define EMAC_RX_STATUS_BASE_ADDR (EMAC_RX_DESC_BASE_ADDR + (EMAC_NUM_RX_DESC * sizeof(EMAC_DESCRIPTOR))) #define EMAC_TX_DESC_BASE_ADDR (EMAC_RX_STATUS_BASE_ADDR + (EMAC_NUM_RX_DESC * sizeof(RX_STATUS))) #define EMAC_TX_STATUS_BASE_ADDR (EMAC_TX_DESC_BASE_ADDR + (EMAC_NUM_TX_DESC * sizeof(EMAC_DESCRIPTOR))) #define EMAC_RX_BUFF_BASE_ADDR (EMAC_TX_STATUS_BASE_ADDR + (EMAC_NUM_TX_DESC * sizeof(TX_STATUS))) #define EMAC_TX_BUFF_BASE_ADDR (EMAC_RX_BUFF_BASE_ADDR + (EMAC_NUM_RX_DESC * EMAC_RX_BUF_SIZE)) /* ********************************************************************************************************* * DATA TYPES ********************************************************************************************************* */ typedef struct emac_descriptor { /* EMAC Descriptor */ CPU_INT32U PacketAddr; /* DMA Buffer Address */ CPU_INT32U Control; /* DMA Control bits */ } EMAC_DESCRIPTOR; typedef struct rx_status { /* Rx Status data type */ CPU_INT32U StatusInfo; /* Status information */ CPU_INT32U StatusHashCRC; /* Status Hash CRC */ } RX_STATUS; typedef struct tx_status { /* Rx Status data type */ CPU_INT32U StatusInfo; /* Status information */ } TX_STATUS; /* ********************************************************************************************************* * GLOBAL VARIABLES ********************************************************************************************************* */ static CPU_INT08U MII_Dividers [7][2] = {{4, MCFG_CLKSEL_DIV4}, {6, MCFG_CLKSEL_DIV6}, {8, MCFG_CLKSEL_DIV8}, {10, MCFG_CLKSEL_DIV10}, {14, MCFG_CLKSEL_DIV14}, {20, MCFG_CLKSEL_DIV20}, {28, MCFG_CLKSEL_DIV28}}; static EMAC_DESCRIPTOR *RxDesc; static EMAC_DESCRIPTOR *TxDesc; static RX_STATUS *RxStatus; static TX_STATUS *TxStatus; static CPU_INT08U *RxBufBaseAddr; static CPU_INT08U *TxBufBaseAddr; static CPU_INT32U NIC_RxNRdyCtr; /*$PAGE*/ /* ********************************************************************************************************* * LOCAL FUNCTION PROTOTYPES ********************************************************************************************************* */ static void NetNIC_TxPktDiscard (NET_ERR *perr); /* ----------- LPC23XX/LPC24XX EMAC FNCTS ------------- */ static void EMAC_Init (NET_ERR *perr); /* ---------- LPC23XX/LPC24XX EMAC RX FNCTS ----------- */ static void EMAC_RxEn (void); static void EMAC_RxDis (void); static void EMAC_RxIntEn (void); static void EMAC_RxPkt (void *ppkt, CPU_INT16U size, NET_ERR *perr); static void EMAC_RxPktDiscard (CPU_INT16U size); /* ---------- LPC23XX/LPC24XX EMAC TX FNCTS ----------- */ static void EMAC_TxEn (void); static void EMAC_TxDis (void); static void EMAC_TxPkt (void *ppkt, CPU_INT16U size, NET_ERR *perr); static CPU_INT16U NIC_RxGetNRdy (void); /* ********************************************************************************************************* ********************************************************************************************************* * GLOBAL FUNCTIONS ********************************************************************************************************* ********************************************************************************************************* */ /* ********************************************************************************************************* * NetNIC_Init() * * Description : (1) Initialize Network Interface Card : * * (a) Perform NIC Layer OS initialization * (b) Initialize NIC status * (c) Initialize NIC statistics & error counters * (d) Initialize EMAC * * * Argument(s) : perr Pointer to variable that will hold the return error code from this function : * * NET_NIC_ERR_NONE Network interface card successfully initialized. * * -------- RETURNED BY NetOS_NIC_Init() : -------- * NET_OS_ERR_INIT_NIC_TX_RDY NIC transmit ready signal NOT successfully * initialized. * NET_OS_ERR_INIT_NIC_TX_RDY_NAME NIC transmit ready name NOT successfully * configured. * Return(s) : none. * * Caller(s) : Net_Init(). * * Note(s) : (1) This function calls EMAC_Init() which initializes the LPC23XX/LPC24XX hardware. ********************************************************************************************************* */ void NetNIC_Init (NET_ERR *perr) { /* --------------- PERFORM NIC/OS INIT -------------------- */ NetOS_NIC_Init(perr); /* Create NIC objs. */ if (*perr != NET_OS_ERR_NONE) { return; } /* ----------------- INIT NIC STATUS ---------------------- */ NetNIC_ConnStatus = DEF_OFF; /* ------------- INIT NIC STAT & ERR CTRS ----------------- */ #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) NetNIC_StatRxPktCtr = 0; NetNIC_StatTxPktCtr = 0; #endif #if (NET_CTR_CFG_ERR_EN == DEF_ENABLED) NetNIC_ErrRxPktDiscardedCtr = 0; NetNIC_ErrTxPktDiscardedCtr = 0; #endif /* ----------------- INIT LPC2378 EMAC -------------------- */ EMAC_Init(perr); } /* ********************************************************************************************************* * NetNIC_IntEn() * * Description : Enable NIC interrupts. * * Argument(s) : none. * * Return(s) : none. * * Caller(s) : Net_Init(). ********************************************************************************************************* */ void NetNIC_IntEn (NET_ERR *perr) { EMAC_RxIntEn(); /* Enable Rx interrupts */ *perr = NET_NIC_ERR_NONE; } /* ********************************************************************************************************* * NetNIC_ConnStatusGet() * * Description : Get NIC's network connection status. * * (1) Obtaining the NIC's network connection status is encapsulated in this function for the * possibility that obtaining a NIC's connection status requires a non-trivial procedure. * * * Argument(s) : none. * * Return(s) : NIC network connection status : * * DEF_OFF Network connection DOWN. * DEF_ON Network connection UP. * * Caller(s) : NetIF_Pkt_Tx(). ********************************************************************************************************* */ CPU_BOOLEAN NetNIC_ConnStatusGet (void) { return (NetNIC_ConnStatus); } /* ********************************************************************************************************* * EMAC Link Settings Update * * Description : This function is called by NetNIC_Init and the PHY ISR in order to update the * : speed and duplex settings for the EMAC. * * Arguments : link_speed Indicates link speed. This can be one of * NET_PHY_SPD_0 * NET_PHY_SPD_10 * NET_PHY_SPD_100 * NET_PHY_SPD_1000 * * link_duplex Indicates link duplex. This can be one of * NET_PHY_DUPLEX_UNKNOWN * NET_PHY_DUPLEX_HALF * NET_PHY_DUPLEX_FULL * * Return(s) : none. ********************************************************************************************************* */ void NetNIC_LinkChange (CPU_INT32U link_speed, CPU_INT32U link_duplex) { switch (link_speed) { case NET_PHY_SPD_0: /* Assume 10Mbps operation until linked */ case NET_PHY_SPD_10: SUPP &= ~SUPP_SPEED; /* Configure the RMII logic (if used) for 10MBps operation */ break; case NET_PHY_SPD_100: SUPP |= SUPP_SPEED; /* Configure the RMII logic (if uses) for 100MBps operation */ break; } switch (link_duplex) { case NET_PHY_DUPLEX_UNKNOWN: /* Assume half duplex until link duplex is known */ case NET_PHY_DUPLEX_HALF: MAC2 &= ~MAC2_FULL_DUPLEX; /* Configure the EMAC to run in HALF duplex mode */ COMMAND &= ~COMMAND_FULL_DUPLEX; /* Configure the MII logic for a Half Duplex PHY Link */ IPGT = IPG_HALF_DUP; /* Set inter packet gap to the recommended Half Duplex */ break; case NET_PHY_DUPLEX_FULL: MAC2 |= MAC2_FULL_DUPLEX; /* Configure the EMAC to run in FULL duplex mode */ COMMAND |= COMMAND_FULL_DUPLEX; /* Configure the MII logic for a Full Duplex PHY Link */ IPGT = IPG_FULL_DUP; /* Set inter packet gap to the recommended Full Duplex */ break; } } /* ********************************************************************************************************* * NetNIC_ISR_Handler() * * Description : (1) Decode ISR & call appropriate ISR handler : * * (a) Receive Buffer Not Available ISR NetNIC_RxPktDiscard(). * (b) Receive ISR NetNIC_RxISR_Handler(). * (c) Transmit ISR NetNIC_TxISR_Handler(). * * Argument(s) : none. * * Return(s) : none. * * Caller(s) : This is an ISR * * Note(s) : 1) VIC interrupts do not need to be explicity acknowledged if the BSP exception * handler writes a 0x00 to the VICAddress register after calling the ISR handler. * User ISR handlers (such as this one) need only clear the local interrupt source. ********************************************************************************************************* */ void NetNIC_ISR_Handler (void) { CPU_INT32U intstatus; CPU_INT16U n_new; NET_ERR err; intstatus = INTSTATUS; /* Read the interrupt status register */ if ((intstatus & INT_RX_DONE) > 0) { /* If a receiver event has occured */ n_new = NIC_RxGetNRdy() - NIC_RxNRdyCtr; /* Determine how many NEW franes have been received */ while (n_new > 0) { NetOS_IF_RxTaskSignal(&err); /* Signal Net IF Rx Task that a new frame has arrived */ switch (err) { /* Each frame is processed sequentially from the Rx task */ case NET_IF_ERR_NONE: if (NIC_RxNRdyCtr < EMAC_NUM_RX_DESC) { NIC_RxNRdyCtr++; } break; case NET_IF_ERR_RX_Q_FULL: case NET_IF_ERR_RX_Q_POST_FAIL: default: NetNIC_RxPktDiscard(0, &err); /* If an error occured while signaling the task, discard */ break; /* the received frame */ } n_new--; } INTCLEAR = (INT_RX_DONE); /* Clear the interrupt flags */ } if ((intstatus & (INT_RX_OVERRUN)) > 0) { /* If a fator Overrun error has occured */ INTCLEAR = (INT_RX_OVERRUN); /* Clear the overrun interrupt flag */ COMMAND |= COMMAND_RESET_RX; /* Soft reset the Rx datapath, this disables the receiver */ COMMAND |= COMMAND_RX_EN; /* Re-enable the reciever */ MAC1 |= MAC1_RX_ENABLE; /* Re-enable the reciever */ } } /* ********************************************************************************************************* * NetNIC_RxPktGetSize() * * Description : Get network packet size from NIC. * * Argument(s) : none. * * Return(s) : Size, in octets, of next frame to be read from the EMAC buffers * * Caller(s) : NetIF_RxTaskHandler() * * Notes : None. ********************************************************************************************************* */ CPU_INT16U NetNIC_RxPktGetSize (void) { CPU_INT16S size; CPU_INT32U rxstatus; rxstatus = RxStatus[RXCONSUMEINDEX].StatusInfo; /* Accquire the status word for this desciptor */ rxstatus &= (RX_DESC_STATUS_NODESC | /* Obtain the descriptor error bits */ RX_DESC_STATUS_OVERRUN | RX_DESC_STATUS_ALGNERR | RX_DESC_STATUS_LENERR | RX_DESC_STATUS_SYMERR | RX_DESC_STATUS_CRCERR | RX_DESC_STATUS_FAILFLT); if (rxstatus > 0) { /* If any receive errors (except range error) occured */ size = 0; /* then return 0 so upper layer call NetNIC_RxPktDiscard() */ } else { size = RxStatus[RXCONSUMEINDEX].StatusInfo & 0x7FF; /* Obtain the fragment size from the status struct pointer */ size -= 3; /* +1 since the size is 0 based, -4 to ignore FCS */ } if (size < 0) { /* Ensure that the subtraction didnt cause an underflow */ size = 0; } return (size); /* Return the size of the current frame */ } /* ********************************************************************************************************* * NetNIC_RxPkt() * * Description : Read network packet from NIC into buffer. * * Argument(s) : ppkt Pointer to memory buffer to receive NIC packet. * * size Number of packet frame octets to read into buffer. * * perr Pointer to variable that will hold the return error code from this function : * * NET_NIC_ERR_NONE Packet successfully read. * NET_ERR_INIT_INCOMPLETE Network initialization NOT complete. * NET_NIC_ERR_NULL_PTR Argument 'ppkt' passed a NULL pointer. * NET_NIC_ERR_INVALID_SIZE Invalid size. * * Return(s) : none. * * Caller(s) : NetIF_RxTaskHandler(). * * Note(s) : 1) NetNIC_RxPkt() blocked until network initialization completes; perform NO action. ********************************************************************************************************* */ void NetNIC_RxPkt (void *ppkt, CPU_INT16U size, NET_ERR *perr) { #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr; #endif #endif if (Net_InitDone != DEF_YES) { /* If init NOT complete, exit rx (see Note #2). */ *perr = NET_ERR_INIT_INCOMPLETE; return; } #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------------------- VALIDATE PTR ------------------ */ if (ppkt == (void *)0) { *perr = NET_NIC_ERR_NULL_PTR; return; } /* ------------------- VALIDATE SIZE ----------------- */ if (size < NET_IF_FRAME_MIN_SIZE) { *perr = NET_NIC_ERR_INVALID_SIZE; return; } #endif EMAC_RxPkt(ppkt, size, perr); /* Read the received Frame from the EMAC buffers */ if (*perr != NET_NIC_ERR_NONE) { return; } NET_CTR_STAT_INC(NetNIC_StatRxPktCtr); *perr = NET_NIC_ERR_NONE; } /* ********************************************************************************************************* * NetNIC_RxPktDiscard() * * Description : Discard network packet from NIC to free NIC packet frames for new receive packets. * * Argument(s) : size Number of packet frame octets. * * perr Pointer to variable that will hold the return error code from this function : * * NET_NIC_ERR_NONE Packet successfully discarded. * NET_ERR_INIT_INCOMPLETE Network initialization NOT complete. * * Return(s) : none. * * Caller(s) : NetIF_RxTaskHandler(). * * Note(s) : (1) NetNIC_RxPktDiscard() blocked until network initialization completes; perform NO action. * * (2) #### 'perr' may NOT be necessary (remove before product release if unnecessary). ********************************************************************************************************* */ void NetNIC_RxPktDiscard (CPU_INT16U size, NET_ERR *perr) { #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr; #endif if (Net_InitDone != DEF_YES) { /* If init NOT complete, exit discard (see Note #1). */ *perr = NET_ERR_INIT_INCOMPLETE; return; } EMAC_RxPktDiscard(size); CPU_CRITICAL_ENTER(); /* This routine alters shared data. Disable interrupts! */ if (NIC_RxNRdyCtr > 0) { /* One less packet to process */ NIC_RxNRdyCtr--; } CPU_CRITICAL_EXIT(); /* Re-Enable interrupts */ NET_CTR_ERR_INC(NetNIC_ErrRxPktDiscardedCtr); *perr = NET_NIC_ERR_NONE; } /* ********************************************************************************************************* * NetNIC_TxPkt() * * Description : Transmit data packets from network driver layer to network interface card. * * Argument(s) : ppkt Pointer to memory buffer to transmit NIC packet. * ---- Argument validated in NetIF_Pkt_Tx(). * * size Number of packet frame octets to write to frame. * ---- Argument checked in NetIF_Tx(). * * perr Pointer to variable that will hold the return error code from this function : * * NET_NIC_ERR_NONE Packet successfully transmitted. * NET_ERR_INIT_INCOMPLETE Network initialization NOT complete. * * - RETURNED BY NetNIC_TxPktDiscard() : - * NET_ERR_TX Transmit error; packet discarded. * * Return(s) : none. * * Caller(s) : NetIF_Pkt_Tx(). * * Note(s) : (1) NetNIC_TxPkt() blocked until network initialization completes; perform NO action. ********************************************************************************************************* */ void NetNIC_TxPkt (void *ppkt, CPU_INT16U size, NET_ERR *perr) { #if ((NET_CTR_CFG_STAT_EN == DEF_ENABLED) && \ (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)) CPU_SR cpu_sr; #endif if (Net_InitDone != DEF_YES) { /* If init NOT complete, exit tx (see Note #1). */ *perr = NET_ERR_INIT_INCOMPLETE; return; } EMAC_TxPkt(ppkt, size, perr); /* Hardware transmit routi */ if (*perr != NET_NIC_ERR_NONE) { NetNIC_TxPktDiscard(perr); return; } NET_CTR_STAT_INC(NetNIC_StatTxPktCtr); } /* ********************************************************************************************************* * NetNIC_PhyRegRd() * * Description : (1) Read PHY register * * Argument(s) : phy PHY address, normally 0. * reg PHY register. * perr Pointer to variable that will hold the return error code from this function * * Return(s) : MRDD PHY register data. * * Caller(s) : EMAC_Init(). * * Note(s) : none. ********************************************************************************************************* */ CPU_INT16U NetNIC_PhyRegRd (CPU_INT08U phy, CPU_INT08U reg, NET_ERR *perr) { CPU_INT08U retries; volatile CPU_INT32U i; retries = 0; /* Initialize retries to 0 */ MCMD = 0; /* Clear the Read COMMAND */ MADR = (phy << 8) | reg; /* [12:8] == PHY addr, [4:0]=0x00(BMCR) register addr */ MCMD = MCMD_READ; /* Issue a Read COMMAND */ while ((MIND != 0) && (retries < PHY_RDWR_RETRIES)) { /* Read the Management Indicator register, MII busy if > 0 */ for (i = 0; i < 1000; i++) { /* Delay while the read is in progress */ ; } retries++; } if (retries >= PHY_RDWR_RETRIES) { /* If there are no retries remaining */ *perr = NET_PHY_ERR_REGRD_TIMEOUT; /* Return an error code if the PHY Read timed out */ } else { *perr = NET_PHY_ERR_NONE; } return (MRDD); /* Return the content of the Management Read Data register */ } /* ********************************************************************************************************* * NetNIC_PhyRegWr() * * Description : (1) Write PHY register * * Argument(s) : phy PHY address, normally 0. * reg PHY register. * val Data to write to PHY register. * perr Pointer to variable that will hold the return error code from this function * * Return(s) : none. * * Caller(s) : EMAC_Init(). * * Note(s) : none. ********************************************************************************************************* */ void NetNIC_PhyRegWr (CPU_INT08U phy, CPU_INT08U reg, CPU_INT16U val, NET_ERR *perr) { CPU_INT08U retries; volatile CPU_INT32U i; retries = 0; /* Initialize retries to 0 */ MCMD = MCMD_WRITE; /* Issue a Write COMMAND */ MADR = (phy << 8) | reg; /* [12:8] == PHY addr, [4:0]=0x00(BMCR) register addr */ MWTD = val; /* Write the data to the Management Write Data register */ while ((MIND != 0) && (retries < PHY_RDWR_RETRIES)) { /* Read the Management Indicator register, MII busy if > 0 */ for (i = 0; i < 1000; i++) { /* Delay while the read is in progress */ ; } retries++; } if (retries >= PHY_RDWR_RETRIES) { /* If there are no retries remaining */ *perr = NET_PHY_ERR_REGWR_TIMEOUT; /* Return an error code if the PHY Read timed out */ } else { *perr = NET_PHY_ERR_NONE; } } /* ********************************************************************************************************* ********************************************************************************************************* * LOCAL FUNCTIONS ********************************************************************************************************* ********************************************************************************************************* */ /* ********************************************************************************************************* * NetNIC_TxPktDiscard() * * Description : On any Transmit errors, set error. * * Argument(s) : pbuf Pointer to network buffer. * * perr Pointer to variable that will hold the return error code from this function : * * NET_ERR_TX Transmit error; packet discarded. * * Return(s) : none. * * Caller(s) : NetNIC_TxPkt(). ********************************************************************************************************* */ static void NetNIC_TxPktDiscard (NET_ERR *perr) { #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr; #endif #endif NET_CTR_ERR_INC(NetNIC_ErrTxPktDiscardedCtr); *perr = NET_ERR_TX; } /* ********************************************************************************************************* * EMAC_Init() * * Description : (1) Initialize the LPC23XX/LPC24XX integrated EMAC * * (a) Initialize Registers * (b) Initialize MAC Address * (c) Initialize Auto Negotiation * (d) Initialize Interrupts * (e) Enable Receiver/Transmitter * * Argument(s) : perr a return error code indicating the result of initialization * NET_NIC_ERR_NONE - success * NET_NIC_ERR_NIC_OFF - link is down, or init failure occured * * Return(s) : none. * * Caller(s) : NetNIC_Init(). * * Note(s) : (1) (a) Assumes MAC address to set has previously been initialized by * (1) Application code for EMAC_MAC_ADDR_SEL_CFG * * (2) Interrupts MUST be enabled ONLY after ALL network initialization is complete (see also * 'net.c Net_Init() Note #4d'). * * (3) P1.6, ENET-TX_CLK, has to be set for EMAC to address a BUG in early revisions of the LPC2378. * This pin must be set even if RMII is not used. The bug has been fixed on newer revisions of * the chip and can be used for GPIO in some cicumstances. The Keil MCB2300 that this driver * has been developed with contains the errata. RMII mode can be switched on and off from * net_bsp.h by adjusting the EMAC_CFG_RMII macro accordingly. * * (4) The external PHY address is defined in net_phy.h as PHY_ADDR and should be set to * the address of your external PHY on the MII bus. This value is shifted over to the * left by 8 bits and written to the MAC_MADR register during PHY communications. * Consult your PHY documentation for additional information on how to determine the * address of your PHY. * * (5) The EMAC does not support the use of serial EEPROMS for automatically loading * the MAC address after reset. Therefore, the macro EMAC_CFG_MAC_ADDR_SEL in * net_bsp.h MUST be configured to EMAC_CFG_MAC_ADDR_SEL_CFG. This will allow * the driver to load the Station Address registers with the data found in * NetIF_MAC_Addr[], which is set by the user in app.c before calling Net_Init(). * If necessary, the user may take steps to read a serial EEPROM and then * fill the content of NetIF_MAC_Addr[] accordingly. * * (6) Interrupts are enabled by uC/TCP-IP, Net_Init() calling NetNIC_IntEn(). * * (7) Rx descriptors must be 32 bit aligned, Rx status descriptors must be 64 bit aligned. * * (8) The EMAC has 16KB of dedicated RAM located on the AHB2 bus at address 0x7FE00000, * see net_bsp.h. ********************************************************************************************************* */ static void EMAC_Init (NET_ERR *perr) { CPU_INT16U i; CPU_INT32U clk_freq; NIC_RxNRdyCtr = 0; /* Initialize global Rx packet count to 0 */ NetNIC_LinkUp(); /* Set NetNIC_ConnStatus to TRUE by default (for uC/TCP-IP) */ /* ------- Reset and configure the EMAC registers --------- */ *perr = NET_NIC_ERR_NONE; /* Initialize the returned error code to NO Error */ PCONP |= (1 << 30); /* Enable the EMAC clock */ NetBSP_Phy_HW_Init(); /* Configure the I/O pins necessary for PHY communication */ MAC1 = MAC1_RESET_TX | /* [15],[14],[11:8] -> soft resets all MAC internal modules */ MAC1_RESET_MCS_TX | MAC1_RESET_RX | MAC1_RESET_MCS_RX | MAC1_RESET_SIM | MAC1_RESET_SOFT; COMMAND = COMMAND_RESET_REG | /* Reset all datapaths and host registers */ COMMAND_RESET_TX | COMMAND_RESET_RX; NetBSP_DlyMs(2); /* Delay for a few milliseconds after reset */ MAC1 = 0; /* Deassert all prior resets */ EMAC_TxDis(); /* Disable the transmitter */ EMAC_RxDis(); /* Disable the receiver */ #if EMAC_CFG_RMII COMMAND |= COMMAND_RMII; /* Configure EMAC / PHY communication to RMII mode */ #else COMMAND &= ~COMMAND_RMII; /* Configure EMAC / PHY communication to MII mode */ #endif SUPP = 0x0000; /* Assume and configure RMII link speed logic for 10Mbit */ NetBSP_DlyMs(2); /* Delay for a few milliseconds after reset */ TEST = 0; /* Default the test register. No tests in progress */ MAXF = 0x600; /* Accept maximum sized frames, 1536 octects (default) */ MAC1 |= MAC1_PASS_ALL_FRAMES; /* Pass All Frames: Normal and Control */ MAC2 = MAC2_CRC_EN | MAC2_PAD_EN; /* Configure the EMAC to PAD short frames and append CRC */ RXFILTERCTRL = ACCEPT_BROADCAST | ACCEPT_PERFECT; /* Accept Broadcast and Perfect Address frames */ /* ---- Configure the MDI port (RMII / MII capable) ------- */ clk_freq = NetBSP_GetHostClkFreq(); /* Get the LPC23xx/LPC24xx cClkFrq (Hz) which feeds the EMAC*/ clk_freq /= 100000; /* Div by 1000000 for MHz, Mult by 10 so floating point */ /* math not necessary when calculating the divider below */ MCFG |= 0x8018; /* Apply a reset to the MII logic, set default divider = 20 */ MCMD = 0; /* Clear MII command register */ for (i = 0; i < 7; i++) { /* Check dividers to yield MII frequency ~2.5 MHz */ if ((clk_freq / MII_Dividers[i][0]) <= 25) { /* Index [i][0] = decimal div value, [i][1] = MCFG reg val */ MCFG = MII_Dividers[i][1]; /* Remove reset, set proper MIIM divider */ break; } } NetBSP_DlyMs(10); /* Short delay while PHY exits reset and new divider is set */ NetNIC_PhyInit(perr); /* --------------- Initialize the PHY --------------------- */ IPGR = 0x0C12; /* Set the Non Back to Back Inter Pkt Gap to recm'd value */ CLRT = 0x370F; /* Collission Windows Retry register (default value) */ SA0 = (NetIF_MAC_Addr[5] << 8) | /* Write the MAC Address, octect 2 and 1 to the EMAC */ (NetIF_MAC_Addr[4]); SA1 = (NetIF_MAC_Addr[3] << 8) | /* Write the MAC Address, octect 4 and 3 to the EMAC */ (NetIF_MAC_Addr[2]); SA2 = (NetIF_MAC_Addr[1] << 8) | /* Write the MAC Address, octect 6 and 5 to the EMAC */ (NetIF_MAC_Addr[0]); NetIF_MAC_AddrValid = DEF_YES; /* Inform uC/TCP-IP, that we have a valid MAC address set */ /* ----- Descriptor List Global Pointer Initialization ---- */ RxDesc = (EMAC_DESCRIPTOR *)(EMAC_RX_DESC_BASE_ADDR); TxDesc = (EMAC_DESCRIPTOR *)(EMAC_TX_DESC_BASE_ADDR); RxStatus = (RX_STATUS *)(EMAC_RX_STATUS_BASE_ADDR); TxStatus = (TX_STATUS *)(EMAC_TX_STATUS_BASE_ADDR); RxBufBaseAddr = (CPU_INT08U *)(EMAC_RX_BUFF_BASE_ADDR); TxBufBaseAddr = (CPU_INT08U *)(EMAC_TX_BUFF_BASE_ADDR); /* ---------------- Rx Descriptor Initialization ----------- */ /* Rx Descriptor and Status array initialization */ /* Set the addr of the DMA Rx buf */ /* Interrupt when Rx complete, set buf size (-1 encoded) */ /* Initialize the Status Info to 0 */ /* Initialize the Status Hash CRC to 0 */ for (i = 0; i < EMAC_NUM_RX_DESC; i++) { RxDesc[i].PacketAddr = (CPU_INT32U)(RxBufBaseAddr + (i * EMAC_RX_BUF_SIZE)); RxDesc[i].Control = EMAC_RX_DESC_INT | (EMAC_RX_BUF_SIZE - 1); RxStatus[i].StatusInfo = 0; RxStatus[i].StatusHashCRC = 0; } RXDESCRIPTOR = (CPU_INT32U)(RxDesc); /* Write the Rx Descriptor base address register */ RXSTATUS = (CPU_INT32U)(RxStatus); /* Write the Rx Status base address register */ RXDESCRIPTORNUMBER = EMAC_NUM_RX_DESC - 1; /* Write the Rx Descriptor Number register with NumDesc - 1 */ RXCONSUMEINDEX = 0; /* Configure the Rx Consume Index register to 0 */ /* ------- Tx Descriptor and Status Initialization -------- */ /* Rx Descriptor and Status array initialization */ /* Set the addr of the DMA Rx buf, assume 1536B frames */ /* Configure the control bits in the EMAC_TxPkt() function */ /* Initialize the Status Info to 0 */ for (i = 0; i < EMAC_NUM_TX_DESC; i++) { TxDesc[i].PacketAddr = (CPU_INT32U)(TxBufBaseAddr + (i * 1536)); TxDesc[i].Control = 0; TxStatus[i].StatusInfo = 0; } TXDESCRIPTOR = (CPU_INT32U)(TxDesc); /* Write the Tx Descriptor base address register */ TXSTATUS = (CPU_INT32U)(TxStatus); /* Write the Tx Status base address register */ TXDESCRIPTORNUMBER = EMAC_NUM_TX_DESC - 1; /* Write the Tx Descriptor Number register with NumDesc - 1 */ TXPRODUCEINDEX = 0; /* Configure the Tx Produce Index register to 0 */ /* ------- Configure Interrupts on the VIC Level ---------- */ INTCLEAR = (INT_RX_OVERRUN | /* Clear all EMAC interrupt sources */ INT_RX_ERROR | INT_RX_FINISHED | INT_RX_DONE | INT_TX_UNDERRUN | INT_TX_ERROR | INT_TX_FINISHED | INT_TX_DONE | INT_SOFT | INT_WAKEUP); NetNIC_IntInit(); /* -------- Enable the transmitter and receiver ----------- */ EMAC_TxEn(); /* Enable the EMAC transmitter */ EMAC_RxEn(); /* Enable the EMAC receiver */ *perr = NET_NIC_ERR_NONE; /* Initialize the returned error code to NO Error */ } /* ********************************************************************************************************* * NIC_RxGetNRdy() * * Description : Determines how many packets we are ready to be processed. * * Parameters : None. * * Returns : Number of NIC buffers that are ready to be processed by the stack. ********************************************************************************************************* */ static CPU_INT16U NIC_RxGetNRdy (void) { CPU_INT16U n_rdy; CPU_INT16U rxconsumeix; CPU_INT16U rxproduceix; rxconsumeix = RXCONSUMEINDEX; rxproduceix = RXPRODUCEINDEX; if (rxproduceix < rxconsumeix) { /* If the produce index has wrapped around */ n_rdy = EMAC_NUM_RX_DESC - rxconsumeix + rxproduceix; } else { /* If consumeix is < produceix, then no wrap around occured */ n_rdy = rxproduceix - rxconsumeix; } return (n_rdy); } /* ********************************************************************************************************* ********************************************************************************************************* * LOCAL FUNCTIONS: EMAC RX FUNCTIONS ********************************************************************************************************* ********************************************************************************************************* */ /* ********************************************************************************************************* * EMAC_RxEn() * * Description : Enable LPC23XX/LPC24XX EMAC Receiver. * * Argument(s) : none. * * Return(s) : none. * * Caller(s) : EMAC_Init(). ********************************************************************************************************* */ static void EMAC_RxEn (void) { COMMAND |= COMMAND_RX_EN; /* Enable the receiver */ MAC1 |= COMMAND_RX_EN; /* Enable the receiver */ } /* ********************************************************************************************************* * EMAC_RxDis() * * Description : Disable LPC23XX/LPC24XX EMAC Receiver. * * Argument(s) : none. * * Return(s) : none. * * Caller(s) : EMAC_Init(). ********************************************************************************************************* */ static void EMAC_RxDis (void) { COMMAND &= ~COMMAND_RX_EN; /* Disable the receiver */ MAC1 &= ~COMMAND_RX_EN; /* Disable the receiver (same bit position as COMMAND reg) */ } /* ********************************************************************************************************* * EMAC_RxIntEn() * * Description : Enable EMAC Receiver Interrupts. * * Argument(s) : none. * * Return(s) : none. * * Caller(s) : NetNIC_IntEn(), NetNIC_RxPktGetSize(), NetNIC_RxPkt(). * * Notes : 1) The RxDone interrupt occurs when a Rx descriptor has been produced by the EMAC. ********************************************************************************************************* */ static void EMAC_RxIntEn (void) { INTENABLE |= (INT_RX_DONE | INT_RX_OVERRUN); /* Enable RxDone interrupts and Rx Overrun interrupts */ } /* ********************************************************************************************************* * EMAC_RxPkt() * * Description : (1) Read network packet from NIC into buffer : * (a) Read received frame DMA memory space. * (b) Release descriptors once data has been read * * Argument(s) : ppkt Pointer to memory buffer to receive NIC packet. * ---- Argument checked in NetNIC_RxPkt(). * * size Number of packet frame octets to read into buffer. * ---- Argument checked in NetNIC_RxPkt(). * * perr Pointer to variable that will hold the return error code from this function : * * NET_NIC_ERR_NONE Packet successfully transmitted. * NET_ERR_RX Error Reading Buffers (EOF not found) * * Return(s) : none. * * Caller(s) : NetNIC_RxPkt(). * * Notes : none. ********************************************************************************************************* */ static void EMAC_RxPkt (void *ppkt, CPU_INT16U size, NET_ERR *perr) { #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr = 0; #endif void *prxbuf; *perr = NET_NIC_ERR_NONE; /* Assume no errors have occured */ prxbuf = (void *)RxDesc[RXCONSUMEINDEX].PacketAddr; /* Get a pointer to the Rx fragment / frame buffer */ RxStatus[RXCONSUMEINDEX].StatusInfo = 0; /* Clear status for debugging purposes */ Mem_Copy(ppkt, prxbuf, size); /* Copy the fragment / frame into the stacks buffer */ RXCONSUMEINDEX = (RXCONSUMEINDEX + 1) % EMAC_NUM_RX_DESC; /* Discard the fragment / frame */ CPU_CRITICAL_ENTER(); /* This routine alters shared data. Disable interrupts! */ if (NIC_RxNRdyCtr > 0) { /* One less packet to process */ NIC_RxNRdyCtr--; } CPU_CRITICAL_EXIT(); /* Re-Enable interrupts */ } /* ********************************************************************************************************* * EMAC_RxPktDiscard() * * Description : Discard network packet from NIC to free NIC packet frames for new receive packets. * * Argument(s) : Size: how much data to discard. However, we will discard an entire frame * so this information is not necessary. * * Return(s) : none. * * Caller(s) : NetNIC_RxPktDiscard(). ********************************************************************************************************* */ static void EMAC_RxPktDiscard (CPU_INT16U size) { (void)size; /* Size is not required since frames are discarded by index */ RXCONSUMEINDEX = (RXCONSUMEINDEX + 1) % EMAC_NUM_RX_DESC; } /* ********************************************************************************************************* ********************************************************************************************************* * LOCAL FUNCTIONS: MACB TX FUNCTIONS ********************************************************************************************************* ********************************************************************************************************* */ /* ********************************************************************************************************* * EMAC_TxEn() * * Description : Enable LPC23XX/LPC24XX EMAC Transmitter. * * Argument(s) : none. * * Return(s) : none. * * Caller(s) : EMAC_Init(). ********************************************************************************************************* */ static void EMAC_TxEn (void) { COMMAND |= COMMAND_TX_EN; /* Enable the transmitter */ } /* ********************************************************************************************************* * EMAC_TxDis() * * Description : Disable LPC23XX/LPC24XX EMAC Transmitter. * * Argument(s) : none. * * Return(s) : none. * * Caller(s) : EMAC_Init(). ********************************************************************************************************* */ static void EMAC_TxDis (void) { COMMAND &= ~COMMAND_TX_EN; /* Disable the transmitter */ } /* ********************************************************************************************************* * EMAC_TxPkt() * * Description : (1) Instruct EMAC to send network packet : * (a) Check if transmitter ready. * (b) Clear all transmitter errors. * (c) Inform transmitter about buffer address and size. * This starts actual transmission of the packet. * * Argument(s) : ppkt Pointer to memory buffer to transmit NIC packet. * ---- Argument checked in NetNIC_TxPkt(). * * size Number of packet frame octets to write to frame. * * perr Pointer to variable that will hold the return error code from this function : * * NET_NIC_ERR_NONE Packet successfully transmitted. * EMAC_ERR_TX_BUSY Transmitter not ready. * Return(s) : none. * * Caller(s) : NetNIC_TxPkt(). * * Notes : 1) The TCP-IP stack is signaled immediately after issuing the Tx command * because it is assumed that the hardware transmits frames much faster * than the CPU can load the next Tx descriptor. ********************************************************************************************************* */ static void EMAC_TxPkt (void *ppkt, CPU_INT16U size, NET_ERR *perr) { Mem_Copy((void *)(TxDesc[TXPRODUCEINDEX].PacketAddr), ppkt, size); /* Copy the packet into the EMAC AHB2 RAM */ TxDesc[TXPRODUCEINDEX].Control = (EMAC_TX_DESC_OVERRIDE | /* Override the defaults from the MAC internal registers */ EMAC_TX_DESC_PAD | /* Add padding for frames < 64 bytes */ EMAC_TX_DESC_LAST | /* No additional descriptors to follow, this is the last */ EMAC_TX_DESC_CRC) | /* Append the CRC automatically */ (size - 1); /* Write the size of the frame, starting from 0 */ TXPRODUCEINDEX = (TXPRODUCEINDEX + 1) % EMAC_NUM_TX_DESC; /* Increment the produce Ix register, initiate Tx of frame */ *perr = NET_NIC_ERR_NONE; /* No error condition */ NetOS_NIC_TxRdySignal(); /* Signal the stack that it may transmit another frame */ }