2 FreeRTOS V7.3.0 - Copyright (C) 2012 Real Time Engineers Ltd.
\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
7 ***************************************************************************
\r
9 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
10 * Complete, revised, and edited pdf reference manuals are also *
\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
20 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
22 * Thank you for using FreeRTOS, and thank you for your support! *
\r
24 ***************************************************************************
\r
27 This file is part of the FreeRTOS distribution.
\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 >>>NOTE<<< The modification to the GPL is included to allow you to
\r
33 distribute a combined work that includes FreeRTOS without being obliged to
\r
34 provide the source code for proprietary components outside of the FreeRTOS
\r
35 kernel. FreeRTOS is distributed in the hope that it will be useful, but
\r
36 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
37 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
38 more details. You should have received a copy of the GNU General Public
\r
39 License and the FreeRTOS license exception along with FreeRTOS; if not it
\r
40 can be viewed here: http://www.freertos.org/a00114.html and also obtained
\r
41 by writing to Richard Barry, contact details for whom are available on the
\r
46 ***************************************************************************
\r
48 * Having a problem? Start by reading the FAQ "My application does *
\r
49 * not run, what could be wrong?" *
\r
51 * http://www.FreeRTOS.org/FAQHelp.html *
\r
53 ***************************************************************************
\r
56 http://www.FreeRTOS.org - Documentation, training, latest versions, license
\r
57 and contact details.
\r
59 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
60 including FreeRTOS+Trace - an indispensable productivity tool.
\r
62 Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell
\r
63 the code with commercial support, indemnification, and middleware, under
\r
64 the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also
\r
65 provide a safety engineered and independently SIL3 certified version under
\r
66 the SafeRTOS brand: http://www.SafeRTOS.com.
\r
69 /* Freescale includes. */
\r
71 #include "eth_phy.h"
\r
75 /* FreeRTOS includes. */
\r
76 #include "FreeRTOS.h"
\r
81 #include "net/uip.h"
\r
83 /* The time to wait between attempts to obtain a free buffer. */
\r
84 #define emacBUFFER_WAIT_DELAY_ms ( 3 / portTICK_RATE_MS )
\r
86 /* The number of times emacBUFFER_WAIT_DELAY_ms should be waited before giving
\r
87 up on attempting to obtain a free buffer all together. */
\r
88 #define emacBUFFER_WAIT_ATTEMPTS ( 30 )
\r
90 /* The number of Rx descriptors. */
\r
91 #define emacNUM_RX_DESCRIPTORS 8
\r
93 /* The number of Tx descriptors. When using uIP there is not point in having
\r
95 #define emacNUM_TX_BUFFERS 2
\r
97 /* The total number of EMAC buffers to allocate. */
\r
98 #define emacNUM_BUFFERS ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )
\r
100 /* The time to wait for the Tx descriptor to become free. */
\r
101 #define emacTX_WAIT_DELAY_ms ( 10 / portTICK_RATE_MS )
\r
103 /* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to
\r
105 #define emacTX_WAIT_ATTEMPTS ( 50 )
\r
107 /* Constants used for set up and initialisation. */
\r
108 #define emacTX_INTERRUPT_NO ( 76 )
\r
109 #define emacRX_INTERRUPT_NO ( 77 )
\r
110 #define emacERROR_INTERRUPT_NO ( 78 )
\r
111 #define emacLINK_DELAY ( 500 / portTICK_RATE_MS )
\r
112 #define emacPHY_STATUS ( 0x1F )
\r
113 #define emacPHY_DUPLEX_STATUS ( 4 << 2 )
\r
114 #define emacPHY_SPEED_STATUS ( 1 << 2 )
\r
116 /*-----------------------------------------------------------*/
\r
119 * Initialise both the Rx and Tx descriptors.
\r
121 static void prvInitialiseDescriptors( void );
\r
124 * Return a pointer to a free buffer within xEthernetBuffers.
\r
126 static unsigned char *prvGetNextBuffer( void );
\r
129 * Return a buffer to the list of free buffers.
\r
131 static void prvReturnBuffer( unsigned char *pucBuffer );
\r
134 * Examine the status of the next Rx descriptor to see if it contains new data.
\r
136 static unsigned short prvCheckRxStatus( void );
\r
139 * Something has gone wrong with the descriptor usage. Reset all the buffers
\r
142 static void prvResetEverything( void );
\r
144 /*-----------------------------------------------------------*/
\r
146 /* The buffers and descriptors themselves. */
\r
147 #pragma data_alignment=16
\r
148 volatile NBUF xRxDescriptors[ emacNUM_RX_DESCRIPTORS ];
\r
150 #pragma data_alignment=16
\r
151 volatile NBUF xTxDescriptors[ emacNUM_TX_BUFFERS ];
\r
153 #pragma data_alignment=16
\r
154 char xEthernetBuffers[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];
\r
156 /* Used to indicate which buffers are free and which are in use. If an index
\r
157 contains 0 then the corresponding buffer in xEthernetBuffers is free, otherwise
\r
158 the buffer is in use or about to be used. */
\r
159 static unsigned char ucBufferInUse[ emacNUM_BUFFERS ];
\r
161 /* Points to the Rx descriptor currently in use. */
\r
162 static volatile NBUF *pxCurrentRxDesc = NULL;
\r
164 /* pxCurrentRxDesc points to descriptor within the xRxDescriptors array that
\r
165 has an index defined by ulRxDescriptorIndex. */
\r
166 static unsigned long ulRxDescriptorIndex = 0UL;
\r
168 /* The buffer used by the uIP stack to both receive and send. This points to
\r
169 one of the Ethernet buffers when its actually in use. */
\r
170 unsigned char *uip_buf = NULL;
\r
172 /*-----------------------------------------------------------*/
\r
174 void vEMACInit( void )
\r
177 extern int periph_clk_khz;
\r
178 const unsigned portCHAR ucMACAddress[] =
\r
180 configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5
\r
183 /* Enable the ENET clock. */
\r
184 SIM_SCGC2 |= SIM_SCGC2_ENET_MASK;
\r
186 /* Allow concurrent access to MPU controller to avoid bus errors. */
\r
189 prvInitialiseDescriptors();
\r
191 /* Reset and enable. */
\r
192 ENET_ECR = ENET_ECR_RESET_MASK;
\r
194 /* Wait at least 8 clock cycles */
\r
197 /* Start the MII interface*/
\r
198 mii_init( 0, periph_clk_khz / 1000L );
\r
200 /* Configure the transmit interrupt. */
\r
201 set_irq_priority( emacTX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
\r
202 enable_irq( emacTX_INTERRUPT_NO );
\r
204 /* Configure the receive interrupt. */
\r
205 set_irq_priority( emacRX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
\r
206 enable_irq( emacRX_INTERRUPT_NO );
\r
208 /* Configure the error interrupt. */
\r
209 set_irq_priority( emacERROR_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
\r
210 enable_irq( emacERROR_INTERRUPT_NO );
\r
212 /* Configure the pins to the PHY - RMII mode used. */
\r
213 PORTB_PCR0 = PORT_PCR_MUX( 4 ); /* RMII0_MDIO / MII0_MDIO. */
\r
214 PORTB_PCR1 = PORT_PCR_MUX( 4 ); /* RMII0_MDC / MII0_MDC */
\r
215 PORTA_PCR14 = PORT_PCR_MUX( 4 ); /* RMII0_CRS_DV / MII0_RXDV */
\r
216 PORTA_PCR12 = PORT_PCR_MUX( 4 ); /* RMII0_RXD1 / MII0_RXD1 */
\r
217 PORTA_PCR13 = PORT_PCR_MUX( 4 ); /* RMII0_RXD0/MII0_RXD0 */
\r
218 PORTA_PCR15 = PORT_PCR_MUX( 4 ); /* RMII0_TXEN/MII0_TXEN */
\r
219 PORTA_PCR16 = PORT_PCR_MUX( 4 ); /* RMII0_TXD0/MII0_TXD0 */
\r
220 PORTA_PCR17 = PORT_PCR_MUX( 4 ); /* RMII0_TXD1/MII0_TXD1 */
\r
222 /* Is there communication with the PHY? */
\r
225 vTaskDelay( emacLINK_DELAY );
\r
227 mii_read( 0, configPHY_ADDRESS, PHY_PHYIDR1, &iData );
\r
229 } while( iData == 0xFFFF );
\r
231 /* Start to auto negotiate. */
\r
232 mii_write( 0, configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );
\r
234 /* Wait for auto negotiate to complete. */
\r
237 vTaskDelay( emacLINK_DELAY );
\r
238 mii_read( 0, configPHY_ADDRESS, PHY_BMSR, &iData );
\r
240 } while( !( iData & PHY_BMSR_AN_COMPLETE ) );
\r
242 /* A link has been established. What was negotiated? */
\r
244 mii_read( 0, configPHY_ADDRESS, emacPHY_STATUS, &iData );
\r
246 /* Clear the Individual and Group Address Hash registers */
\r
252 /* Set the Physical Address for the selected ENET */
\r
253 enet_set_address( 0, ucMACAddress );
\r
255 ENET_RCR = ENET_RCR_MAX_FL( UIP_BUFSIZE ) | ENET_RCR_MII_MODE_MASK | ENET_RCR_CRCFWD_MASK | ENET_RCR_RMII_MODE_MASK;
\r
257 /* Clear the control registers. */
\r
260 if( iData & emacPHY_DUPLEX_STATUS )
\r
263 ENET_RCR &= ( unsigned long )~ENET_RCR_DRT_MASK;
\r
264 ENET_TCR |= ENET_TCR_FDEN_MASK;
\r
269 ENET_RCR |= ENET_RCR_DRT_MASK;
\r
270 ENET_TCR &= (unsigned portLONG)~ENET_TCR_FDEN_MASK;
\r
273 if( iData & emacPHY_SPEED_STATUS )
\r
276 ENET_RCR |= ENET_RCR_RMII_10T_MASK;
\r
279 ENET_ECR = ENET_ECR_EN1588_MASK;
\r
281 /* Store and forward checksum. */
\r
282 ENET_TFWR = ENET_TFWR_STRFWD_MASK;
\r
284 /* Set Rx Buffer Size */
\r
285 ENET_MRBR = ( unsigned short ) UIP_BUFSIZE;
\r
287 /* Point to the start of the circular Rx buffer descriptor queue */
\r
288 ENET_RDSR = ( unsigned long ) &( xRxDescriptors[ 0 ] );
\r
290 /* Point to the start of the circular Tx buffer descriptor queue */
\r
291 ENET_TDSR = ( unsigned long ) &( xTxDescriptors[ 0 ] );
\r
293 /* Clear all ENET interrupt events */
\r
294 ENET_EIR = ( unsigned long ) -1;
\r
296 /* Enable interrupts. */
\r
299 | ENET_EIMR_RXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_RXB_MASK*/
\r
301 | ENET_EIMR_TXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_TXB_MASK*/
\r
303 | ENET_EIMR_UN_MASK | ENET_EIMR_RL_MASK | ENET_EIMR_LC_MASK | ENET_EIMR_BABT_MASK | ENET_EIMR_BABR_MASK | ENET_EIMR_EBERR_MASK
\r
306 /* Enable the MAC itself. */
\r
307 ENET_ECR |= ENET_ECR_ETHEREN_MASK;
\r
309 /* Indicate that there have been empty receive buffers produced */
\r
310 ENET_RDAR = ENET_RDAR_RDAR_MASK;
\r
312 /*-----------------------------------------------------------*/
\r
314 static void prvInitialiseDescriptors( void )
\r
316 volatile NBUF *pxDescriptor;
\r
319 for( x = 0; x < emacNUM_BUFFERS; x++ )
\r
321 /* Ensure none of the buffers are shown as in use at the start. */
\r
322 ucBufferInUse[ x ] = pdFALSE;
\r
325 /* Initialise the Rx descriptors. */
\r
326 for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )
\r
328 pxDescriptor = &( xRxDescriptors[ x ] );
\r
329 pxDescriptor->data = ( uint8_t* ) &( xEthernetBuffers[ x ][ 0 ] );
\r
330 pxDescriptor->data = ( uint8_t* ) __REV( ( unsigned long ) pxDescriptor->data );
\r
331 pxDescriptor->length = 0;
\r
332 pxDescriptor->status = RX_BD_E;
\r
333 pxDescriptor->bdu = 0;
\r
334 pxDescriptor->ebd_status = RX_BD_INT;
\r
336 /* Mark this buffer as in use. */
\r
337 ucBufferInUse[ x ] = pdTRUE;
\r
340 /* The last descriptor points back to the start. */
\r
341 pxDescriptor->status |= RX_BD_W;
\r
343 /* Initialise the Tx descriptors. */
\r
344 for( x = 0; x < emacNUM_TX_BUFFERS; x++ )
\r
346 pxDescriptor = &( xTxDescriptors[ x ] );
\r
348 /* A buffer is not allocated to the Tx descriptor until a send is
\r
349 actually required. */
\r
350 pxDescriptor->data = NULL;
\r
351 pxDescriptor->length = 0;
\r
352 pxDescriptor->status = TX_BD_TC;
\r
353 pxDescriptor->ebd_status = TX_BD_INT;
\r
356 /* The last descriptor points back to the start. */
\r
357 pxDescriptor->status |= TX_BD_W;
\r
359 /* Use the first Rx descriptor to start with. */
\r
360 ulRxDescriptorIndex = 0UL;
\r
361 pxCurrentRxDesc = &( xRxDescriptors[ 0 ] );
\r
363 /*-----------------------------------------------------------*/
\r
365 void vEMACWrite( void )
\r
369 /* Wait until the second transmission of the last packet has completed. */
\r
370 for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )
\r
372 if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )
\r
374 /* Descriptor is still active. */
\r
375 vTaskDelay( emacTX_WAIT_DELAY_ms );
\r
383 /* Is the descriptor free after waiting for it? */
\r
384 if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )
\r
386 /* Something has gone wrong. */
\r
387 prvResetEverything();
\r
390 /* Setup both descriptors to transmit the frame. */
\r
391 xTxDescriptors[ 0 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );
\r
392 xTxDescriptors[ 0 ].length = __REVSH( uip_len );
\r
393 xTxDescriptors[ 1 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );
\r
394 xTxDescriptors[ 1 ].length = __REVSH( uip_len );
\r
396 /* uip_buf is being sent by the Tx descriptor. Allocate a new buffer
\r
397 for use by the stack. */
\r
398 uip_buf = prvGetNextBuffer();
\r
400 /* Clear previous settings and go. */
\r
401 xTxDescriptors[ 0 ].status |= ( TX_BD_R | TX_BD_L );
\r
402 xTxDescriptors[ 1 ].status |= ( TX_BD_R | TX_BD_L );
\r
404 /* Start the Tx. */
\r
405 ENET_TDAR = ENET_TDAR_TDAR_MASK;
\r
407 /*-----------------------------------------------------------*/
\r
409 static unsigned char *prvGetNextBuffer( void )
\r
412 unsigned char *pucReturn = NULL;
\r
413 unsigned long ulAttempts = 0;
\r
415 while( pucReturn == NULL )
\r
417 /* Look through the buffers to find one that is not in use by
\r
419 for( x = 0; x < emacNUM_BUFFERS; x++ )
\r
421 if( ucBufferInUse[ x ] == pdFALSE )
\r
423 ucBufferInUse[ x ] = pdTRUE;
\r
424 pucReturn = ( unsigned char * ) &( xEthernetBuffers[ x ][ 0 ] );
\r
429 /* Was a buffer found? */
\r
430 if( pucReturn == NULL )
\r
434 if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )
\r
439 /* Wait then look again. */
\r
440 vTaskDelay( emacBUFFER_WAIT_DELAY_ms );
\r
446 /*-----------------------------------------------------------*/
\r
448 static void prvResetEverything( void )
\r
450 /* Temporary code just to see if this gets called. This function has not
\r
451 been implemented. */
\r
452 portDISABLE_INTERRUPTS();
\r
455 /*-----------------------------------------------------------*/
\r
457 unsigned short usEMACRead( void )
\r
459 unsigned short usBytesReceived;
\r
461 usBytesReceived = prvCheckRxStatus();
\r
462 usBytesReceived = __REVSH( usBytesReceived );
\r
464 if( usBytesReceived > 0 )
\r
466 /* Mark the pxDescriptor buffer as free as uip_buf is going to be set to
\r
467 the buffer that contains the received data. */
\r
468 prvReturnBuffer( uip_buf );
\r
470 /* Point uip_buf to the data about to be processed. */
\r
471 uip_buf = ( void * ) pxCurrentRxDesc->data;
\r
472 uip_buf = ( void * ) __REV( ( unsigned long ) uip_buf );
\r
474 /* Allocate a new buffer to the descriptor, as uip_buf is now using it's
\r
476 pxCurrentRxDesc->data = ( uint8_t * ) prvGetNextBuffer();
\r
477 pxCurrentRxDesc->data = ( uint8_t* ) __REV( ( unsigned long ) pxCurrentRxDesc->data );
\r
479 /* Prepare the descriptor to go again. */
\r
480 pxCurrentRxDesc->status |= RX_BD_E;
\r
482 /* Move onto the next buffer in the ring. */
\r
483 ulRxDescriptorIndex++;
\r
484 if( ulRxDescriptorIndex >= emacNUM_RX_DESCRIPTORS )
\r
486 ulRxDescriptorIndex = 0UL;
\r
488 pxCurrentRxDesc = &( xRxDescriptors[ ulRxDescriptorIndex ] );
\r
490 /* Restart Ethernet if it has stopped */
\r
491 ENET_RDAR = ENET_RDAR_RDAR_MASK;
\r
494 return usBytesReceived;
\r
496 /*-----------------------------------------------------------*/
\r
498 static void prvReturnBuffer( unsigned char *pucBuffer )
\r
502 /* Return a buffer to the pool of free buffers. */
\r
503 for( ul = 0; ul < emacNUM_BUFFERS; ul++ )
\r
505 if( &( xEthernetBuffers[ ul ][ 0 ] ) == ( void * ) pucBuffer )
\r
507 ucBufferInUse[ ul ] = pdFALSE;
\r
512 /*-----------------------------------------------------------*/
\r
514 static unsigned short prvCheckRxStatus( void )
\r
516 unsigned long usReturn = 0;
\r
518 if( ( pxCurrentRxDesc->status & RX_BD_E ) != 0 )
\r
520 /* Current descriptor is still active. */
\r
524 /* The descriptor contains a frame. Because of the size of the buffers
\r
525 the frame should always be complete. */
\r
526 usReturn = pxCurrentRxDesc->length;
\r
531 /*-----------------------------------------------------------*/
\r
533 void vEMAC_TxISRHandler( void )
\r
535 /* Clear the interrupt. */
\r
536 ENET_EIR = ENET_EIR_TXF_MASK;
\r
538 /* Check the buffers have not already been freed in the first of the
\r
539 two Tx interrupts - which could potentially happen if the second Tx completed
\r
540 during the interrupt for the first Tx. */
\r
541 if( xTxDescriptors[ 0 ].data != NULL )
\r
543 if( ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) && ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) )
\r
545 configASSERT( xTxDescriptors[ 0 ].data == xTxDescriptors[ 1 ].data );
\r
547 xTxDescriptors[ 0 ].data = ( uint8_t* ) __REV( ( unsigned long ) xTxDescriptors[ 0 ].data );
\r
548 prvReturnBuffer( xTxDescriptors[ 0 ].data );
\r
550 /* Just to mark the fact that the buffer has already been released. */
\r
551 xTxDescriptors[ 0 ].data = NULL;
\r
555 /*-----------------------------------------------------------*/
\r
557 void vEMAC_RxISRHandler( void )
\r
559 const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;
\r
560 long lHigherPriorityTaskWoken = pdFALSE;
\r
561 extern xQueueHandle xEMACEventQueue;
\r
563 /* Clear the interrupt. */
\r
564 ENET_EIR = ENET_EIR_RXF_MASK;
\r
566 /* An Ethernet Rx event has occurred. */
\r
567 xQueueSendFromISR( xEMACEventQueue, &ulRxEvent, &lHigherPriorityTaskWoken );
\r
568 portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );
\r
570 /*-----------------------------------------------------------*/
\r
572 void vEMAC_ErrorISRHandler( void )
\r
574 /* Clear the interrupt. */
\r
575 ENET_EIR = ENET_EIR & ENET_EIMR;
\r
577 /* Attempt recovery. Not very sophisticated. */
\r
578 prvInitialiseDescriptors();
\r
579 ENET_RDAR = ENET_RDAR_RDAR_MASK;
\r
581 /*-----------------------------------------------------------*/
\r