LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
enet.c
Go to the documentation of this file.
1 /*
2  * @brief Simple ethernet example
3  * This simple MAC example will listen for all packets on
4  * the ethernet and display some stats via UART when a
5  * packet is received. A dummy packet can also be sent out.
6  * Wireshark can be used to view the outgoing packet.
7  *
8  * @note
9  * Copyright(C) NXP Semiconductors, 2012
10  * All rights reserved.
11  *
12  * @par
13  * Software that is described herein is for illustrative purposes only
14  * which provides customers with programming information regarding the
15  * LPC products. This software is supplied "AS IS" without any warranties of
16  * any kind, and NXP Semiconductors and its licensor disclaim any and
17  * all warranties, express or implied, including all implied warranties of
18  * merchantability, fitness for a particular purpose and non-infringement of
19  * intellectual property rights. NXP Semiconductors assumes no responsibility
20  * or liability for the use of the software, conveys no license or rights under any
21  * patent, copyright, mask work right, or any other intellectual property rights in
22  * or to any products. NXP Semiconductors reserves the right to make changes
23  * in the software without notification. NXP Semiconductors also makes no
24  * representation or warranty that such application will be suitable for the
25  * specified use without further testing or modification.
26  *
27  * @par
28  * Permission to use, copy, modify, and distribute this software and its
29  * documentation is hereby granted, under NXP Semiconductors' and its
30  * licensor's relevant copyrights in the software, without fee, provided that it
31  * is used in conjunction with NXP Semiconductors microcontrollers. This
32  * copyright, permission, and disclaimer notice must appear in all copies of
33  * this code.
34  */
35 
36 #include "board.h"
37 #include <stdio.h>
38 #include <string.h>
39 
73 /*****************************************************************************
74  * Private types/enumerations/variables
75  ****************************************************************************/
76 
77 #define ENET_NUM_TX_DESC 4
78 #define ENET_NUM_RX_DESC 4
79 
82 
83 /* Transmit/receive buffers and indices */
86 static int32_t rxFill, rxGet, rxAvail, rxNumDescs;
87 static int32_t txFill, txGet, txUsed, txNumDescs;
88 
89 /*****************************************************************************
90  * Public types/enumerations/variables
91  ****************************************************************************/
92 
93 /*****************************************************************************
94  * Private functions
95  ****************************************************************************/
96 
97 /* Local delay function used by the ENET or PHY drivers . This can be
98  replaced with something more accurate if needed. */
99 static void localMsDelay(uint32_t ms)
100 {
101  ms = ms * 50000;
102  while (ms > 0) {
103  ms--;
104  }
105 }
106 
107 /* Local index and check function */
108 static __INLINE int32_t incIndex(int32_t index, int32_t max)
109 {
110  index++;
111  if (index >= max) {
112  index = 0;
113  }
114 
115  return index;
116 }
117 
118 /* Initialize MAC descriptors for simple packet receive/transmit */
119 static void InitDescriptors(
120  IP_ENET_001_ENHTXDESC_T *pTXDescs, int32_t numTXDescs,
121  IP_ENET_001_ENHRXDESC_T *pRXDescs, int32_t numRXDescs)
122 {
123  int i;
124 
125  /* Setup the descriptor list to a default state */
126  memset(pTXDescs, 0, numTXDescs * sizeof(*pTXDescs));
127  memset(pTXDescs, 0, numRXDescs * sizeof(*pRXDescs));
128  rxFill = rxGet = 0;
129  rxAvail = rxNumDescs = numRXDescs;
130  txNumDescs = numTXDescs;
131  txUsed = txGet = txFill = 0;
132 
133  /* Build linked list, CPU is owner of descriptors */
134  for (i = 0; i < numTXDescs; i++) {
135  pTXDescs[i].CTRLSTAT = 0;
136  pTXDescs[i].B2ADD = (uint32_t) &pTXDescs[i + 1];
137  }
138  pTXDescs[numTXDescs - 1].B2ADD = (uint32_t) &pTXDescs[0];
139  for (i = 0; i < numRXDescs; i++) {
140  pRXDescs[i].STATUS = 0;
141  pRXDescs[i].B2ADD = (uint32_t) &pRXDescs[i + 1];
142  pRXDescs[i].CTRL = RDES_ENH_RCH;
143  }
144  pRXDescs[numRXDescs - 1].B2ADD = (uint32_t) &pRXDescs[0];
145  pRXDescs[numRXDescs - 1].CTRL |= RDES_ENH_RER;
146 
147  /* Setup list pointers in Ethernet controller */
148  Chip_ENET_InitDescriptors(LPC_ETHERNET, pTXDescs, pRXDescs);
149 }
150 
151 /* Attach a buffer to a descriptor and queue it for reception */
152 static void ENET_RXQueue(void *buffer, int32_t bytes)
153 {
154  if (rxAvail > 0) {
155  /* Queue the next descriptor and start polling */
156  RXDescs[rxFill].B1ADD = (uint32_t) buffer;
157  RXDescs[rxFill].CTRL = RDES_ENH_BS1(bytes) | RDES_ENH_RCH;
158  if (rxFill == (rxNumDescs - 1)) {
159  RXDescs[rxFill].CTRL |= RDES_ENH_RER;
160  }
161  RXDescs[rxFill].STATUS = RDES_OWN;
162  rxAvail--;
164 
165  /* Start polling */
167  }
168 }
169 
170 /* Returns a pointer to a filled ethernet buffer or NULL if none are available */
171 static void *ENET_RXGet(int32_t *bytes)
172 {
173  void *buffer;
174 
175  /* This doesn't check status of the received packet */
176  if ((rxAvail < rxNumDescs) && (!(RXDescs[rxGet].STATUS & RDES_OWN))) {
177  /* CPU owns descriptor, so a packet was received */
178  buffer = (void *) RXDescs[rxGet].B1ADD;
179  *bytes = (int32_t) RXDescs[rxGet].STATUS & 0xFFF;
181  rxAvail++;
182  }
183  else {
184  /* Nothing received */
185  *bytes = 0;
186  buffer = NULL;
187  }
188 
189  return buffer;
190 }
191 
192 /* Attaches a buffer to a transmit descriptor and queues it for transmit */
193 static void ENET_TXQueue(void *buffer, int32_t bytes)
194 {
195  if (txUsed < txNumDescs) {
196  /* Queue the next descriptor and start polling */
197  TXDescs[txFill].B1ADD = (uint32_t) buffer;
198  TXDescs[txFill].BSIZE = TDES_ENH_BS1(bytes);
200  if (txFill == (txNumDescs - 1)) {
201  TXDescs[txFill].CTRLSTAT |= TDES_ENH_TER;
202  }
203  TXDescs[txFill].CTRLSTAT |= TDES_OWN;
204  txUsed++;
206 
207  /* Start polling */
209  }
210 }
211 
212 /* Returns a pointer to a buffer that has been transmitted */
213 static void *ENET_TXBuffClaim(void)
214 {
215  void *buffer;
216 
217  /* Is packet done sending? */
218  if ((txUsed > 0) && (!(TXDescs[txGet].CTRLSTAT & TDES_OWN))) {
219  /* CPU owns descriptor, so the packet completed transmit */
220  buffer = (void *) TXDescs[txGet].B1ADD;
222  txUsed--;
223  Board_LED_Set(2, false);
224  }
225  else {
226  buffer = NULL;
227  }
228 
229  return buffer;
230 }
231 
232 /*****************************************************************************
233  * Public functions
234  ****************************************************************************/
235 
240 void ETH_IRQHandler(void)
241 {
242  /* This demo is entirely polled, so the IRQ isn't really needed */
243 }
244 
249 int main(void)
250 {
251  uint8_t macaddr[6], *workbuff;
252  uint32_t physts = 0;
253  int32_t rxBytes, i, txNextIndex;
254  bool ethpkttgl = true;
255 
256  /* LED0 is used for the link status, on = PHY cable detected */
257  Board_Init();
258 
259  /* Initial LED state is off to show an unconnected cable state */
260  Board_LED_Set(0, false);
261 
262  /* Setup ethernet and PHY */
264 #if defined(USE_RMII)
265  lpc_phy_init(true, localMsDelay);
266 #else
267  lpc_phy_init(false, localMsDelay);
268 #endif
269 
270  /* Setup MAC address for device */
271  Board_ENET_GetMacADDR(macaddr);
273 
274  /* Setup descriptors */
276 
277  /* Attach a buffer to a RX descriptor and queue it for receive */
278  i = 0;
279  while (i < ENET_NUM_RX_DESC) {
281  i++;
282  }
283  txNextIndex = 0;
284 
285  /* Enable RX/TX after descriptors are setup */
288 
289  while (1) {
290  /* Check for receive packets */
291  workbuff = ENET_RXGet(&rxBytes);
292  if (workbuff) {
293  /* Packet was received. Dump some info from the packet */
294  DEBUGOUT("Packet received: ");
295  ethpkttgl = (bool) !ethpkttgl;
296 
297  /* Toggle LED2 on each packet received */
298  Board_LED_Set(1, ethpkttgl);
299 
300  /* Destination and source MAC addresses */
301  DEBUGOUT("-Dest MAC: %02x:%02x:%02x:%02x:%02x:%02x-",
302  workbuff[0], workbuff[1], workbuff[2], workbuff[3], workbuff[4], workbuff[5]);
303  DEBUGOUT("-Source MAC: %02x:%02x:%02x:%02x:%02x:%02x-",
304  workbuff[6], workbuff[7], workbuff[8], workbuff[9], workbuff[10], workbuff[11]);
305 
306  /* Length of received packet and embedded len/type */
307  DEBUGOUT("-Packet len: %d", rxBytes);
308  DEBUGOUT("-Type: %04x\r\n", ((((uint32_t) workbuff[12]) << 8) | (((uint32_t) workbuff[13]))));
309 
310  /* Re-queue the (same) packet again */
311  ENET_RXQueue(workbuff, EMAC_ETH_MAX_FLEN);
312  }
313 
314  /* Send a 'dummy' broadcast packet on a keypress. You'll only see this
315  if your using a tool such as WireShark and the packet will not have
316  a checksum */
317  if (DEBUGIN() != EOF) {
318  /* Only if link detected */
319  if (physts & PHY_LINK_CONNECTED) {
320  /* Get next available TX buffer */
321  workbuff = (uint8_t *) TXBuffer[txNextIndex];
322  txNextIndex = incIndex(txNextIndex, ENET_NUM_TX_DESC);
323  /* Destination is broadcast */
324  for (i = 0; i < 6; i++) {
325  workbuff[i] = 0xFF;
326  }
327 
328  /* Source is this MAC address */
329  memcpy(&workbuff[6], macaddr, 6);
330 
331  /* Size will be 128 bytes (total) */
332  workbuff[12] = 0;
333  workbuff[13] = 128;
334 
335  /* Some dummy data, fill beyond end of packet */
336  for (i = 0; i < 128; i++) {
337  workbuff[i + 14] = (uint8_t) (i & 0xFF);
338  }
339 
340  /* Queue TX packet. This is an Ethernet packet, but the payload and
341  hecksum are garbage. The packet will still be viewable with
342  Wireshark */
343  ENET_TXQueue(workbuff, 128);
344  Board_LED_Set(2, true);
345  }
346  }
347 
348  /* Transmit buffers are 'zero-copy' buffers with the queue function, so
349  the buffer must remain in memory until the packet has been fully
350  transmitted. Call ENET_TXBuffClaim() to to reclaim a sent
351  packet. If a packet buffer address is return (not NULL), then the
352  packet can be de-allocated. Since the buffers in this examples are
353  static, there isn't too much to do. */
355 
356  /* PHY status state machine, LED on when connected. This function will
357  not block. */
358  physts = lpcPHYStsPoll();
359 
360  /* Only check for connection state when the PHY status has changed */
361  if (physts & PHY_LINK_CHANGED) {
362  if (physts & PHY_LINK_CONNECTED) {
363  Board_LED_Set(0, true);
364 
365  /* Set interface speed and duplex */
368  }
369  else {
370  Board_LED_Set(0, false);
371  }
372 
373  DEBUGOUT("Link connect status: %d\r\n", ((physts & PHY_LINK_CONNECTED) != 0));
374  }
375  }
376 
377  /* Never returns, for warning only */
378  return 0;
379 }
380