NXP LPC1768 Ethernet driver for lwip and CMSIS-RTOS

Dependents:   EthernetInterface EthernetInterface EthernetInterface_RSF EthernetInterface ... more

Legacy Networking Libraries

This is an mbed 2 networking library. For mbed 5, the networking libraries have been revised to better support additional network stacks and thread safety here.

This library is based on the code of the NXP LPC port of the Lightweight TCP/IP Stack

Copyright(C) 2011, NXP Semiconductor
All rights reserved.

Software that is described herein is for illustrative purposes only
which provides customers with programming information regarding the
products. This software is supplied "AS IS" without any warranties.
NXP Semiconductors assumes no responsibility or liability for the
use of the software, conveys no license or title under any patent,
copyright, or mask work right to the product. NXP Semiconductors
reserves the right to make changes in the software without
notification. NXP Semiconductors also make no representation or
warranty that such application will be suitable for the specified
use without further testing or modification.
Revision:
7:5754e05385b8
Parent:
6:59b01b9349d5
Child:
8:59490137c7a7
--- a/arch/lpc17_emac.c	Mon Jun 03 12:06:46 2013 +0100
+++ b/arch/lpc17_emac.c	Mon Aug 19 18:39:00 2013 +0300
@@ -6,7 +6,7 @@
 * @version	1.0
 * @date		20. Nov. 2011
 * @author	NXP MCU SW Application Team
-* 
+*
 * Copyright(C) 2011, NXP Semiconductor
 * All rights reserved.
 *
@@ -62,7 +62,7 @@
 
 #if NO_SYS == 0
 /** \brief  Driver transmit and receive thread priorities
- * 
+ *
  * Thread priorities for receive thread and TX cleanup thread. Alter
  * to prioritize receive or transmit bandwidth. In a heavily loaded
  * system or with LEIP_DEBUG enabled, the priorities might be better
@@ -71,7 +71,7 @@
 #define TX_PRIORITY   (osPriorityNormal)
 
 /** \brief  Debug output formatter lock define
- * 
+ *
  * When using FreeRTOS and with LWIP_DEBUG enabled, enabling this
  * define will allow RX debug messages to not interleave with the
  * TX messages (so they are actually readable). Not enabling this
@@ -138,13 +138,19 @@
 #  else
 #     define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned))
 #  endif
-#else
-#   define ETHMEM_SECTION ALIGNED(8)
+#elif defined(TARGET_LPC1768)
+#  if defined(TOOLCHAIN_GCC_ARM)
+#     define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned))
+#  endif
+#endif
+
+#ifndef ETHMEM_SECTION
+#define ETHMEM_SECTION ALIGNED(8)
 #endif
 
 /** \brief  LPC EMAC driver work data
  */
-ETHMEM_SECTION struct lpc_enetdata lpc_enetdata; 
+ETHMEM_SECTION struct lpc_enetdata lpc_enetdata;
 
 /* Write a value via the MII link (non-blocking) */
 void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value)
@@ -196,7 +202,7 @@
 }
 
 /* Starts a read operation via the MII link (non-blocking) */
-void lpc_mii_read_noblock(u32_t PhyReg) 
+void lpc_mii_read_noblock(u32_t PhyReg)
 {
 	/* Read value at PHY address and register */
 	LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg;
@@ -204,7 +210,7 @@
 }
 
 /* Read a value via the MII link (blocking) */
-err_t lpc_mii_read(u32_t PhyReg, u32_t *data) 
+err_t lpc_mii_read(u32_t PhyReg, u32_t *data)
 {
 	u32_t mst = 250;
 	err_t sts = ERR_OK;
@@ -307,7 +313,7 @@
 }
 
 /** \brief  Sets up the RX descriptor ring buffers.
- * 
+ *
  *  This function sets up the descriptor list used for receive packets.
  *
  *  \param[in]  lpc_enetif  Pointer to driver data structure
@@ -414,7 +420,7 @@
 			LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
 				("lpc_low_level_input: Packet dropped with errors (0x%x)\n",
 				lpc_enetif->prxs[idx].statusinfo));
-			
+
 			p = NULL;
 		} else {
 			/* A packet is waiting, get length */
@@ -424,10 +430,31 @@
 			p = lpc_enetif->rxb[idx];
 			p->len = (u16_t) length;
 
-			/* Free pbuf from desriptor */
+			/* Free pbuf from descriptor */
 			lpc_enetif->rxb[idx] = NULL;
 			lpc_enetif->rx_free_descs++;
 
