LPCOpen Platform
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 
65 /*****************************************************************************
66  * Private types/enumerations/variables
67  ****************************************************************************/
68 
69 #define ENET_NUM_TX_DESC 4
70 #define ENET_NUM_RX_DESC 4
71 
74 
75 /* Transmit/receive buffers and indices */
78 static int32_t rxFill, rxGet, rxAvail, rxNumDescs;
79 static int32_t txFill, txGet, txUsed, txNumDescs;
80 
81 /*****************************************************************************
82  * Public types/enumerations/variables
83  ****************************************************************************/
84 
85 /*****************************************************************************
86  * Private functions
87  ****************************************************************************/
88 
89 /* Local delay function used by the ENET or PHY drivers . This can be
90  replaced with something more accurate if needed. */
91 static void localMsDelay(uint32_t ms)
92 {
93  ms = ms * 50000;
94  while (ms > 0) {
95  ms--;
96  }
97 }
98 
99 /* Local index and check function */
100 static __INLINE int32_t incIndex(int32_t index, int32_t max)
101 {
102  index++;
103  if (index >= max) {
104  index = 0;
105  }
106 
107  return index;
108 }
109 
110 /* Initialize MAC descriptors for simple packet receive/transmit */
111 static void InitDescriptors(
112  IP_ENET_001_ENHTXDESC_Type *pTXDescs, int32_t numTXDescs,
113  IP_ENET_001_ENHRXDESC_Type *pRXDescs, int32_t numRXDescs)
114 {
115  int i;
116 
117  /* Setup the descriptor list to a default state */
118  memset(pTXDescs, 0, numTXDescs * sizeof(*pTXDescs));
119  memset(pTXDescs, 0, numRXDescs * sizeof(*pRXDescs));
120  rxFill = rxGet = 0;
121  rxAvail = rxNumDescs = numRXDescs;
122  txNumDescs = numTXDescs;
123  txUsed = txGet = txFill = 0;
124 
125  /* Build linked list, CPU is owner of descriptors */
126  for (i = 0; i < numTXDescs; i++) {
127  pTXDescs[i].CTRLSTAT = 0;
128  pTXDescs[i].B2ADD = (uint32_t) &pTXDescs[i + 1];
129  }
130  pTXDescs[numTXDescs - 1].B2ADD = (uint32_t) &pTXDescs[0];
131  for (i = 0; i < numRXDescs; i++) {
132  pRXDescs[i].STATUS = 0;
133  pRXDescs[i].B2ADD = (uint32_t) &pRXDescs[i + 1];
134  pRXDescs[i].CTRL = RDES_ENH_RCH;
135  }
136  pRXDescs[numRXDescs - 1].B2ADD = (uint32_t) &pRXDescs[0];
137  pRXDescs[numRXDescs - 1].CTRL |= RDES_ENH_RER;
138 
139  /* Setup list pointers in Ethernet controller */
140  Chip_ENET_InitDescriptors(pTXDescs, pRXDescs);
141 }
142 
143 /* Attach a buffer to a descriptor and queue it for reception */
144 static void ENET_RXQueue(void *buffer, int32_t bytes)
145 {
146  if (rxAvail > 0) {
147  /* Queue the next descriptor and start polling */
148  RXDescs[rxFill].B1ADD = (uint32_t) buffer;
149  RXDescs[rxFill].CTRL = RDES_ENH_BS1(bytes) | RDES_ENH_RCH;
150  if (rxFill == (rxNumDescs - 1)) {
151  RXDescs[rxFill].CTRL |= RDES_ENH_RER;
152  }
153  RXDescs[rxFill].STATUS = RDES_OWN;
154  rxAvail--;
156 
157  /* Start polling */
159  }
160 }
161 
162 /* Returns a pointer to a filled ethernet buffer or NULL if none are available */
163 static void *ENET_RXGet(int32_t *bytes)
164 {
165  void *buffer;
166 
167  /* This doesn't check status of the received packet */
168  if ((rxAvail < rxNumDescs) && (!(RXDescs[rxGet].STATUS & RDES_OWN))) {
169  /* CPU owns descriptor, so a packet was received */
170  buffer = (void *) RXDescs[rxGet].B1ADD;
171  *bytes = (int32_t) RXDescs[rxGet].STATUS & 0xFFF;
173  rxAvail++;
174  }
175  else {
176  /* Nothing received */
177  *bytes = 0;
178  buffer = NULL;
179  }
180 
181  return buffer;
182 }
183 
184 /* Attaches a buffer to a transmit descriptor and queues it for transmit */
185 static void ENET_TXQueue(void *buffer, int32_t bytes)
186 {
187  if (txUsed < txNumDescs) {
188  /* Queue the next descriptor and start polling */
189  TXDescs[txFill].B1ADD = (uint32_t) buffer;
190  TXDescs[txFill].BSIZE = TDES_ENH_BS1(bytes);
192  if (txFill == (txNumDescs - 1)) {
193  TXDescs[txFill].CTRLSTAT |= TDES_ENH_TER;
194  }
195  TXDescs[txFill].CTRLSTAT |= TDES_OWN;
196  txUsed++;
198 
199  /* Start polling */
201  }
202 }
203 
204 /* Returns a pointer to a buffer that has been transmitted */
205 static void *ENET_TXBuffClaim(void)
206 {
207  void *buffer;
208 
209  /* Is packet done sending? */
210  if ((txUsed > 0) && (!(TXDescs[txGet].CTRLSTAT & TDES_OWN))) {
211  /* CPU owns descriptor, so the packet completed transmit */
212  buffer = (void *) TXDescs[txGet].B1ADD;
214  txUsed--;
215  Board_LED_Set(2, false);
216  }
217  else {
218  buffer = NULL;
219  }
220 
221  return buffer;
222 }
223 
224 /*****************************************************************************
225  * Public functions
226  ****************************************************************************/
227 
232 void ETH_IRQHandler(void)
233 {
234  /* This demo is entirely polled, so the IRQ isn't really needed */
235 }
236 
241 int main(void)
242 {
243  uint8_t macaddr[6], *workbuff;
244  uint32_t physts = 0;
245  int32_t rxBytes, i, txNextIndex;
246  bool ethpkttgl = true;
247 
248  /* LED0 is used for the link status, on = PHY cable detected */
249  Board_Init();
250  Board_LED_Init();
251 
252  /* Initial LED state is off to show an unconnected cable state */
253  Board_LED_Set(0, false);
254 
255  /* Setup ethernet and PHY */
256  Chip_ENET_Init();
257 #if defined(USE_RMII)
258  lpc_phy_init(true, localMsDelay);
259 #else
260  lpc_phy_init(false, localMsDelay);
261 #endif
262 
263  /* Setup MAC address for device */
264  Board_ENET_GetMacADDR(macaddr);
265  Chip_ENET_SetADDR(macaddr);
266 
267  /* Setup descriptors */
269 
270  /* Attach a buffer to a RX descriptor and queue it for receive */
271  i = 0;
272  while (i < ENET_NUM_RX_DESC) {
274  i++;
275  }
276  txNextIndex = 0;
277 
278  /* Enable RX/TX after descriptors are setup */
279  Chip_ENET_TX_Enable(true);
280  Chip_ENET_RX_Enable(true);
281 
282  while (1) {
283  /* Check for receive packets */
284  workbuff = ENET_RXGet(&rxBytes);
285  if (workbuff) {
286  /* Packet was received. Dump some info from the packet */
287  DEBUGOUT("Packet received: ");
288  ethpkttgl = (bool) !ethpkttgl;
289 
290  /* Toggle LED2 on each packet received */
291  Board_LED_Set(1, ethpkttgl);
292 
293  /* Destination and source MAC addresses */
294  DEBUGOUT("-Dest MAC: %02x:%02x:%02x:%02x:%02x:%02x-",
295  workbuff[0], workbuff[1], workbuff[2], workbuff[3], workbuff[4], workbuff[5]);
296  DEBUGOUT("-Source MAC: %02x:%02x:%02x:%02x:%02x:%02x-",
297  workbuff[6], workbuff[7], workbuff[8], workbuff[9], workbuff[10], workbuff[11]);
298 
299  /* Length of received packet and embedded len/type */
300  DEBUGOUT("-Packet len: %d", rxBytes);
301  DEBUGOUT("-Type: %04x\n", ((((uint32_t) workbuff[12]) << 8) | (((uint32_t) workbuff[13]))));
302 
303  /* Re-queue the (same) packet again */
304  ENET_RXQueue(workbuff, EMAC_ETH_MAX_FLEN);
305  }
306 
307  /* Send a 'dummy' broadcast packet on a keypress. You'll only see this
308  if your using a tool such as WireShark and the packet will not have
309  a checksum */
310  if (DEBUGIN() != EOF) {
311  /* Only if link detected */
312  if (physts & PHY_LINK_CONNECTED) {
313  /* Get next available TX buffer */
314  workbuff = (uint8_t *) TXBuffer[txNextIndex];
315  txNextIndex = incIndex(txNextIndex, ENET_NUM_TX_DESC);
316  /* Destination is broadcast */
317  for (i = 0; i < 6; i++) {
318  workbuff[i] = 0xFF;
319  }
320 
321  /* Source is this MAC address */
322  memcpy(&workbuff[6], macaddr, 6);
323 
324  /* Size will be 128 bytes (total) */
325  workbuff[12] = 0;
326  workbuff[13] = 128;
327 
328  /* Some dummy data, fill beyond end of packet */
329  for (i = 0; i < 128; i++) {
330  workbuff[i + 14] = (uint8_t) (i & 0xFF);
331  }
332 
333  /* Queue TX packet. This is an Ethernet packet, but the payload and
334  hecksum are garbage. The packet will still be viewable with
335  Wireshark */
336  ENET_TXQueue(workbuff, 128);
337  Board_LED_Set(2, true);
338  }
339  }
340 
341  /* Transmit buffers are 'zero-copy' buffers with the queue function, so
342  the buffer must remain in memory until the packet has been fully
343  transmitted. Call ENET_TXBuffClaim() to to reclaim a sent
344  packet. If a packet buffer address is return (not NULL), then the
345  packet can be de-allocated. Since the buffers in this examples are
346  static, there isn't too much to do. */
348 
349  /* PHY status state machine, LED on when connected. This function will
350  not block. */
351  physts = lpcPHYStsPoll();
352 
353  /* Only check for connection state when the PHY status has changed */
354  if (physts & PHY_LINK_CHANGED) {
355  if (physts & PHY_LINK_CONNECTED) {
356  Board_LED_Set(0, true);
357 
358  /* Set interface speed and duplex */
359  Chip_ENET_Set_Duplex((bool) (physts & PHY_LINK_FULLDUPLX));
360  Chip_ENET_Set_Speed((bool) (physts & PHY_LINK_SPEED100));
361  }
362  else {
363  Board_LED_Set(0, false);
364  }
365 
366  DEBUGOUT("Link connect status: %d\n", ((physts & PHY_LINK_CONNECTED) != 0));
367  }
368  }
369 
370  /* Never returns, for warning only */
371  return 0;
372 }
373