2 FreeRTOS V8.2.2 - Copyright (C) 2015 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 This file is part of the FreeRTOS distribution.
\r
9 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
10 the terms of the GNU General Public License (version 2) as published by the
\r
11 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
13 ***************************************************************************
\r
14 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
15 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
16 >>! obliged to provide the source code for proprietary components !<<
\r
17 >>! outside of the FreeRTOS kernel. !<<
\r
18 ***************************************************************************
\r
20 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
22 FOR A PARTICULAR PURPOSE. Full license text is available on the following
\r
23 link: http://www.freertos.org/a00114.html
\r
25 ***************************************************************************
\r
27 * FreeRTOS provides completely free yet professionally developed, *
\r
28 * robust, strictly quality controlled, supported, and cross *
\r
29 * platform software that is more than just the market leader, it *
\r
30 * is the industry's de facto standard. *
\r
32 * Help yourself get started quickly while simultaneously helping *
\r
33 * to support the FreeRTOS project by purchasing a FreeRTOS *
\r
34 * tutorial book, reference manual, or both: *
\r
35 * http://www.FreeRTOS.org/Documentation *
\r
37 ***************************************************************************
\r
39 http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
\r
40 the FAQ page "My application does not run, what could be wrong?". Have you
\r
41 defined configASSERT()?
\r
43 http://www.FreeRTOS.org/support - In return for receiving this top quality
\r
44 embedded software for free we request you assist our global community by
\r
45 participating in the support forum.
\r
47 http://www.FreeRTOS.org/training - Investing in training allows your team to
\r
48 be as productive as possible as early as possible. Now you can receive
\r
49 FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
\r
50 Ltd, and the world's leading authority on the world's leading RTOS.
\r
52 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
53 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
54 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
56 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
\r
57 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
\r
59 http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
\r
60 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
61 licenses offer ticketed support, indemnification and commercial middleware.
\r
63 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
64 engineered and independently SIL3 certified version for use in safety and
\r
65 mission critical applications that require provable dependability.
\r
70 /* Freescale includes. */
\r
72 #include "eth_phy.h"
\r
76 /* FreeRTOS includes. */
\r
77 #include "FreeRTOS.h"
\r
82 #include "net/uip.h"
\r
84 /* The time to wait between attempts to obtain a free buffer. */
\r
85 #define emacBUFFER_WAIT_DELAY_ms ( 3 / portTICK_PERIOD_MS )
\r
87 /* The number of times emacBUFFER_WAIT_DELAY_ms should be waited before giving
\r
88 up on attempting to obtain a free buffer all together. */
\r
89 #define emacBUFFER_WAIT_ATTEMPTS ( 30 )
\r
91 /* The number of Rx descriptors. */
\r
92 #define emacNUM_RX_DESCRIPTORS 8
\r
94 /* The number of Tx descriptors. When using uIP there is not point in having
\r
96 #define emacNUM_TX_BUFFERS 2
\r
98 /* The total number of EMAC buffers to allocate. */
\r
99 #define emacNUM_BUFFERS ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )
\r
101 /* The time to wait for the Tx descriptor to become free. */
\r
102 #define emacTX_WAIT_DELAY_ms ( 10 / portTICK_PERIOD_MS )
\r
104 /* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to
\r
106 #define emacTX_WAIT_ATTEMPTS ( 50 )
\r
108 /* Constants used for set up and initialisation. */
\r
109 #define emacTX_INTERRUPT_NO ( 76 )
\r
110 #define emacRX_INTERRUPT_NO ( 77 )
\r
111 #define emacERROR_INTERRUPT_NO ( 78 )
\r
112 #define emacLINK_DELAY ( 500 / portTICK_PERIOD_MS )
\r
113 #define emacPHY_STATUS ( 0x1F )
\r
114 #define emacPHY_DUPLEX_STATUS ( 4 << 2 )
\r
115 #define emacPHY_SPEED_STATUS ( 1 << 2 )
\r
117 /*-----------------------------------------------------------*/
\r
120 * Initialise both the Rx and Tx descriptors.
\r
122 static void prvInitialiseDescriptors( void );
\r
125 * Return a pointer to a free buffer within xEthernetBuffers.
\r
127 static unsigned char *prvGetNextBuffer( void );
\r
130 * Return a buffer to the list of free buffers.
\r
132 static void prvReturnBuffer( unsigned char *pucBuffer );
\r
135 * Examine the status of the next Rx descriptor to see if it contains new data.
\r
137 static unsigned short prvCheckRxStatus( void );
\r
140 * Something has gone wrong with the descriptor usage. Reset all the buffers
\r
143 static void prvResetEverything( void );
\r
145 /*-----------------------------------------------------------*/
\r
147 /* The buffers and descriptors themselves. */
\r
148 #pragma data_alignment=16
\r
149 volatile NBUF xRxDescriptors[ emacNUM_RX_DESCRIPTORS ];
\r
151 #pragma data_alignment=16
\r
152 volatile NBUF xTxDescriptors[ emacNUM_TX_BUFFERS ];
\r
154 #pragma data_alignment=16
\r
155 char xEthernetBuffers[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];
\r
157 /* Used to indicate which buffers are free and which are in use. If an index
\r
158 contains 0 then the corresponding buffer in xEthernetBuffers is free, otherwise
\r
159 the buffer is in use or about to be used. */
\r
160 static unsigned char ucBufferInUse[ emacNUM_BUFFERS ];
\r
162 /* Points to the Rx descriptor currently in use. */
\r
163 static volatile NBUF *pxCurrentRxDesc = NULL;
\r
165 /* pxCurrentRxDesc points to descriptor within the xRxDescriptors array that
\r
166 has an index defined by ulRxDescriptorIndex. */
\r
167 static unsigned long ulRxDescriptorIndex = 0UL;
\r
169 /* The buffer used by the uIP stack to both receive and send. This points to
\r
170 one of the Ethernet buffers when its actually in use. */
\r
171 unsigned char *uip_buf = NULL;
\r
173 /*-----------------------------------------------------------*/
\r
175 void vEMACInit( void )
\r
178 extern int periph_clk_khz;
\r
179 const unsigned char ucMACAddress[] =
\r
181 configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5
\r
184 /* Enable the ENET clock. */
\r
185 SIM_SCGC2 |= SIM_SCGC2_ENET_MASK;
\r
187 /* Allow concurrent access to MPU controller to avoid bus errors. */
\r
190 prvInitialiseDescriptors();
\r
192 /* Reset and enable. */
\r
193 ENET_ECR = ENET_ECR_RESET_MASK;
\r
195 /* Wait at least 8 clock cycles */
\r
198 /* Start the MII interface*/
\r
199 mii_init( 0, periph_clk_khz / 1000L );
\r
201 /* Configure the transmit interrupt. */
\r
202 set_irq_priority( emacTX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
\r
203 enable_irq( emacTX_INTERRUPT_NO );
\r
205 /* Configure the receive interrupt. */
\r
206 set_irq_priority( emacRX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
\r
207 enable_irq( emacRX_INTERRUPT_NO );
\r
209 /* Configure the error interrupt. */
\r
210 set_irq_priority( emacERROR_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
\r
211 enable_irq( emacERROR_INTERRUPT_NO );
\r
213 /* Configure the pins to the PHY - RMII mode used. */
\r
214 PORTB_PCR0 = PORT_PCR_MUX( 4 ); /* RMII0_MDIO / MII0_MDIO. */
\r
215 PORTB_PCR1 = PORT_PCR_MUX( 4 ); /* RMII0_MDC / MII0_MDC */
\r
216 PORTA_PCR14 = PORT_PCR_MUX( 4 ); /* RMII0_CRS_DV / MII0_RXDV */
\r
217 PORTA_PCR12 = PORT_PCR_MUX( 4 ); /* RMII0_RXD1 / MII0_RXD1 */
\r
218 PORTA_PCR13 = PORT_PCR_MUX( 4 ); /* RMII0_RXD0/MII0_RXD0 */
\r
219 PORTA_PCR15 = PORT_PCR_MUX( 4 ); /* RMII0_TXEN/MII0_TXEN */
\r
220 PORTA_PCR16 = PORT_PCR_MUX( 4 ); /* RMII0_TXD0/MII0_TXD0 */
\r
221 PORTA_PCR17 = PORT_PCR_MUX( 4 ); /* RMII0_TXD1/MII0_TXD1 */
\r
223 /* Is there communication with the PHY? */
\r
226 vTaskDelay( emacLINK_DELAY );
\r
228 mii_read( 0, configPHY_ADDRESS, PHY_PHYIDR1, &iData );
\r
230 } while( iData == 0xFFFF );
\r
232 /* Start to auto negotiate. */
\r
233 mii_write( 0, configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );
\r
235 /* Wait for auto negotiate to complete. */
\r
238 vTaskDelay( emacLINK_DELAY );
\r
239 mii_read( 0, configPHY_ADDRESS, PHY_BMSR, &iData );
\r
241 } while( !( iData & PHY_BMSR_AN_COMPLETE ) );
\r
243 /* A link has been established. What was negotiated? */
\r
245 mii_read( 0, configPHY_ADDRESS, emacPHY_STATUS, &iData );
\r
247 /* Clear the Individual and Group Address Hash registers */
\r
253 /* Set the Physical Address for the selected ENET */
\r
254 enet_set_address( 0, ucMACAddress );
\r
256 ENET_RCR = ENET_RCR_MAX_FL( UIP_BUFSIZE ) | ENET_RCR_MII_MODE_MASK | ENET_RCR_CRCFWD_MASK | ENET_RCR_RMII_MODE_MASK;
\r
258 /* Clear the control registers. */
\r
261 if( iData & emacPHY_DUPLEX_STATUS )
\r
264 ENET_RCR &= ( unsigned long )~ENET_RCR_DRT_MASK;
\r
265 ENET_TCR |= ENET_TCR_FDEN_MASK;
\r
270 ENET_RCR |= ENET_RCR_DRT_MASK;
\r
271 ENET_TCR &= (unsigned long)~ENET_TCR_FDEN_MASK;
\r
274 if( iData & emacPHY_SPEED_STATUS )
\r
277 ENET_RCR |= ENET_RCR_RMII_10T_MASK;
\r
280 ENET_ECR = ENET_ECR_EN1588_MASK;
\r
282 /* Store and forward checksum. */
\r
283 ENET_TFWR = ENET_TFWR_STRFWD_MASK;
\r
285 /* Set Rx Buffer Size */
\r
286 ENET_MRBR = ( unsigned short ) UIP_BUFSIZE;
\r
288 /* Point to the start of the circular Rx buffer descriptor queue */
\r
289 ENET_RDSR = ( unsigned long ) &( xRxDescriptors[ 0 ] );
\r
291 /* Point to the start of the circular Tx buffer descriptor queue */
\r
292 ENET_TDSR = ( unsigned long ) &( xTxDescriptors[ 0 ] );
\r
294 /* Clear all ENET interrupt events */
\r
295 ENET_EIR = ( unsigned long ) -1;
\r
297 /* Enable interrupts. */
\r
300 | ENET_EIMR_RXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_RXB_MASK*/
\r
302 | ENET_EIMR_TXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_TXB_MASK*/
\r
304 | 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
307 /* Enable the MAC itself. */
\r
308 ENET_ECR |= ENET_ECR_ETHEREN_MASK;
\r
310 /* Indicate that there have been empty receive buffers produced */
\r
311 ENET_RDAR = ENET_RDAR_RDAR_MASK;
\r
313 /*-----------------------------------------------------------*/
\r
315 static void prvInitialiseDescriptors( void )
\r
317 volatile NBUF *pxDescriptor;
\r
320 for( x = 0; x < emacNUM_BUFFERS; x++ )
\r
322 /* Ensure none of the buffers are shown as in use at the start. */
\r
323 ucBufferInUse[ x ] = pdFALSE;
\r
326 /* Initialise the Rx descriptors. */
\r
327 for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )
\r
329 pxDescriptor = &( xRxDescriptors[ x ] );
\r
330 pxDescriptor->data = ( uint8_t* ) &( xEthernetBuffers[ x ][ 0 ] );
\r
331 pxDescriptor->data = ( uint8_t* ) __REV( ( unsigned long ) pxDescriptor->data );
\r
332 pxDescriptor->length = 0;
\r
333 pxDescriptor->status = RX_BD_E;
\r
334 pxDescriptor->bdu = 0;
\r
335 pxDescriptor->ebd_status = RX_BD_INT;
\r
337 /* Mark this buffer as in use. */
\r
338 ucBufferInUse[ x ] = pdTRUE;
\r
341 /* The last descriptor points back to the start. */
\r
342 pxDescriptor->status |= RX_BD_W;
\r
344 /* Initialise the Tx descriptors. */
\r
345 for( x = 0; x < emacNUM_TX_BUFFERS; x++ )
\r
347 pxDescriptor = &( xTxDescriptors[ x ] );
\r
349 /* A buffer is not allocated to the Tx descriptor until a send is
\r
350 actually required. */
\r
351 pxDescriptor->data = NULL;
\r
352 pxDescriptor->length = 0;
\r
353 pxDescriptor->status = TX_BD_TC;
\r
354 pxDescriptor->ebd_status = TX_BD_INT;
\r
357 /* The last descriptor points back to the start. */
\r
358 pxDescriptor->status |= TX_BD_W;
\r
360 /* Use the first Rx descriptor to start with. */
\r
361 ulRxDescriptorIndex = 0UL;
\r
362 pxCurrentRxDesc = &( xRxDescriptors[ 0 ] );
\r
364 /*-----------------------------------------------------------*/
\r
366 void vEMACWrite( void )
\r
370 /* Wait until the second transmission of the last packet has completed. */
\r
371 for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )
\r
373 if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )
\r
375 /* Descriptor is still active. */
\r
376 vTaskDelay( emacTX_WAIT_DELAY_ms );
\r
384 /* Is the descriptor free after waiting for it? */
\r
385 if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )
\r
387 /* Something has gone wrong. */
\r
388 prvResetEverything();
\r
391 /* Setup both descriptors to transmit the frame. */
\r
392 xTxDescriptors[ 0 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );
\r
393 xTxDescriptors[ 0 ].length = __REVSH( uip_len );
\r
394 xTxDescriptors[ 1 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );
\r
395 xTxDescriptors[ 1 ].length = __REVSH( uip_len );
\r
397 /* uip_buf is being sent by the Tx descriptor. Allocate a new buffer
\r
398 for use by the stack. */
\r
399 uip_buf = prvGetNextBuffer();
\r
401 /* Clear previous settings and go. */
\r
402 xTxDescriptors[ 0 ].status |= ( TX_BD_R | TX_BD_L );
\r
403 xTxDescriptors[ 1 ].status |= ( TX_BD_R | TX_BD_L );
\r
405 /* Start the Tx. */
\r
406 ENET_TDAR = ENET_TDAR_TDAR_MASK;
\r
408 /*-----------------------------------------------------------*/
\r
410 static unsigned char *prvGetNextBuffer( void )
\r
413 unsigned char *pucReturn = NULL;
\r
414 unsigned long ulAttempts = 0;
\r
416 while( pucReturn == NULL )
\r
418 /* Look through the buffers to find one that is not in use by
\r
420 for( x = 0; x < emacNUM_BUFFERS; x++ )
\r
422 if( ucBufferInUse[ x ] == pdFALSE )
\r
424 ucBufferInUse[ x ] = pdTRUE;
\r
425 pucReturn = ( unsigned char * ) &( xEthernetBuffers[ x ][ 0 ] );
\r
430 /* Was a buffer found? */
\r
431 if( pucReturn == NULL )
\r
435 if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )
\r
440 /* Wait then look again. */
\r
441 vTaskDelay( emacBUFFER_WAIT_DELAY_ms );
\r
447 /*-----------------------------------------------------------*/
\r
449 static void prvResetEverything( void )
\r
451 /* Temporary code just to see if this gets called. This function has not
\r
452 been implemented. */
\r
453 portDISABLE_INTERRUPTS();
\r
456 /*-----------------------------------------------------------*/
\r
458 unsigned short usEMACRead( void )
\r
460 unsigned short usBytesReceived;
\r
462 usBytesReceived = prvCheckRxStatus();
\r
463 usBytesReceived = __REVSH( usBytesReceived );
\r
465 if( usBytesReceived > 0 )
\r
467 /* Mark the pxDescriptor buffer as free as uip_buf is going to be set to
\r
468 the buffer that contains the received data. */
\r
469 prvReturnBuffer( uip_buf );
\r
471 /* Point uip_buf to the data about to be processed. */
\r
472 uip_buf = ( void * ) pxCurrentRxDesc->data;
\r
473 uip_buf = ( void * ) __REV( ( unsigned long ) uip_buf );
\r
475 /* Allocate a new buffer to the descriptor, as uip_buf is now using it's
\r
477 pxCurrentRxDesc->data = ( uint8_t * ) prvGetNextBuffer();
\r
478 pxCurrentRxDesc->data = ( uint8_t* ) __REV( ( unsigned long ) pxCurrentRxDesc->data );
\r
480 /* Prepare the descriptor to go again. */
\r
481 pxCurrentRxDesc->status |= RX_BD_E;
\r
483 /* Move onto the next buffer in the ring. */
\r
484 ulRxDescriptorIndex++;
\r
485 if( ulRxDescriptorIndex >= emacNUM_RX_DESCRIPTORS )
\r
487 ulRxDescriptorIndex = 0UL;
\r
489 pxCurrentRxDesc = &( xRxDescriptors[ ulRxDescriptorIndex ] );
\r
491 /* Restart Ethernet if it has stopped */
\r
492 ENET_RDAR = ENET_RDAR_RDAR_MASK;
\r
495 return usBytesReceived;
\r
497 /*-----------------------------------------------------------*/
\r
499 static void prvReturnBuffer( unsigned char *pucBuffer )
\r
503 /* Return a buffer to the pool of free buffers. */
\r
504 for( ul = 0; ul < emacNUM_BUFFERS; ul++ )
\r
506 if( &( xEthernetBuffers[ ul ][ 0 ] ) == ( void * ) pucBuffer )
\r
508 ucBufferInUse[ ul ] = pdFALSE;
\r
513 /*-----------------------------------------------------------*/
\r
515 static unsigned short prvCheckRxStatus( void )
\r
517 unsigned long usReturn = 0;
\r
519 if( ( pxCurrentRxDesc->status & RX_BD_E ) != 0 )
\r
521 /* Current descriptor is still active. */
\r
525 /* The descriptor contains a frame. Because of the size of the buffers
\r
526 the frame should always be complete. */
\r
527 usReturn = pxCurrentRxDesc->length;
\r
532 /*-----------------------------------------------------------*/
\r
534 void vEMAC_TxISRHandler( void )
\r
536 /* Clear the interrupt. */
\r
537 ENET_EIR = ENET_EIR_TXF_MASK;
\r
539 /* Check the buffers have not already been freed in the first of the
\r
540 two Tx interrupts - which could potentially happen if the second Tx completed
\r
541 during the interrupt for the first Tx. */
\r
542 if( xTxDescriptors[ 0 ].data != NULL )
\r
544 if( ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) && ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) )
\r
546 configASSERT( xTxDescriptors[ 0 ].data == xTxDescriptors[ 1 ].data );
\r
548 xTxDescriptors[ 0 ].data = ( uint8_t* ) __REV( ( unsigned long ) xTxDescriptors[ 0 ].data );
\r
549 prvReturnBuffer( xTxDescriptors[ 0 ].data );
\r
551 /* Just to mark the fact that the buffer has already been released. */
\r
552 xTxDescriptors[ 0 ].data = NULL;
\r
556 /*-----------------------------------------------------------*/
\r
558 void vEMAC_RxISRHandler( void )
\r
560 const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;
\r
561 long lHigherPriorityTaskWoken = pdFALSE;
\r
562 extern QueueHandle_t xEMACEventQueue;
\r
564 /* Clear the interrupt. */
\r
565 ENET_EIR = ENET_EIR_RXF_MASK;
\r
567 /* An Ethernet Rx event has occurred. */
\r
568 xQueueSendFromISR( xEMACEventQueue, &ulRxEvent, &lHigherPriorityTaskWoken );
\r
569 portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );
\r
571 /*-----------------------------------------------------------*/
\r
573 void vEMAC_ErrorISRHandler( void )
\r
575 /* Clear the interrupt. */
\r
576 ENET_EIR = ENET_EIR & ENET_EIMR;
\r
578 /* Attempt recovery. Not very sophisticated. */
\r
579 prvInitialiseDescriptors();
\r
580 ENET_RDAR = ENET_RDAR_RDAR_MASK;
\r
582 /*-----------------------------------------------------------*/
\r