2 FreeRTOS V7.4.2 - Copyright (C) 2013 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
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
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 it can 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
49 ***************************************************************************
\r
51 * Having a problem? Start by reading the FAQ "My application does *
\r
52 * not run, what could be wrong?" *
\r
54 * http://www.FreeRTOS.org/FAQHelp.html *
\r
56 ***************************************************************************
\r
59 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
60 license and Real Time Engineers Ltd. contact details.
\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
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
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
75 /* Freescale includes. */
\r
77 #include "eth_phy.h"
\r
81 /* FreeRTOS includes. */
\r
82 #include "FreeRTOS.h"
\r
87 #include "net/uip.h"
\r
89 /* The time to wait between attempts to obtain a free buffer. */
\r
90 #define emacBUFFER_WAIT_DELAY_ms ( 3 / portTICK_RATE_MS )
\r
92 /* The number of times emacBUFFER_WAIT_DELAY_ms should be waited before giving
\r
93 up on attempting to obtain a free buffer all together. */
\r
94 #define emacBUFFER_WAIT_ATTEMPTS ( 30 )
\r
96 /* The number of Rx descriptors. */
\r
97 #define emacNUM_RX_DESCRIPTORS 8
\r
99 /* The number of Tx descriptors. When using uIP there is not point in having
\r
101 #define emacNUM_TX_BUFFERS 2
\r
103 /* The total number of EMAC buffers to allocate. */
\r
104 #define emacNUM_BUFFERS ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )
\r
106 /* The time to wait for the Tx descriptor to become free. */
\r
107 #define emacTX_WAIT_DELAY_ms ( 10 / portTICK_RATE_MS )
\r
109 /* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to
\r
111 #define emacTX_WAIT_ATTEMPTS ( 50 )
\r
113 /* Constants used for set up and initialisation. */
\r
114 #define emacTX_INTERRUPT_NO ( 76 )
\r
115 #define emacRX_INTERRUPT_NO ( 77 )
\r
116 #define emacERROR_INTERRUPT_NO ( 78 )
\r
117 #define emacLINK_DELAY ( 500 / portTICK_RATE_MS )
\r
118 #define emacPHY_STATUS ( 0x1F )
\r
119 #define emacPHY_DUPLEX_STATUS ( 4 << 2 )
\r
120 #define emacPHY_SPEED_STATUS ( 1 << 2 )
\r
122 /*-----------------------------------------------------------*/
\r
125 * Initialise both the Rx and Tx descriptors.
\r
127 static void prvInitialiseDescriptors( void );
\r
130 * Return a pointer to a free buffer within xEthernetBuffers.
\r
132 static unsigned char *prvGetNextBuffer( void );
\r
135 * Return a buffer to the list of free buffers.
\r
137 static void prvReturnBuffer( unsigned char *pucBuffer );
\r
140 * Examine the status of the next Rx descriptor to see if it contains new data.
\r
142 static unsigned short prvCheckRxStatus( void );
\r
145 * Something has gone wrong with the descriptor usage. Reset all the buffers
\r
148 static void prvResetEverything( void );
\r
150 /*-----------------------------------------------------------*/
\r
152 /* The buffers and descriptors themselves. */
\r
153 #pragma data_alignment=16
\r
154 volatile NBUF xRxDescriptors[ emacNUM_RX_DESCRIPTORS ];
\r
156 #pragma data_alignment=16
\r
157 volatile NBUF xTxDescriptors[ emacNUM_TX_BUFFERS ];
\r
159 #pragma data_alignment=16
\r
160 char xEthernetBuffers[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];
\r
162 /* Used to indicate which buffers are free and which are in use. If an index
\r
163 contains 0 then the corresponding buffer in xEthernetBuffers is free, otherwise
\r
164 the buffer is in use or about to be used. */
\r
165 static unsigned char ucBufferInUse[ emacNUM_BUFFERS ];
\r
167 /* Points to the Rx descriptor currently in use. */
\r
168 static volatile NBUF *pxCurrentRxDesc = NULL;
\r
170 /* pxCurrentRxDesc points to descriptor within the xRxDescriptors array that
\r
171 has an index defined by ulRxDescriptorIndex. */
\r
172 static unsigned long ulRxDescriptorIndex = 0UL;
\r
174 /* The buffer used by the uIP stack to both receive and send. This points to
\r
175 one of the Ethernet buffers when its actually in use. */
\r
176 unsigned char *uip_buf = NULL;
\r
178 /*-----------------------------------------------------------*/
\r
180 void vEMACInit( void )
\r
183 extern int periph_clk_khz;
\r
184 const unsigned portCHAR ucMACAddress[] =
\r
186 configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5
\r
189 /* Enable the ENET clock. */
\r
190 SIM_SCGC2 |= SIM_SCGC2_ENET_MASK;
\r
192 /* Allow concurrent access to MPU controller to avoid bus errors. */
\r
195 prvInitialiseDescriptors();
\r
197 /* Reset and enable. */
\r
198 ENET_ECR = ENET_ECR_RESET_MASK;
\r
200 /* Wait at least 8 clock cycles */
\r
203 /* Start the MII interface*/
\r
204 mii_init( 0, periph_clk_khz / 1000L );
\r
206 /* Configure the transmit interrupt. */
\r
207 set_irq_priority( emacTX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
\r
208 enable_irq( emacTX_INTERRUPT_NO );
\r
210 /* Configure the receive interrupt. */
\r
211 set_irq_priority( emacRX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
\r
212 enable_irq( emacRX_INTERRUPT_NO );
\r
214 /* Configure the error interrupt. */
\r
215 set_irq_priority( emacERROR_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
\r
216 enable_irq( emacERROR_INTERRUPT_NO );
\r
218 /* Configure the pins to the PHY - RMII mode used. */
\r
219 PORTB_PCR0 = PORT_PCR_MUX( 4 ); /* RMII0_MDIO / MII0_MDIO. */
\r
220 PORTB_PCR1 = PORT_PCR_MUX( 4 ); /* RMII0_MDC / MII0_MDC */
\r
221 PORTA_PCR14 = PORT_PCR_MUX( 4 ); /* RMII0_CRS_DV / MII0_RXDV */
\r
222 PORTA_PCR12 = PORT_PCR_MUX( 4 ); /* RMII0_RXD1 / MII0_RXD1 */
\r
223 PORTA_PCR13 = PORT_PCR_MUX( 4 ); /* RMII0_RXD0/MII0_RXD0 */
\r
224 PORTA_PCR15 = PORT_PCR_MUX( 4 ); /* RMII0_TXEN/MII0_TXEN */
\r
225 PORTA_PCR16 = PORT_PCR_MUX( 4 ); /* RMII0_TXD0/MII0_TXD0 */
\r
226 PORTA_PCR17 = PORT_PCR_MUX( 4 ); /* RMII0_TXD1/MII0_TXD1 */
\r
228 /* Is there communication with the PHY? */
\r
231 vTaskDelay( emacLINK_DELAY );
\r
233 mii_read( 0, configPHY_ADDRESS, PHY_PHYIDR1, &iData );
\r
235 } while( iData == 0xFFFF );
\r
237 /* Start to auto negotiate. */
\r
238 mii_write( 0, configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );
\r
240 /* Wait for auto negotiate to complete. */
\r
243 vTaskDelay( emacLINK_DELAY );
\r
244 mii_read( 0, configPHY_ADDRESS, PHY_BMSR, &iData );
\r
246 } while( !( iData & PHY_BMSR_AN_COMPLETE ) );
\r
248 /* A link has been established. What was negotiated? */
\r
250 mii_read( 0, configPHY_ADDRESS, emacPHY_STATUS, &iData );
\r
252 /* Clear the Individual and Group Address Hash registers */
\r
258 /* Set the Physical Address for the selected ENET */
\r
259 enet_set_address( 0, ucMACAddress );
\r
261 ENET_RCR = ENET_RCR_MAX_FL( UIP_BUFSIZE ) | ENET_RCR_MII_MODE_MASK | ENET_RCR_CRCFWD_MASK | ENET_RCR_RMII_MODE_MASK;
\r
263 /* Clear the control registers. */
\r
266 if( iData & emacPHY_DUPLEX_STATUS )
\r
269 ENET_RCR &= ( unsigned long )~ENET_RCR_DRT_MASK;
\r
270 ENET_TCR |= ENET_TCR_FDEN_MASK;
\r
275 ENET_RCR |= ENET_RCR_DRT_MASK;
\r
276 ENET_TCR &= (unsigned portLONG)~ENET_TCR_FDEN_MASK;
\r
279 if( iData & emacPHY_SPEED_STATUS )
\r
282 ENET_RCR |= ENET_RCR_RMII_10T_MASK;
\r
285 ENET_ECR = ENET_ECR_EN1588_MASK;
\r
287 /* Store and forward checksum. */
\r
288 ENET_TFWR = ENET_TFWR_STRFWD_MASK;
\r
290 /* Set Rx Buffer Size */
\r
291 ENET_MRBR = ( unsigned short ) UIP_BUFSIZE;
\r
293 /* Point to the start of the circular Rx buffer descriptor queue */
\r
294 ENET_RDSR = ( unsigned long ) &( xRxDescriptors[ 0 ] );
\r
296 /* Point to the start of the circular Tx buffer descriptor queue */
\r
297 ENET_TDSR = ( unsigned long ) &( xTxDescriptors[ 0 ] );
\r
299 /* Clear all ENET interrupt events */
\r
300 ENET_EIR = ( unsigned long ) -1;
\r
302 /* Enable interrupts. */
\r
305 | ENET_EIMR_RXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_RXB_MASK*/
\r
307 | ENET_EIMR_TXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_TXB_MASK*/
\r
309 | 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
312 /* Enable the MAC itself. */
\r
313 ENET_ECR |= ENET_ECR_ETHEREN_MASK;
\r
315 /* Indicate that there have been empty receive buffers produced */
\r
316 ENET_RDAR = ENET_RDAR_RDAR_MASK;
\r
318 /*-----------------------------------------------------------*/
\r
320 static void prvInitialiseDescriptors( void )
\r
322 volatile NBUF *pxDescriptor;
\r
325 for( x = 0; x < emacNUM_BUFFERS; x++ )
\r
327 /* Ensure none of the buffers are shown as in use at the start. */
\r
328 ucBufferInUse[ x ] = pdFALSE;
\r
331 /* Initialise the Rx descriptors. */
\r
332 for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )
\r
334 pxDescriptor = &( xRxDescriptors[ x ] );
\r
335 pxDescriptor->data = ( uint8_t* ) &( xEthernetBuffers[ x ][ 0 ] );
\r
336 pxDescriptor->data = ( uint8_t* ) __REV( ( unsigned long ) pxDescriptor->data );
\r
337 pxDescriptor->length = 0;
\r
338 pxDescriptor->status = RX_BD_E;
\r
339 pxDescriptor->bdu = 0;
\r
340 pxDescriptor->ebd_status = RX_BD_INT;
\r
342 /* Mark this buffer as in use. */
\r
343 ucBufferInUse[ x ] = pdTRUE;
\r
346 /* The last descriptor points back to the start. */
\r
347 pxDescriptor->status |= RX_BD_W;
\r
349 /* Initialise the Tx descriptors. */
\r
350 for( x = 0; x < emacNUM_TX_BUFFERS; x++ )
\r
352 pxDescriptor = &( xTxDescriptors[ x ] );
\r
354 /* A buffer is not allocated to the Tx descriptor until a send is
\r
355 actually required. */
\r
356 pxDescriptor->data = NULL;
\r
357 pxDescriptor->length = 0;
\r
358 pxDescriptor->status = TX_BD_TC;
\r
359 pxDescriptor->ebd_status = TX_BD_INT;
\r
362 /* The last descriptor points back to the start. */
\r
363 pxDescriptor->status |= TX_BD_W;
\r
365 /* Use the first Rx descriptor to start with. */
\r
366 ulRxDescriptorIndex = 0UL;
\r
367 pxCurrentRxDesc = &( xRxDescriptors[ 0 ] );
\r
369 /*-----------------------------------------------------------*/
\r
371 void vEMACWrite( void )
\r
375 /* Wait until the second transmission of the last packet has completed. */
\r
376 for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )
\r
378 if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )
\r
380 /* Descriptor is still active. */
\r
381 vTaskDelay( emacTX_WAIT_DELAY_ms );
\r
389 /* Is the descriptor free after waiting for it? */
\r
390 if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )
\r
392 /* Something has gone wrong. */
\r
393 prvResetEverything();
\r
396 /* Setup both descriptors to transmit the frame. */
\r
397 xTxDescriptors[ 0 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );
\r
398 xTxDescriptors[ 0 ].length = __REVSH( uip_len );
\r
399 xTxDescriptors[ 1 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );
\r
400 xTxDescriptors[ 1 ].length = __REVSH( uip_len );
\r
402 /* uip_buf is being sent by the Tx descriptor. Allocate a new buffer
\r
403 for use by the stack. */
\r
404 uip_buf = prvGetNextBuffer();
\r
406 /* Clear previous settings and go. */
\r
407 xTxDescriptors[ 0 ].status |= ( TX_BD_R | TX_BD_L );
\r
408 xTxDescriptors[ 1 ].status |= ( TX_BD_R | TX_BD_L );
\r
410 /* Start the Tx. */
\r
411 ENET_TDAR = ENET_TDAR_TDAR_MASK;
\r
413 /*-----------------------------------------------------------*/
\r
415 static unsigned char *prvGetNextBuffer( void )
\r
418 unsigned char *pucReturn = NULL;
\r
419 unsigned long ulAttempts = 0;
\r
421 while( pucReturn == NULL )
\r
423 /* Look through the buffers to find one that is not in use by
\r
425 for( x = 0; x < emacNUM_BUFFERS; x++ )
\r
427 if( ucBufferInUse[ x ] == pdFALSE )
\r
429 ucBufferInUse[ x ] = pdTRUE;
\r
430 pucReturn = ( unsigned char * ) &( xEthernetBuffers[ x ][ 0 ] );
\r
435 /* Was a buffer found? */
\r
436 if( pucReturn == NULL )
\r
440 if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )
\r
445 /* Wait then look again. */
\r
446 vTaskDelay( emacBUFFER_WAIT_DELAY_ms );
\r
452 /*-----------------------------------------------------------*/
\r
454 static void prvResetEverything( void )
\r
456 /* Temporary code just to see if this gets called. This function has not
\r
457 been implemented. */
\r
458 portDISABLE_INTERRUPTS();
\r
461 /*-----------------------------------------------------------*/
\r
463 unsigned short usEMACRead( void )
\r
465 unsigned short usBytesReceived;
\r
467 usBytesReceived = prvCheckRxStatus();
\r
468 usBytesReceived = __REVSH( usBytesReceived );
\r
470 if( usBytesReceived > 0 )
\r
472 /* Mark the pxDescriptor buffer as free as uip_buf is going to be set to
\r
473 the buffer that contains the received data. */
\r
474 prvReturnBuffer( uip_buf );
\r
476 /* Point uip_buf to the data about to be processed. */
\r
477 uip_buf = ( void * ) pxCurrentRxDesc->data;
\r
478 uip_buf = ( void * ) __REV( ( unsigned long ) uip_buf );
\r
480 /* Allocate a new buffer to the descriptor, as uip_buf is now using it's
\r
482 pxCurrentRxDesc->data = ( uint8_t * ) prvGetNextBuffer();
\r
483 pxCurrentRxDesc->data = ( uint8_t* ) __REV( ( unsigned long ) pxCurrentRxDesc->data );
\r
485 /* Prepare the descriptor to go again. */
\r
486 pxCurrentRxDesc->status |= RX_BD_E;
\r
488 /* Move onto the next buffer in the ring. */
\r
489 ulRxDescriptorIndex++;
\r
490 if( ulRxDescriptorIndex >= emacNUM_RX_DESCRIPTORS )
\r
492 ulRxDescriptorIndex = 0UL;
\r
494 pxCurrentRxDesc = &( xRxDescriptors[ ulRxDescriptorIndex ] );
\r
496 /* Restart Ethernet if it has stopped */
\r
497 ENET_RDAR = ENET_RDAR_RDAR_MASK;
\r
500 return usBytesReceived;
\r
502 /*-----------------------------------------------------------*/
\r
504 static void prvReturnBuffer( unsigned char *pucBuffer )
\r
508 /* Return a buffer to the pool of free buffers. */
\r
509 for( ul = 0; ul < emacNUM_BUFFERS; ul++ )
\r
511 if( &( xEthernetBuffers[ ul ][ 0 ] ) == ( void * ) pucBuffer )
\r
513 ucBufferInUse[ ul ] = pdFALSE;
\r
518 /*-----------------------------------------------------------*/
\r
520 static unsigned short prvCheckRxStatus( void )
\r
522 unsigned long usReturn = 0;
\r
524 if( ( pxCurrentRxDesc->status & RX_BD_E ) != 0 )
\r
526 /* Current descriptor is still active. */
\r
530 /* The descriptor contains a frame. Because of the size of the buffers
\r
531 the frame should always be complete. */
\r
532 usReturn = pxCurrentRxDesc->length;
\r
537 /*-----------------------------------------------------------*/
\r
539 void vEMAC_TxISRHandler( void )
\r
541 /* Clear the interrupt. */
\r
542 ENET_EIR = ENET_EIR_TXF_MASK;
\r
544 /* Check the buffers have not already been freed in the first of the
\r
545 two Tx interrupts - which could potentially happen if the second Tx completed
\r
546 during the interrupt for the first Tx. */
\r
547 if( xTxDescriptors[ 0 ].data != NULL )
\r
549 if( ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) && ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) )
\r
551 configASSERT( xTxDescriptors[ 0 ].data == xTxDescriptors[ 1 ].data );
\r
553 xTxDescriptors[ 0 ].data = ( uint8_t* ) __REV( ( unsigned long ) xTxDescriptors[ 0 ].data );
\r
554 prvReturnBuffer( xTxDescriptors[ 0 ].data );
\r
556 /* Just to mark the fact that the buffer has already been released. */
\r
557 xTxDescriptors[ 0 ].data = NULL;
\r
561 /*-----------------------------------------------------------*/
\r
563 void vEMAC_RxISRHandler( void )
\r
565 const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;
\r
566 long lHigherPriorityTaskWoken = pdFALSE;
\r
567 extern xQueueHandle xEMACEventQueue;
\r
569 /* Clear the interrupt. */
\r
570 ENET_EIR = ENET_EIR_RXF_MASK;
\r
572 /* An Ethernet Rx event has occurred. */
\r
573 xQueueSendFromISR( xEMACEventQueue, &ulRxEvent, &lHigherPriorityTaskWoken );
\r
574 portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );
\r
576 /*-----------------------------------------------------------*/
\r
578 void vEMAC_ErrorISRHandler( void )
\r
580 /* Clear the interrupt. */
\r
581 ENET_EIR = ENET_EIR & ENET_EIMR;
\r
583 /* Attempt recovery. Not very sophisticated. */
\r
584 prvInitialiseDescriptors();
\r
585 ENET_RDAR = ENET_RDAR_RDAR_MASK;
\r
587 /*-----------------------------------------------------------*/
\r