2 FreeRTOS V7.1.1 - Copyright (C) 2012 Real Time Engineers Ltd.
\r
5 ***************************************************************************
\r
7 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
8 * Complete, revised, and edited pdf reference manuals are also *
\r
11 * Purchasing FreeRTOS documentation will not only help you, by *
\r
12 * ensuring you get running as quickly as possible and with an *
\r
13 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
14 * the FreeRTOS project to continue with its mission of providing *
\r
15 * professional grade, cross platform, de facto standard solutions *
\r
16 * for microcontrollers - completely free of charge! *
\r
18 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
20 * Thank you for using FreeRTOS, and thank you for your support! *
\r
22 ***************************************************************************
\r
25 This file is part of the FreeRTOS distribution.
\r
27 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
28 the terms of the GNU General Public License (version 2) as published by the
\r
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
30 >>>NOTE<<< The modification to the GPL is included to allow you to
\r
31 distribute a combined work that includes FreeRTOS without being obliged to
\r
32 provide the source code for proprietary components outside of the FreeRTOS
\r
33 kernel. FreeRTOS is distributed in the hope that it will be useful, but
\r
34 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
35 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
36 more details. You should have received a copy of the GNU General Public
\r
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
\r
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
\r
39 by writing to Richard Barry, contact details for whom are available on the
\r
44 ***************************************************************************
\r
46 * Having a problem? Start by reading the FAQ "My application does *
\r
47 * not run, what could be wrong? *
\r
49 * http://www.FreeRTOS.org/FAQHelp.html *
\r
51 ***************************************************************************
\r
54 http://www.FreeRTOS.org - Documentation, training, latest information,
\r
55 license and contact details.
\r
57 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
58 including FreeRTOS+Trace - an indispensable productivity tool.
\r
60 Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell
\r
61 the code with commercial support, indemnification, and middleware, under
\r
62 the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also
\r
63 provide a safety engineered and independently SIL3 certified version under
\r
64 the SafeRTOS brand: http://www.SafeRTOS.com.
\r
67 /* Freescale includes. */
\r
69 #include "eth_phy.h"
\r
73 /* FreeRTOS includes. */
\r
74 #include "FreeRTOS.h"
\r
79 #include "net/uip.h"
\r
81 /* The time to wait between attempts to obtain a free buffer. */
\r
82 #define emacBUFFER_WAIT_DELAY_ms ( 3 / portTICK_RATE_MS )
\r
84 /* The number of times emacBUFFER_WAIT_DELAY_ms should be waited before giving
\r
85 up on attempting to obtain a free buffer all together. */
\r
86 #define emacBUFFER_WAIT_ATTEMPTS ( 30 )
\r
88 /* The number of Rx descriptors. */
\r
89 #define emacNUM_RX_DESCRIPTORS 8
\r
91 /* The number of Tx descriptors. When using uIP there is not point in having
\r
93 #define emacNUM_TX_BUFFERS 2
\r
95 /* The total number of EMAC buffers to allocate. */
\r
96 #define emacNUM_BUFFERS ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )
\r
98 /* The time to wait for the Tx descriptor to become free. */
\r
99 #define emacTX_WAIT_DELAY_ms ( 10 / portTICK_RATE_MS )
\r
101 /* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to
\r
103 #define emacTX_WAIT_ATTEMPTS ( 50 )
\r
105 /* Constants used for set up and initialisation. */
\r
106 #define emacTX_INTERRUPT_NO ( 76 )
\r
107 #define emacRX_INTERRUPT_NO ( 77 )
\r
108 #define emacERROR_INTERRUPT_NO ( 78 )
\r
109 #define emacLINK_DELAY ( 500 / portTICK_RATE_MS )
\r
110 #define emacPHY_STATUS ( 0x1F )
\r
111 #define emacPHY_DUPLEX_STATUS ( 4 << 2 )
\r
112 #define emacPHY_SPEED_STATUS ( 1 << 2 )
\r
114 /*-----------------------------------------------------------*/
\r
117 * Initialise both the Rx and Tx descriptors.
\r
119 static void prvInitialiseDescriptors( void );
\r
122 * Return a pointer to a free buffer within xEthernetBuffers.
\r
124 static unsigned char *prvGetNextBuffer( void );
\r
127 * Return a buffer to the list of free buffers.
\r
129 static void prvReturnBuffer( unsigned char *pucBuffer );
\r
132 * Examine the status of the next Rx descriptor to see if it contains new data.
\r
134 static unsigned short prvCheckRxStatus( void );
\r
137 * Something has gone wrong with the descriptor usage. Reset all the buffers
\r
140 static void prvResetEverything( void );
\r
142 /*-----------------------------------------------------------*/
\r
144 /* The buffers and descriptors themselves. */
\r
145 #pragma data_alignment=16
\r
146 volatile NBUF xRxDescriptors[ emacNUM_RX_DESCRIPTORS ];
\r
148 #pragma data_alignment=16
\r
149 volatile NBUF xTxDescriptors[ emacNUM_TX_BUFFERS ];
\r
151 #pragma data_alignment=16
\r
152 char xEthernetBuffers[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];
\r
154 /* Used to indicate which buffers are free and which are in use. If an index
\r
155 contains 0 then the corresponding buffer in xEthernetBuffers is free, otherwise
\r
156 the buffer is in use or about to be used. */
\r
157 static unsigned char ucBufferInUse[ emacNUM_BUFFERS ];
\r
159 /* Points to the Rx descriptor currently in use. */
\r
160 static volatile NBUF *pxCurrentRxDesc = NULL;
\r
162 /* pxCurrentRxDesc points to descriptor within the xRxDescriptors array that
\r
163 has an index defined by ulRxDescriptorIndex. */
\r
164 static unsigned long ulRxDescriptorIndex = 0UL;
\r
166 /* The buffer used by the uIP stack to both receive and send. This points to
\r
167 one of the Ethernet buffers when its actually in use. */
\r
168 unsigned char *uip_buf = NULL;
\r
170 /*-----------------------------------------------------------*/
\r
172 void vEMACInit( void )
\r
175 extern int periph_clk_khz;
\r
176 const unsigned portCHAR ucMACAddress[] =
\r
178 configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5
\r
181 /* Enable the ENET clock. */
\r
182 SIM_SCGC2 |= SIM_SCGC2_ENET_MASK;
\r
184 /* Allow concurrent access to MPU controller to avoid bus errors. */
\r
187 prvInitialiseDescriptors();
\r
189 /* Reset and enable. */
\r
190 ENET_ECR = ENET_ECR_RESET_MASK;
\r
192 /* Wait at least 8 clock cycles */
\r
195 /* Start the MII interface*/
\r
196 mii_init( 0, periph_clk_khz / 1000L );
\r
198 /* Configure the transmit interrupt. */
\r
199 set_irq_priority( emacTX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
\r
200 enable_irq( emacTX_INTERRUPT_NO );
\r
202 /* Configure the receive interrupt. */
\r
203 set_irq_priority( emacRX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
\r
204 enable_irq( emacRX_INTERRUPT_NO );
\r
206 /* Configure the error interrupt. */
\r
207 set_irq_priority( emacERROR_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
\r
208 enable_irq( emacERROR_INTERRUPT_NO );
\r
210 /* Configure the pins to the PHY - RMII mode used. */
\r
211 PORTB_PCR0 = PORT_PCR_MUX( 4 ); /* RMII0_MDIO / MII0_MDIO. */
\r
212 PORTB_PCR1 = PORT_PCR_MUX( 4 ); /* RMII0_MDC / MII0_MDC */
\r
213 PORTA_PCR14 = PORT_PCR_MUX( 4 ); /* RMII0_CRS_DV / MII0_RXDV */
\r
214 PORTA_PCR12 = PORT_PCR_MUX( 4 ); /* RMII0_RXD1 / MII0_RXD1 */
\r
215 PORTA_PCR13 = PORT_PCR_MUX( 4 ); /* RMII0_RXD0/MII0_RXD0 */
\r
216 PORTA_PCR15 = PORT_PCR_MUX( 4 ); /* RMII0_TXEN/MII0_TXEN */
\r
217 PORTA_PCR16 = PORT_PCR_MUX( 4 ); /* RMII0_TXD0/MII0_TXD0 */
\r
218 PORTA_PCR17 = PORT_PCR_MUX( 4 ); /* RMII0_TXD1/MII0_TXD1 */
\r
220 /* Is there communication with the PHY? */
\r
223 vTaskDelay( emacLINK_DELAY );
\r
225 mii_read( 0, configPHY_ADDRESS, PHY_PHYIDR1, &iData );
\r
227 } while( iData == 0xFFFF );
\r
229 /* Start to auto negotiate. */
\r
230 mii_write( 0, configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );
\r
232 /* Wait for auto negotiate to complete. */
\r
235 vTaskDelay( emacLINK_DELAY );
\r
236 mii_read( 0, configPHY_ADDRESS, PHY_BMSR, &iData );
\r
238 } while( !( iData & PHY_BMSR_AN_COMPLETE ) );
\r
240 /* A link has been established. What was negotiated? */
\r
242 mii_read( 0, configPHY_ADDRESS, emacPHY_STATUS, &iData );
\r
244 /* Clear the Individual and Group Address Hash registers */
\r
250 /* Set the Physical Address for the selected ENET */
\r
251 enet_set_address( 0, ucMACAddress );
\r
253 ENET_RCR = ENET_RCR_MAX_FL( UIP_BUFSIZE ) | ENET_RCR_MII_MODE_MASK | ENET_RCR_CRCFWD_MASK | ENET_RCR_RMII_MODE_MASK;
\r
255 /* Clear the control registers. */
\r
258 if( iData & emacPHY_DUPLEX_STATUS )
\r
261 ENET_RCR &= ( unsigned long )~ENET_RCR_DRT_MASK;
\r
262 ENET_TCR |= ENET_TCR_FDEN_MASK;
\r
267 ENET_RCR |= ENET_RCR_DRT_MASK;
\r
268 ENET_TCR &= (unsigned portLONG)~ENET_TCR_FDEN_MASK;
\r
271 if( iData & emacPHY_SPEED_STATUS )
\r
274 ENET_RCR |= ENET_RCR_RMII_10T_MASK;
\r
277 ENET_ECR = ENET_ECR_EN1588_MASK;
\r
279 /* Store and forward checksum. */
\r
280 ENET_TFWR = ENET_TFWR_STRFWD_MASK;
\r
282 /* Set Rx Buffer Size */
\r
283 ENET_MRBR = ( unsigned short ) UIP_BUFSIZE;
\r
285 /* Point to the start of the circular Rx buffer descriptor queue */
\r
286 ENET_RDSR = ( unsigned long ) &( xRxDescriptors[ 0 ] );
\r
288 /* Point to the start of the circular Tx buffer descriptor queue */
\r
289 ENET_TDSR = ( unsigned long ) &( xTxDescriptors[ 0 ] );
\r
291 /* Clear all ENET interrupt events */
\r
292 ENET_EIR = ( unsigned long ) -1;
\r
294 /* Enable interrupts. */
\r
297 | ENET_EIMR_RXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_RXB_MASK*/
\r
299 | ENET_EIMR_TXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_TXB_MASK*/
\r
301 | 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
304 /* Enable the MAC itself. */
\r
305 ENET_ECR |= ENET_ECR_ETHEREN_MASK;
\r
307 /* Indicate that there have been empty receive buffers produced */
\r
308 ENET_RDAR = ENET_RDAR_RDAR_MASK;
\r
310 /*-----------------------------------------------------------*/
\r
312 static void prvInitialiseDescriptors( void )
\r
314 volatile NBUF *pxDescriptor;
\r
317 for( x = 0; x < emacNUM_BUFFERS; x++ )
\r
319 /* Ensure none of the buffers are shown as in use at the start. */
\r
320 ucBufferInUse[ x ] = pdFALSE;
\r
323 /* Initialise the Rx descriptors. */
\r
324 for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )
\r
326 pxDescriptor = &( xRxDescriptors[ x ] );
\r
327 pxDescriptor->data = ( uint8_t* ) &( xEthernetBuffers[ x ][ 0 ] );
\r
328 pxDescriptor->data = ( uint8_t* ) __REV( ( unsigned long ) pxDescriptor->data );
\r
329 pxDescriptor->length = 0;
\r
330 pxDescriptor->status = RX_BD_E;
\r
331 pxDescriptor->bdu = 0;
\r
332 pxDescriptor->ebd_status = RX_BD_INT;
\r
334 /* Mark this buffer as in use. */
\r
335 ucBufferInUse[ x ] = pdTRUE;
\r
338 /* The last descriptor points back to the start. */
\r
339 pxDescriptor->status |= RX_BD_W;
\r
341 /* Initialise the Tx descriptors. */
\r
342 for( x = 0; x < emacNUM_TX_BUFFERS; x++ )
\r
344 pxDescriptor = &( xTxDescriptors[ x ] );
\r
346 /* A buffer is not allocated to the Tx descriptor until a send is
\r
347 actually required. */
\r
348 pxDescriptor->data = NULL;
\r
349 pxDescriptor->length = 0;
\r
350 pxDescriptor->status = TX_BD_TC;
\r
351 pxDescriptor->ebd_status = TX_BD_INT;
\r
354 /* The last descriptor points back to the start. */
\r
355 pxDescriptor->status |= TX_BD_W;
\r
357 /* Use the first Rx descriptor to start with. */
\r
358 ulRxDescriptorIndex = 0UL;
\r
359 pxCurrentRxDesc = &( xRxDescriptors[ 0 ] );
\r
361 /*-----------------------------------------------------------*/
\r
363 void vEMACWrite( void )
\r
367 /* Wait until the second transmission of the last packet has completed. */
\r
368 for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )
\r
370 if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )
\r
372 /* Descriptor is still active. */
\r
373 vTaskDelay( emacTX_WAIT_DELAY_ms );
\r
381 /* Is the descriptor free after waiting for it? */
\r
382 if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )
\r
384 /* Something has gone wrong. */
\r
385 prvResetEverything();
\r
388 /* Setup both descriptors to transmit the frame. */
\r
389 xTxDescriptors[ 0 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );
\r
390 xTxDescriptors[ 0 ].length = __REVSH( uip_len );
\r
391 xTxDescriptors[ 1 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );
\r
392 xTxDescriptors[ 1 ].length = __REVSH( uip_len );
\r
394 /* uip_buf is being sent by the Tx descriptor. Allocate a new buffer
\r
395 for use by the stack. */
\r
396 uip_buf = prvGetNextBuffer();
\r
398 /* Clear previous settings and go. */
\r
399 xTxDescriptors[ 0 ].status |= ( TX_BD_R | TX_BD_L );
\r
400 xTxDescriptors[ 1 ].status |= ( TX_BD_R | TX_BD_L );
\r
402 /* Start the Tx. */
\r
403 ENET_TDAR = ENET_TDAR_TDAR_MASK;
\r
405 /*-----------------------------------------------------------*/
\r
407 static unsigned char *prvGetNextBuffer( void )
\r
410 unsigned char *pucReturn = NULL;
\r
411 unsigned long ulAttempts = 0;
\r
413 while( pucReturn == NULL )
\r
415 /* Look through the buffers to find one that is not in use by
\r
417 for( x = 0; x < emacNUM_BUFFERS; x++ )
\r
419 if( ucBufferInUse[ x ] == pdFALSE )
\r
421 ucBufferInUse[ x ] = pdTRUE;
\r
422 pucReturn = ( unsigned char * ) &( xEthernetBuffers[ x ][ 0 ] );
\r
427 /* Was a buffer found? */
\r
428 if( pucReturn == NULL )
\r
432 if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )
\r
437 /* Wait then look again. */
\r
438 vTaskDelay( emacBUFFER_WAIT_DELAY_ms );
\r
444 /*-----------------------------------------------------------*/
\r
446 static void prvResetEverything( void )
\r
448 /* Temporary code just to see if this gets called. This function has not
\r
449 been implemented. */
\r
450 portDISABLE_INTERRUPTS();
\r
453 /*-----------------------------------------------------------*/
\r
455 unsigned short usEMACRead( void )
\r
457 unsigned short usBytesReceived;
\r
459 usBytesReceived = prvCheckRxStatus();
\r
460 usBytesReceived = __REVSH( usBytesReceived );
\r
462 if( usBytesReceived > 0 )
\r
464 /* Mark the pxDescriptor buffer as free as uip_buf is going to be set to
\r
465 the buffer that contains the received data. */
\r
466 prvReturnBuffer( uip_buf );
\r
468 /* Point uip_buf to the data about to be processed. */
\r
469 uip_buf = ( void * ) pxCurrentRxDesc->data;
\r
470 uip_buf = ( void * ) __REV( ( unsigned long ) uip_buf );
\r
472 /* Allocate a new buffer to the descriptor, as uip_buf is now using it's
\r
474 pxCurrentRxDesc->data = ( uint8_t * ) prvGetNextBuffer();
\r
475 pxCurrentRxDesc->data = ( uint8_t* ) __REV( ( unsigned long ) pxCurrentRxDesc->data );
\r
477 /* Prepare the descriptor to go again. */
\r
478 pxCurrentRxDesc->status |= RX_BD_E;
\r
480 /* Move onto the next buffer in the ring. */
\r
481 ulRxDescriptorIndex++;
\r
482 if( ulRxDescriptorIndex >= emacNUM_RX_DESCRIPTORS )
\r
484 ulRxDescriptorIndex = 0UL;
\r
486 pxCurrentRxDesc = &( xRxDescriptors[ ulRxDescriptorIndex ] );
\r
488 /* Restart Ethernet if it has stopped */
\r
489 ENET_RDAR = ENET_RDAR_RDAR_MASK;
\r
492 return usBytesReceived;
\r
494 /*-----------------------------------------------------------*/
\r
496 static void prvReturnBuffer( unsigned char *pucBuffer )
\r
500 /* Return a buffer to the pool of free buffers. */
\r
501 for( ul = 0; ul < emacNUM_BUFFERS; ul++ )
\r
503 if( &( xEthernetBuffers[ ul ][ 0 ] ) == ( void * ) pucBuffer )
\r
505 ucBufferInUse[ ul ] = pdFALSE;
\r
510 /*-----------------------------------------------------------*/
\r
512 static unsigned short prvCheckRxStatus( void )
\r
514 unsigned long usReturn = 0;
\r
516 if( ( pxCurrentRxDesc->status & RX_BD_E ) != 0 )
\r
518 /* Current descriptor is still active. */
\r
522 /* The descriptor contains a frame. Because of the size of the buffers
\r
523 the frame should always be complete. */
\r
524 usReturn = pxCurrentRxDesc->length;
\r
529 /*-----------------------------------------------------------*/
\r
531 void vEMAC_TxISRHandler( void )
\r
533 /* Clear the interrupt. */
\r
534 ENET_EIR = ENET_EIR_TXF_MASK;
\r
536 /* Check the buffers have not already been freed in the first of the
\r
537 two Tx interrupts - which could potentially happen if the second Tx completed
\r
538 during the interrupt for the first Tx. */
\r
539 if( xTxDescriptors[ 0 ].data != NULL )
\r
541 if( ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) && ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) )
\r
543 configASSERT( xTxDescriptors[ 0 ].data == xTxDescriptors[ 1 ].data );
\r
545 xTxDescriptors[ 0 ].data = ( uint8_t* ) __REV( ( unsigned long ) xTxDescriptors[ 0 ].data );
\r
546 prvReturnBuffer( xTxDescriptors[ 0 ].data );
\r
548 /* Just to mark the fact that the buffer has already been released. */
\r
549 xTxDescriptors[ 0 ].data = NULL;
\r
553 /*-----------------------------------------------------------*/
\r
555 void vEMAC_RxISRHandler( void )
\r
557 const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;
\r
558 long lHigherPriorityTaskWoken = pdFALSE;
\r
559 extern xQueueHandle xEMACEventQueue;
\r
561 /* Clear the interrupt. */
\r
562 ENET_EIR = ENET_EIR_RXF_MASK;
\r
564 /* An Ethernet Rx event has occurred. */
\r
565 xQueueSendFromISR( xEMACEventQueue, &ulRxEvent, &lHigherPriorityTaskWoken );
\r
566 portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );
\r
568 /*-----------------------------------------------------------*/
\r
570 void vEMAC_ErrorISRHandler( void )
\r
572 /* Clear the interrupt. */
\r
573 ENET_EIR = ENET_EIR & ENET_EIMR;
\r
575 /* Attempt recovery. Not very sophisticated. */
\r
576 prvInitialiseDescriptors();
\r
577 ENET_RDAR = ENET_RDAR_RDAR_MASK;
\r
579 /*-----------------------------------------------------------*/
\r