]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_LPC1768_GCC_Rowley/webserver/emac.c
c8f2648dbb6486c5997d8ab4ce95ccbedd378e00
[freertos] / FreeRTOS / Demo / CORTEX_LPC1768_GCC_Rowley / webserver / emac.c
1 /*\r
2     FreeRTOS V7.4.0 - Copyright (C) 2013 Real Time Engineers Ltd.\r
3 \r
4     FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME.  PLEASE VISIT\r
5     http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     ***************************************************************************\r
8      *                                                                       *\r
9      *    FreeRTOS tutorial books are available in pdf and paperback.        *\r
10      *    Complete, revised, and edited pdf reference manuals are also       *\r
11      *    available.                                                         *\r
12      *                                                                       *\r
13      *    Purchasing FreeRTOS documentation will not only help you, by       *\r
14      *    ensuring you get running as quickly as possible and with an        *\r
15      *    in-depth knowledge of how to use FreeRTOS, it will also help       *\r
16      *    the FreeRTOS project to continue with its mission of providing     *\r
17      *    professional grade, cross platform, de facto standard solutions    *\r
18      *    for microcontrollers - completely free of charge!                  *\r
19      *                                                                       *\r
20      *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *\r
21      *                                                                       *\r
22      *    Thank you for using FreeRTOS, and thank you for your support!      *\r
23      *                                                                       *\r
24     ***************************************************************************\r
25 \r
26 \r
27     This file is part of the FreeRTOS distribution.\r
28 \r
29     FreeRTOS is free software; you can redistribute it and/or modify it under\r
30     the terms of the GNU General Public License (version 2) as published by the\r
31     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
32 \r
33     >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to\r
34     distribute a combined work that includes FreeRTOS without being obliged to\r
35     provide the source code for proprietary components outside of the FreeRTOS\r
36     kernel.\r
37 \r
38     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
39     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
40     FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\r
41     details. You should have received a copy of the GNU General Public License\r
42     and the FreeRTOS license exception along with FreeRTOS; if not itcan be\r
43     viewed here: http://www.freertos.org/a00114.html and also obtained by\r
44     writing to Real Time Engineers Ltd., contact details for whom are available\r
45     on the FreeRTOS WEB site.\r
46 \r
47     1 tab == 4 spaces!\r
48 \r
49     ***************************************************************************\r
50      *                                                                       *\r
51      *    Having a problem?  Start by reading the FAQ "My application does   *\r
52      *    not run, what could be wrong?"                                     *\r
53      *                                                                       *\r
54      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
55      *                                                                       *\r
56     ***************************************************************************\r
57 \r
58 \r
59     http://www.FreeRTOS.org - Documentation, books, training, latest versions, \r
60     license and Real Time Engineers Ltd. contact details.\r
61 \r
62     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
63     including FreeRTOS+Trace - an indispensable productivity tool, and our new\r
64     fully thread aware and reentrant UDP/IP stack.\r
65 \r
66     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High \r
67     Integrity Systems, who sell the code with commercial support, \r
68     indemnification and middleware, under the OpenRTOS brand.\r
69     \r
70     http://www.SafeRTOS.com - High Integrity Systems also provide a safety \r
71     engineered and independently SIL3 certified version for use in safety and \r
72     mission critical applications that require provable dependability.\r
73 */\r
74 \r
75 /* Originally adapted from file written by Andreas Dannenberg.  Supplied with permission. */\r
76 \r
77 /* Kernel includes. */\r
78 #include "FreeRTOS.h"\r
79 #include "task.h"\r
80 #include "semphr.h"\r
81 \r
82 /* Hardware specific includes. */\r
83 #include "EthDev_LPC17xx.h"\r
84 \r
85 /* Time to wait between each inspection of the link status. */\r
86 #define emacWAIT_FOR_LINK_TO_ESTABLISH ( 500 / portTICK_RATE_MS )\r
87 \r
88 /* Short delay used in several places during the initialisation process. */\r
89 #define emacSHORT_DELAY                            ( 2 )\r
90 \r
91 /* Hardware specific bit definitions. */\r
92 #define emacLINK_ESTABLISHED            ( 0x0001 )\r
93 #define emacFULL_DUPLEX_ENABLED         ( 0x0004 )\r
94 #define emac10BASE_T_MODE                       ( 0x0002 )\r
95 #define emacPINSEL2_VALUE                       ( 0x50150105 )\r
96 \r
97 /* If no buffers are available, then wait this long before looking again.... */\r
98 #define emacBUFFER_WAIT_DELAY   ( 3 / portTICK_RATE_MS )\r
99 \r
100 /* ...and don't look more than this many times. */\r
101 #define emacBUFFER_WAIT_ATTEMPTS        ( 30 )\r
102 \r
103 /* Index to the Tx descriptor that is always used first for every Tx.  The second\r
104 descriptor is then used to re-send in order to speed up the uIP Tx process. */\r
105 #define emacTX_DESC_INDEX                       ( 0 )\r
106 \r
107 /*-----------------------------------------------------------*/\r
108 \r
109 /*\r
110  * Configure both the Rx and Tx descriptors during the init process.\r
111  */\r
112 static void prvInitDescriptors( void );\r
113 \r
114 /*\r
115  * Setup the IO and peripherals required for Ethernet communication.\r
116  */\r
117 static void prvSetupEMACHardware( void );\r
118 \r
119 /*\r
120  * Control the auto negotiate process.\r
121  */\r
122 static void prvConfigurePHY( void );\r
123 \r
124 /*\r
125  * Wait for a link to be established, then setup the PHY according to the link\r
126  * parameters.\r
127  */\r
128 static long prvSetupLinkStatus( void );\r
129 \r
130 /*\r
131  * Search the pool of buffers to find one that is free.  If a buffer is found\r
132  * mark it as in use before returning its address.\r
133  */\r
134 static unsigned char *prvGetNextBuffer( void );\r
135 \r
136 /*\r
137  * Return an allocated buffer to the pool of free buffers.\r
138  */\r
139 static void prvReturnBuffer( unsigned char *pucBuffer );\r
140 \r
141 /*\r
142  * Send lValue to the lPhyReg within the PHY.\r
143  */\r
144 static long prvWritePHY( long lPhyReg, long lValue );\r
145 \r
146 /*\r
147  * Read a value from ucPhyReg within the PHY.  *plStatus will be set to\r
148  * pdFALSE if there is an error.\r
149  */\r
150 static unsigned short prvReadPHY( unsigned char ucPhyReg, long *plStatus );\r
151 \r
152 /*-----------------------------------------------------------*/\r
153 \r
154 /* The semaphore used to wake the uIP task when data arrives. */\r
155 extern xSemaphoreHandle xEMACSemaphore;\r
156 \r
157 /* Each ucBufferInUse index corresponds to a position in the pool of buffers.\r
158 If the index contains a 1 then the buffer within pool is in use, if it\r
159 contains a 0 then the buffer is free. */\r
160 static unsigned char ucBufferInUse[ ETH_NUM_BUFFERS ] = { pdFALSE };\r
161 \r
162 /* The uip_buffer is not a fixed array, but instead gets pointed to the buffers\r
163 allocated within this file. */\r
164 unsigned char * uip_buf;\r
165 \r
166 /* Store the length of the data being sent so the data can be sent twice.  The\r
167 value will be set back to 0 once the data has been sent twice. */\r
168 static unsigned short usSendLen = 0;\r
169 \r
170 /*-----------------------------------------------------------*/\r
171 \r
172 long lEMACInit( void )\r
173 {\r
174 long lReturn = pdPASS;\r
175 unsigned long ulID1, ulID2;\r
176 \r
177         /* Reset peripherals, configure port pins and registers. */\r
178         prvSetupEMACHardware();\r
179 \r
180         /* Check the PHY part number is as expected. */\r
181         ulID1 = prvReadPHY( PHY_REG_IDR1, &lReturn );\r
182         ulID2 = prvReadPHY( PHY_REG_IDR2, &lReturn );\r
183         if( ( (ulID1 << 16UL ) | ( ulID2 & 0xFFF0UL ) ) == DP83848C_ID )\r
184         {\r
185                 /* Set the Ethernet MAC Address registers */\r
186                 EMAC->SA0 = ( configMAC_ADDR0 << 8 ) | configMAC_ADDR1;\r
187                 EMAC->SA1 = ( configMAC_ADDR2 << 8 ) | configMAC_ADDR3;\r
188                 EMAC->SA2 = ( configMAC_ADDR4 << 8 ) | configMAC_ADDR5;\r
189 \r
190                 /* Initialize Tx and Rx DMA Descriptors */\r
191                 prvInitDescriptors();\r
192 \r
193                 /* Receive broadcast and perfect match packets */\r
194                 EMAC->RxFilterCtrl = RFC_UCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN;\r
195 \r
196                 /* Setup the PHY. */\r
197                 prvConfigurePHY();\r
198         }\r
199         else\r
200         {\r
201                 lReturn = pdFAIL;\r
202         }\r
203 \r
204         /* Check the link status. */\r
205         if( lReturn == pdPASS )\r
206         {\r
207                 lReturn = prvSetupLinkStatus();\r
208         }\r
209 \r
210         if( lReturn == pdPASS )\r
211         {\r
212                 /* Initialise uip_buf to ensure it points somewhere valid. */\r
213                 uip_buf = prvGetNextBuffer();\r
214 \r
215                 /* Reset all interrupts */\r
216                 EMAC->IntClear = ( INT_RX_OVERRUN | INT_RX_ERR | INT_RX_FIN | INT_RX_DONE | INT_TX_UNDERRUN | INT_TX_ERR | INT_TX_FIN | INT_TX_DONE | INT_SOFT_INT | INT_WAKEUP );\r
217 \r
218                 /* Enable receive and transmit mode of MAC Ethernet core */\r
219                 EMAC->Command |= ( CR_RX_EN | CR_TX_EN );\r
220                 EMAC->MAC1 |= MAC1_REC_EN;\r
221         }\r
222 \r
223         return lReturn;\r
224 }\r
225 /*-----------------------------------------------------------*/\r
226 \r
227 static unsigned char *prvGetNextBuffer( void )\r
228 {\r
229 long x;\r
230 unsigned char *pucReturn = NULL;\r
231 unsigned long ulAttempts = 0;\r
232 \r
233         while( pucReturn == NULL )\r
234         {\r
235                 /* Look through the buffers to find one that is not in use by\r
236                 anything else. */\r
237                 for( x = 0; x < ETH_NUM_BUFFERS; x++ )\r
238                 {\r
239                         if( ucBufferInUse[ x ] == pdFALSE )\r
240                         {\r
241                                 ucBufferInUse[ x ] = pdTRUE;\r
242                                 pucReturn = ( unsigned char * ) ETH_BUF( x );\r
243                                 break;\r
244                         }\r
245                 }\r
246 \r
247                 /* Was a buffer found? */\r
248                 if( pucReturn == NULL )\r
249                 {\r
250                         ulAttempts++;\r
251 \r
252                         if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )\r
253                         {\r
254                                 break;\r
255                         }\r
256 \r
257                         /* Wait then look again. */\r
258                         vTaskDelay( emacBUFFER_WAIT_DELAY );\r
259                 }\r
260         }\r
261 \r
262         return pucReturn;\r
263 }\r
264 /*-----------------------------------------------------------*/\r
265 \r
266 static void prvInitDescriptors( void )\r
267 {\r
268 long x, lNextBuffer = 0;\r
269 \r
270         for( x = 0; x < NUM_RX_FRAG; x++ )\r
271         {\r
272                 /* Allocate the next Ethernet buffer to this descriptor. */\r
273                 RX_DESC_PACKET( x ) = ETH_BUF( lNextBuffer );\r
274                 RX_DESC_CTRL( x ) = RCTRL_INT | ( ETH_FRAG_SIZE - 1 );\r
275                 RX_STAT_INFO( x ) = 0;\r
276                 RX_STAT_HASHCRC( x ) = 0;\r
277 \r
278                 /* The Ethernet buffer is now in use. */\r
279                 ucBufferInUse[ lNextBuffer ] = pdTRUE;\r
280                 lNextBuffer++;\r
281         }\r
282 \r
283         /* Set EMAC Receive Descriptor Registers. */\r
284         EMAC->RxDescriptor = RX_DESC_BASE;\r
285         EMAC->RxStatus = RX_STAT_BASE;\r
286         EMAC->RxDescriptorNumber = NUM_RX_FRAG - 1;\r
287 \r
288         /* Rx Descriptors Point to 0 */\r
289         EMAC->RxConsumeIndex = 0;\r
290 \r
291         /* A buffer is not allocated to the Tx descriptors until they are actually\r
292         used. */\r
293         for( x = 0; x < NUM_TX_FRAG; x++ )\r
294         {\r
295                 TX_DESC_PACKET( x ) = ( unsigned long ) NULL;\r
296                 TX_DESC_CTRL( x ) = 0;\r
297                 TX_STAT_INFO( x ) = 0;\r
298         }\r
299 \r
300         /* Set EMAC Transmit Descriptor Registers. */\r
301         EMAC->TxDescriptor = TX_DESC_BASE;\r
302         EMAC->TxStatus = TX_STAT_BASE;\r
303         EMAC->TxDescriptorNumber = NUM_TX_FRAG - 1;\r
304 \r
305         /* Tx Descriptors Point to 0 */\r
306         EMAC->TxProduceIndex = 0;\r
307 }\r
308 /*-----------------------------------------------------------*/\r
309 \r
310 static void prvSetupEMACHardware( void )\r
311 {\r
312 unsigned short us;\r
313 long x, lDummy;\r
314 \r
315         /* Enable P1 Ethernet Pins. */\r
316         PINCON->PINSEL2 = emacPINSEL2_VALUE;\r
317         PINCON->PINSEL3 = ( PINCON->PINSEL3 & ~0x0000000F ) | 0x00000005;\r
318 \r
319         /* Power Up the EMAC controller. */\r
320         SC->PCONP |= PCONP_PCENET;\r
321         vTaskDelay( emacSHORT_DELAY );\r
322 \r
323         /* Reset all EMAC internal modules. */\r
324         EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES;\r
325         EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM;\r
326 \r
327         /* A short delay after reset. */\r
328         vTaskDelay( emacSHORT_DELAY );\r
329 \r
330         /* Initialize MAC control registers. */\r
331         EMAC->MAC1 = MAC1_PASS_ALL;\r
332         EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;\r
333         EMAC->MAXF = ETH_MAX_FLEN;\r
334         EMAC->CLRT = CLRT_DEF;\r
335         EMAC->IPGR = IPGR_DEF;\r
336 \r
337         /* Enable Reduced MII interface. */\r
338         EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM;\r
339 \r
340         /* Reset Reduced MII Logic. */\r
341         EMAC->SUPP = SUPP_RES_RMII;\r
342         vTaskDelay( emacSHORT_DELAY );\r
343         EMAC->SUPP = 0;\r
344 \r
345         /* Put the PHY in reset mode */\r
346         prvWritePHY( PHY_REG_BMCR, MCFG_RES_MII );\r
347         prvWritePHY( PHY_REG_BMCR, MCFG_RES_MII );\r
348 \r
349         /* Wait for hardware reset to end. */\r
350         for( x = 0; x < 100; x++ )\r
351         {\r
352                 vTaskDelay( emacSHORT_DELAY * 5 );\r
353                 us = prvReadPHY( PHY_REG_BMCR, &lDummy );\r
354                 if( !( us & MCFG_RES_MII ) )\r
355                 {\r
356                         /* Reset complete */\r
357                         break;\r
358                 }\r
359         }\r
360 }\r
361 /*-----------------------------------------------------------*/\r
362 \r
363 static void prvConfigurePHY( void )\r
364 {\r
365 unsigned short us;\r
366 long x, lDummy;\r
367 \r
368         /* Auto negotiate the configuration. */\r
369         if( prvWritePHY( PHY_REG_BMCR, PHY_AUTO_NEG ) )\r
370         {\r
371                 vTaskDelay( emacSHORT_DELAY * 5 );\r
372 \r
373                 for( x = 0; x < 10; x++ )\r
374                 {\r
375                         us = prvReadPHY( PHY_REG_BMSR, &lDummy );\r
376 \r
377                         if( us & PHY_AUTO_NEG_COMPLETE )\r
378                         {\r
379                                 break;\r
380                         }\r
381 \r
382                         vTaskDelay( emacWAIT_FOR_LINK_TO_ESTABLISH );\r
383                 }\r
384         }\r
385 }\r
386 /*-----------------------------------------------------------*/\r
387 \r
388 static long prvSetupLinkStatus( void )\r
389 {\r
390 long lReturn = pdFAIL, x;\r
391 unsigned short usLinkStatus;\r
392 \r
393         /* Wait with timeout for the link to be established. */\r
394         for( x = 0; x < 10; x++ )\r
395         {\r
396                 usLinkStatus = prvReadPHY( PHY_REG_STS, &lReturn );\r
397                 if( usLinkStatus & emacLINK_ESTABLISHED )\r
398                 {\r
399                         /* Link is established. */\r
400                         lReturn = pdPASS;\r
401                         break;\r
402                 }\r
403 \r
404         vTaskDelay( emacWAIT_FOR_LINK_TO_ESTABLISH );\r
405         }\r
406 \r
407         if( lReturn == pdPASS )\r
408         {\r
409                 /* Configure Full/Half Duplex mode. */\r
410                 if( usLinkStatus & emacFULL_DUPLEX_ENABLED )\r
411                 {\r
412                         /* Full duplex is enabled. */\r
413                         EMAC->MAC2 |= MAC2_FULL_DUP;\r
414                         EMAC->Command |= CR_FULL_DUP;\r
415                         EMAC->IPGT = IPGT_FULL_DUP;\r
416                 }\r
417                 else\r
418                 {\r
419                         /* Half duplex mode. */\r
420                         EMAC->IPGT = IPGT_HALF_DUP;\r
421                 }\r
422 \r
423                 /* Configure 100MBit/10MBit mode. */\r
424                 if( usLinkStatus & emac10BASE_T_MODE )\r
425                 {\r
426                         /* 10MBit mode. */\r
427                         EMAC->SUPP = 0;\r
428                 }\r
429                 else\r
430                 {\r
431                         /* 100MBit mode. */\r
432                         EMAC->SUPP = SUPP_SPEED;\r
433                 }\r
434         }\r
435 \r
436         return lReturn;\r
437 }\r
438 /*-----------------------------------------------------------*/\r
439 \r
440 static void prvReturnBuffer( unsigned char *pucBuffer )\r
441 {\r
442 unsigned long ul;\r
443 \r
444         /* Return a buffer to the pool of free buffers. */\r
445         for( ul = 0; ul < ETH_NUM_BUFFERS; ul++ )\r
446         {\r
447                 if( ETH_BUF( ul ) == ( unsigned long ) pucBuffer )\r
448                 {\r
449                         ucBufferInUse[ ul ] = pdFALSE;\r
450                         break;\r
451                 }\r
452         }\r
453 }\r
454 /*-----------------------------------------------------------*/\r
455 \r
456 unsigned long ulGetEMACRxData( void )\r
457 {\r
458 unsigned long ulLen = 0;\r
459 long lIndex;\r
460 \r
461         if( EMAC->RxProduceIndex != EMAC->RxConsumeIndex )\r
462         {\r
463                 /* Mark the current buffer as free as uip_buf is going to be set to\r
464                 the buffer that contains the received data. */\r
465                 prvReturnBuffer( uip_buf );\r
466 \r
467                 ulLen = ( RX_STAT_INFO( EMAC->RxConsumeIndex ) & RINFO_SIZE ) - 3;\r
468                 uip_buf = ( unsigned char * ) RX_DESC_PACKET( EMAC->RxConsumeIndex );\r
469 \r
470                 /* Allocate a new buffer to the descriptor. */\r
471         RX_DESC_PACKET( EMAC->RxConsumeIndex ) = ( unsigned long ) prvGetNextBuffer();\r
472 \r
473                 /* Move the consume index onto the next position, ensuring it wraps to\r
474                 the beginning at the appropriate place. */\r
475                 lIndex = EMAC->RxConsumeIndex;\r
476 \r
477                 lIndex++;\r
478                 if( lIndex >= NUM_RX_FRAG )\r
479                 {\r
480                         lIndex = 0;\r
481                 }\r
482 \r
483                 EMAC->RxConsumeIndex = lIndex;\r
484         }\r
485 \r
486         return ulLen;\r
487 }\r
488 /*-----------------------------------------------------------*/\r
489 \r
490 void vSendEMACTxData( unsigned short usTxDataLen )\r
491 {\r
492 unsigned long ulAttempts = 0UL;\r
493 \r
494         /* Check to see if the Tx descriptor is free, indicated by its buffer being\r
495         NULL. */\r
496         while( TX_DESC_PACKET( emacTX_DESC_INDEX ) != ( unsigned long ) NULL )\r
497         {\r
498                 /* Wait for the Tx descriptor to become available. */\r
499                 vTaskDelay( emacBUFFER_WAIT_DELAY );\r
500 \r
501                 ulAttempts++;\r
502                 if( ulAttempts > emacBUFFER_WAIT_ATTEMPTS )\r
503                 {\r
504                         /* Something has gone wrong as the Tx descriptor is still in use.\r
505                         Clear it down manually, the data it was sending will probably be\r
506                         lost. */\r
507                         prvReturnBuffer( ( unsigned char * ) TX_DESC_PACKET( emacTX_DESC_INDEX ) );\r
508                         break;\r
509                 }\r
510         }\r
511 \r
512         /* Setup the Tx descriptor for transmission.  Remember the length of the\r
513         data being sent so the second descriptor can be used to send it again from\r
514         within the ISR. */\r
515         usSendLen = usTxDataLen;\r
516         TX_DESC_PACKET( emacTX_DESC_INDEX ) = ( unsigned long ) uip_buf;\r
517         TX_DESC_CTRL( emacTX_DESC_INDEX ) = ( usTxDataLen | TCTRL_LAST | TCTRL_INT );\r
518         EMAC->TxProduceIndex = ( emacTX_DESC_INDEX + 1 );\r
519 \r
520         /* uip_buf is being sent by the Tx descriptor.  Allocate a new buffer. */\r
521         uip_buf = prvGetNextBuffer();\r
522 }\r
523 /*-----------------------------------------------------------*/\r
524 \r
525 static long prvWritePHY( long lPhyReg, long lValue )\r
526 {\r
527 const long lMaxTime = 10;\r
528 long x;\r
529 \r
530         EMAC->MADR = DP83848C_DEF_ADR | lPhyReg;\r
531         EMAC->MWTD = lValue;\r
532 \r
533         x = 0;\r
534         for( x = 0; x < lMaxTime; x++ )\r
535         {\r
536                 if( ( EMAC->MIND & MIND_BUSY ) == 0 )\r
537                 {\r
538                         /* Operation has finished. */\r
539                         break;\r
540                 }\r
541 \r
542                 vTaskDelay( emacSHORT_DELAY );\r
543         }\r
544 \r
545         if( x < lMaxTime )\r
546         {\r
547                 return pdPASS;\r
548         }\r
549         else\r
550         {\r
551                 return pdFAIL;\r
552         }\r
553 }\r
554 /*-----------------------------------------------------------*/\r
555 \r
556 static unsigned short prvReadPHY( unsigned char ucPhyReg, long *plStatus )\r
557 {\r
558 long x;\r
559 const long lMaxTime = 10;\r
560 \r
561         EMAC->MADR = DP83848C_DEF_ADR | ucPhyReg;\r
562         EMAC->MCMD = MCMD_READ;\r
563 \r
564         for( x = 0; x < lMaxTime; x++ )\r
565         {\r
566                 /* Operation has finished. */\r
567                 if( ( EMAC->MIND & MIND_BUSY ) == 0 )\r
568                 {\r
569                         break;\r
570                 }\r
571 \r
572                 vTaskDelay( emacSHORT_DELAY );\r
573         }\r
574 \r
575         EMAC->MCMD = 0;\r
576 \r
577         if( x >= lMaxTime )\r
578         {\r
579                 *plStatus = pdFAIL;\r
580         }\r
581 \r
582         return( EMAC->MRDD );\r
583 }\r
584 /*-----------------------------------------------------------*/\r
585 \r
586 void vEMAC_ISR( void )\r
587 {\r
588 unsigned long ulStatus;\r
589 long lHigherPriorityTaskWoken = pdFALSE;\r
590 \r
591         ulStatus = EMAC->IntStatus;\r
592 \r
593         /* Clear the interrupt. */\r
594         EMAC->IntClear = ulStatus;\r
595 \r
596         if( ulStatus & INT_RX_DONE )\r
597         {\r
598                 /* Ensure the uIP task is not blocked as data has arrived. */\r
599                 xSemaphoreGiveFromISR( xEMACSemaphore, &lHigherPriorityTaskWoken );\r
600         }\r
601 \r
602         if( ulStatus & INT_TX_DONE )\r
603         {\r
604                 if( usSendLen > 0 )\r
605                 {\r
606                         /* Send the data again, using the second descriptor.  As there are\r
607                         only two descriptors the index is set back to 0. */\r
608                         TX_DESC_PACKET( ( emacTX_DESC_INDEX + 1 ) ) = TX_DESC_PACKET( emacTX_DESC_INDEX );\r
609                         TX_DESC_CTRL( ( emacTX_DESC_INDEX + 1 ) ) = ( usSendLen | TCTRL_LAST | TCTRL_INT );\r
610                         EMAC->TxProduceIndex = ( emacTX_DESC_INDEX );\r
611 \r
612                         /* This is the second Tx so set usSendLen to 0 to indicate that the\r
613                         Tx descriptors will be free again. */\r
614                         usSendLen = 0UL;\r
615                 }\r
616                 else\r
617                 {\r
618                         /* The Tx buffer is no longer required. */\r
619                         prvReturnBuffer( ( unsigned char * ) TX_DESC_PACKET( emacTX_DESC_INDEX ) );\r
620             TX_DESC_PACKET( emacTX_DESC_INDEX ) = ( unsigned long ) NULL;\r
621                 }\r
622         }\r
623 \r
624         portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );\r
625 }\r