+			/* Attempt to queue new buffer(s) */
+			if (lpc_rx_queue(lpc_enetif->netif) == 0) {
+    			/* Drop the frame due to OOM. */
+    			LINK_STATS_INC(link.drop);
+
+    			/* Re-queue the pbuf for receive */
+    			lpc_rxqueue_pbuf(lpc_enetif, p);
+
+    			LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
+    				("lpc_low_level_input: Packet index %d dropped for OOM\n",
+    				idx));
+			
+#ifdef LOCK_RX_THREAD
+#if NO_SYS == 0
+        		sys_mutex_unlock(&lpc_enetif->TXLockMutex);
+#endif
+#endif
+
+		        return NULL;
+			}
+
 			LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
 				("lpc_low_level_input: Packet received: %p, size %d (index=%d)\n",
 				p, length, idx));
@@ -435,9 +462,6 @@
 			/* Save size */
 			p->tot_len = (u16_t) length;
 			LINK_STATS_INC(link.recv);
-
-			/* Queue new buffer(s) */
-			lpc_rx_queue(lpc_enetif->netif);
 		}
 	}
 
@@ -447,7 +471,7 @@
 #endif
 #endif
 
-	return p;  
+	return p;
 }
 
 /** \brief  Attempt to read a packet from the EMAC interface.
@@ -497,11 +521,11 @@
  */
 static s32_t lpc_packet_addr_notsafe(void *addr) {
 	/* Check for legal address ranges */
-#if defined(TARGET_LPC1768)  
+#if defined(TARGET_LPC1768)
 	if ((((u32_t) addr >= 0x2007C000) && ((u32_t) addr < 0x20083FFF))) {
 #elif defined(TARGET_LPC4088)
 	if ((((u32_t) addr >= 0x20000000) && ((u32_t) addr < 0x20007FFF))) {
-#endif  
+#endif
 	    return 0;
 	}
 	return 1;
@@ -618,14 +642,14 @@
 	struct lpc_enetdata *lpc_enetif = netif->state;
 	struct pbuf *q;
 	u8_t *dst;
-    u32_t idx;
+    u32_t idx, notdmasafe = 0;
 	struct pbuf *np;
-	u32_t dn, notdmasafe = 0;
+	s32_t dn;
 
 	/* Zero-copy TX buffers may be fragmented across mutliple payload
 	   chains. Determine the number of descriptors needed for the
 	   transfer. The pbuf chaining can be a mess! */
-	dn = (u32_t) pbuf_clen(p);
+	dn = (s32_t) pbuf_clen(p);
 
 	/* Test to make sure packet addresses are DMA safe. A DMA safe
 	   address is once that uses external memory or periphheral RAM.
@@ -641,7 +665,7 @@
 		/* Allocate a pbuf in DMA memory */
 		np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
 		if (np == NULL)
-			return ERR_MEM;	
+			return ERR_MEM;
 
 		/* This buffer better be contiguous! */
 		LWIP_ASSERT("lpc_low_level_output: New transmit pbuf is chained",
@@ -654,7 +678,7 @@
 	  		MEMCPY(dst, (u8_t *) q->payload, q->len);
 		  dst += q->len;
 		}
-		np->len = p->tot_len; 
+		np->len = p->tot_len;
 
 		LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
 			("lpc_low_level_output: Switched to DMA safe buffer, old=%p, new=%p\n",
@@ -759,12 +783,12 @@
         /* RX group interrupt(s): Give semaphore to wakeup RX receive task.*/
         sys_sem_signal(&lpc_enetdata.RxSem);
     }
-    
+
     if (ints & TXINTGROUP) {
         /* TX group interrupt(s): Give semaphore to wakeup TX cleanup task. */
         sys_sem_signal(&lpc_enetdata.TxCleanSem);
     }
-    
+
 	/* Clear pending interrupts */
 	LPC_EMAC->IntClear = ints;
 #endif
@@ -780,11 +804,11 @@
  */
 static void packet_rx(void* pvParameters) {
     struct lpc_enetdata *lpc_enetif = pvParameters;
-    
+
     while (1) {
         /* Wait for receive task to wakeup */
         sys_arch_sem_wait(&lpc_enetif->RxSem, 0);
-        
+
         /* Process packets until all empty */
         while (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex)
             lpc_enetif_input(lpc_enetif->netif);
@@ -802,18 +826,18 @@
 static void packet_tx(void* pvParameters) {
     struct lpc_enetdata *lpc_enetif = pvParameters;
     s32_t idx;
-    
+
     while (1) {
         /* Wait for transmit cleanup task to wakeup */
         sys_arch_sem_wait(&lpc_enetif->TxCleanSem, 0);
-        
+
         /* Error handling for TX underruns. This should never happen unless
            something is holding the bus or the clocks are going too slow. It
             can probably be safely removed. */
         if (LPC_EMAC->IntStatus & EMAC_INT_TX_UNDERRUN) {
             LINK_STATS_INC(link.err);
             LINK_STATS_INC(link.drop);
-            
+
 #if NO_SYS == 0
             /* Get exclusive access */
             sys_mutex_lock(&lpc_enetif->TXLockMutex);
@@ -821,7 +845,7 @@
             /* Reset the TX side */
             LPC_EMAC->MAC1 |= EMAC_MAC1_RES_TX;
             LPC_EMAC->IntClear = EMAC_INT_TX_UNDERRUN;
-            
+
             /* De-allocate all queued TX pbufs */
             for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) {
                 if (lpc_enetif->txb[idx] != NULL) {
@@ -829,7 +853,7 @@
                     lpc_enetif->txb[idx] = NULL;
                 }
             }
-            
+
 #if NO_SYS == 0
             /* Restore access */
             sys_mutex_unlock(&lpc_enetif->TXLockMutex);
@@ -855,8 +879,8 @@
 
 	/* Enable MII clocking */
 	LPC_SC->PCONP |= CLKPWR_PCONP_PCENET;
-	
-#if defined(TARGET_LPC1768)  
+
+#if defined(TARGET_LPC1768)
 	LPC_PINCON->PINSEL2 = 0x50150105;                  /* Enable P1 Ethernet Pins. */
 	LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005;
 #elif defined(TARGET_LPC4088)
@@ -880,8 +904,8 @@
   LPC_IOCON->P1_16 |= 0x01;     /* ENET_MDC */
   LPC_IOCON->P1_17 &= ~0x07;
   LPC_IOCON->P1_17 |= 0x01;     /* ENET_MDIO */
-#endif  
-	
+#endif
+
 	/* Reset all MAC logic */
 	LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX |
 		EMAC_MAC1_RES_RX | EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES |
@@ -889,7 +913,7 @@
 	LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES |
 		EMAC_CR_PASS_RUNT_FRM;
 	osDelay(10);
-	
+
 	/* Initial MAC initialization */
 	LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL;
 	LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN |
@@ -980,7 +1004,7 @@
  *
  * \param[in] netif the lwip network interface structure for this lpc_enetif
  * \param[in] q Pointer to pbug to send
- * \param[in] ipaddr IP address 
+ * \param[in] ipaddr IP address
  * \return ERR_OK or error code
  */
 err_t lpc_etharp_output(struct netif *netif, struct pbuf *q,
@@ -1017,11 +1041,20 @@
 	err_t err;
 
 	LWIP_ASSERT("netif != NULL", (netif != NULL));
-    
+
 	lpc_enetdata.netif = netif;
 
 	/* set MAC hardware address */
+#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
+	netif->hwaddr[0] = MBED_MAC_ADDR_0;
+	netif->hwaddr[1] = MBED_MAC_ADDR_1;
+	netif->hwaddr[2] = MBED_MAC_ADDR_2;
+	netif->hwaddr[3] = MBED_MAC_ADDR_3;
+	netif->hwaddr[4] = MBED_MAC_ADDR_4;
+	netif->hwaddr[5] = MBED_MAC_ADDR_5;
+#else
 	mbed_mac_address((char *)netif->hwaddr);
+#endif
 	netif->hwaddr_len = ETHARP_HWADDR_LEN;
 
  	/* maximum transfer unit */
@@ -1068,12 +1101,12 @@
 	err = sys_sem_new(&lpc_enetdata.TxCleanSem, 0);
 	LWIP_ASSERT("TxCleanSem creation error", (err == ERR_OK));
 	sys_thread_new("txclean_thread", packet_tx, netif->state, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY);
-	
+
 	/* periodic PHY status update */
 	osTimerId phy_timer = osTimerCreate(osTimer(phy_update), osTimerPeriodic, (void *)netif);
 	osTimerStart(phy_timer, 250);
 #endif
-    
+
     return ERR_OK;
 }