2  * FreeRTOS+UDP V1.0.2 (C) 2013 Real Time Engineers ltd.
\r 
   3  * All rights reserved
\r 
   5  * This file is part of the FreeRTOS+UDP distribution.  The FreeRTOS+UDP license
\r 
   6  * terms are different to the FreeRTOS license terms.
\r 
   8  * FreeRTOS+UDP uses a dual license model that allows the software to be used 
\r 
   9  * under a standard GPL open source license, or a commercial license.  The 
\r 
  10  * standard GPL license (unlike the modified GPL license under which FreeRTOS 
\r 
  11  * itself is distributed) requires that all software statically linked with 
\r 
  12  * FreeRTOS+UDP is also distributed under the same GPL V2 license terms.  
\r 
  13  * Details of both license options follow:
\r 
  15  * - Open source licensing -
\r 
  16  * FreeRTOS+UDP is a free download and may be used, modified, evaluated and
\r 
  17  * distributed without charge provided the user adheres to version two of the
\r 
  18  * GNU General Public License (GPL) and does not remove the copyright notice or
\r 
  19  * this text.  The GPL V2 text is available on the gnu.org web site, and on the
\r 
  20  * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.
\r 
  22  * - Commercial licensing -
\r 
  23  * Businesses and individuals that for commercial or other reasons cannot comply
\r 
  24  * with the terms of the GPL V2 license must obtain a commercial license before 
\r 
  25  * incorporating FreeRTOS+UDP into proprietary software for distribution in any 
\r 
  26  * form.  Commercial licenses can be purchased from http://shop.freertos.org/udp 
\r 
  27  * and do not require any source files to be changed.
\r 
  29  * FreeRTOS+UDP is distributed in the hope that it will be useful.  You cannot
\r 
  30  * use FreeRTOS+UDP unless you agree that you use the software 'as is'.
\r 
  31  * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied
\r 
  32  * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r 
  33  * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r 
  34  * implied, expressed, or statutory.
\r 
  36  * 1 tab == 4 spaces!
\r 
  38  * http://www.FreeRTOS.org
\r 
  39  * http://www.FreeRTOS.org/udp
\r 
  43 /* FreeRTOS includes. */
\r 
  44 #include "FreeRTOS.h"
\r 
  48 /* FreeRTOS+UDP includes. */
\r 
  49 #include "FreeRTOS_UDP_IP.h"
\r 
  50 #include "FreeRTOS_IP_Private.h"
\r 
  51 #include "NetworkBufferManagement.h"
\r 
  53 /* Library includes. */
\r 
  56 /* Descriptors that reference received buffers are expected to have both the
\r 
  57 first and last frame bits set because buffers are dimensioned to hold complete
\r 
  59 #define emacEXPECTED_RX_STATUS_MASK     ( RDES_LS | RDES_FS )
\r 
  61 /*-----------------------------------------------------------*/
\r 
  64  * Set the Rx and Tx descriptors into their expected initial state.
\r 
  66 static void prvResetRxDescriptors( void );
\r 
  67 static void prvResetTxDescriptors( void );
\r 
  70  * Returns the length of the data pointed to by the next Rx descriptor.
\r 
  72 static uint32_t prvReceivedDataLength( void );
\r 
  75 /*-----------------------------------------------------------*/
\r 
  77 /* Rx and Tx descriptors and data array. */
\r 
  78 static volatile IP_ENET_001_ENHRXDESC_T xRXDescriptors[ configNUM_RX_ETHERNET_DMA_DESCRIPTORS ];
\r 
  79 static volatile IP_ENET_001_ENHTXDESC_T xTxDescriptors[ configNUM_TX_ETHERNET_DMA_DESCRIPTORS ];
\r 
  81 /* Indexes into the Rx and Tx descriptor arrays. */
\r 
  82 static unsigned int xRxDescriptorIndex = 0;
\r 
  83 static unsigned int xTxDescriptorIndex = 0;
\r 
  85 /*-----------------------------------------------------------*/
\r 
  87 portBASE_TYPE xEMACInit( uint8_t ucMACAddress[ 6 ] )
\r 
  89 portBASE_TYPE xReturn;
\r 
  90 uint32_t ulPHYStatus;
\r 
  92         /* Configure the hardware. */
\r 
  93         Chip_ENET_Init( LPC_ETHERNET );
\r 
  95         if( lpc_phy_init( pdTRUE, vTaskDelay ) == SUCCESS )
\r 
  97                 /* The MAC address is passed in as the function parameter. */
\r 
  98                 Chip_ENET_SetADDR( LPC_ETHERNET, ucMACAddress );
\r 
 100                 /* Wait for autonegotiation to complete. */
\r 
 104                         ulPHYStatus = lpcPHYStsPoll();
\r 
 105                 } while( ( ulPHYStatus & PHY_LINK_CONNECTED ) == 0x00 );
\r 
 107                 /* Configure the hardware as per the negotiated link. */
\r 
 108                 if( ( ulPHYStatus & PHY_LINK_FULLDUPLX ) == PHY_LINK_FULLDUPLX )
\r 
 110                         IP_ENET_SetDuplex( LPC_ETHERNET, pdTRUE );
\r 
 114                         IP_ENET_SetDuplex( LPC_ETHERNET, pdFALSE );
\r 
 117                 if( ( ulPHYStatus & PHY_LINK_SPEED100 ) == PHY_LINK_SPEED100 )
\r 
 119                         IP_ENET_SetSpeed( LPC_ETHERNET, pdTRUE );
\r 
 123                         IP_ENET_SetSpeed( LPC_ETHERNET, pdFALSE );
\r 
 126                 /* Set descriptors to their initial state. */
\r 
 127                 prvResetRxDescriptors();
\r 
 128                 prvResetTxDescriptors();
\r 
 130                 /* Enable RX and TX. */
\r 
 131                 Chip_ENET_TXEnable( LPC_ETHERNET );
\r 
 132                 Chip_ENET_RXEnable( LPC_ETHERNET );
\r 
 134                 /* Enable the interrupt and set its priority as configured.  THIS
\r 
 135                 DRIVER REQUIRES configMAC_INTERRUPT_PRIORITY TO BE DEFINED, PREFERABLY
\r 
 136                 IN FreeRTOSConfig.h. */
\r 
 137                 NVIC_SetPriority( ETHERNET_IRQn, configMAC_INTERRUPT_PRIORITY );
\r 
 138                 NVIC_EnableIRQ( ETHERNET_IRQn );
\r 
 140                 /* Enable interrupts. */
\r 
 141                 LPC_ETHERNET->DMA_INT_EN =  DMA_IE_NIE | DMA_IE_RIE;
\r 
 152 /*-----------------------------------------------------------*/
\r 
 154 portBASE_TYPE xEMACIsTxDescriptorAvailable( void )
\r 
 156 portBASE_TYPE xReturn;
\r 
 158         if( ( xTxDescriptors[ xTxDescriptorIndex ].CTRLSTAT & RDES_OWN ) == 0 )
\r 
 169 /*-----------------------------------------------------------*/
\r 
 171 void vEMACAssignBufferToDescriptor( uint8_t * pucBuffer )
\r 
 173         /* The old packet is now finished with and can be freed. */
\r 
 174         vEthernetBufferRelease( ( void * ) xTxDescriptors[ xTxDescriptorIndex ].B1ADD );
\r 
 176         /* Assign the new packet to the descriptor. */
\r 
 177         xTxDescriptors[ xTxDescriptorIndex ].B1ADD = ( uint32_t ) pucBuffer;
\r 
 179 /*-----------------------------------------------------------*/
\r 
 181 void vEMACStartNextTransmission( uint32_t ulLength )
\r 
 183         xTxDescriptors[ xTxDescriptorIndex ].BSIZE = ulLength;
\r 
 184         xTxDescriptors[ xTxDescriptorIndex ].CTRLSTAT |= RDES_OWN;
\r 
 186         /* Wake Up the DMA if it's in Suspended Mode. */
\r 
 187         LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1;
\r 
 188         xTxDescriptorIndex++;
\r 
 190         if( xTxDescriptorIndex == configNUM_TX_ETHERNET_DMA_DESCRIPTORS )
\r 
 192                 xTxDescriptorIndex = 0;
\r 
 195 /*-----------------------------------------------------------*/
\r 
 197 static uint32_t prvReceivedDataLength( void )
\r 
 199 unsigned short RxLen = 0;
\r 
 201         RxLen = ( xRXDescriptors[ xRxDescriptorIndex ].STATUS >> 16 ) & 0x03FFF;
\r 
 204 /*-----------------------------------------------------------*/
\r 
 206 void vEMACReturnRxDescriptor( void )
\r 
 208         xRXDescriptors[ xRxDescriptorIndex ].STATUS = RDES_OWN;
\r 
 209         xRxDescriptorIndex++;
\r 
 211         if( xRxDescriptorIndex == configNUM_RX_ETHERNET_DMA_DESCRIPTORS )
\r 
 213                 xRxDescriptorIndex = 0;
\r 
 216 /*-----------------------------------------------------------*/
\r 
 218 portBASE_TYPE xEMACRxDataAvailable( void )
\r 
 220 portBASE_TYPE xReturn;
\r 
 222         if( ( xRXDescriptors[ xRxDescriptorIndex ].STATUS & RDES_OWN ) == 0 )
\r 
 233 /*-----------------------------------------------------------*/
\r 
 235 void vEMACSwapEmptyBufferForRxedData( xNetworkBufferDescriptor_t *pxNetworkBuffer )
\r 
 239         /* Swap the buffer in the network buffer with the buffer used by the DMA.
\r 
 240         This allows the data to be passed out without having to perform any copies. */
\r 
 241         pucTemp = ( uint8_t * ) xRXDescriptors[ xRxDescriptorIndex ].B1ADD;
\r 
 242         xRXDescriptors[ xRxDescriptorIndex ].B1ADD = ( uint32_t ) pxNetworkBuffer->pucEthernetBuffer;
\r 
 243         pxNetworkBuffer->pucEthernetBuffer = pucTemp;
\r 
 245         /* Only supports frames coming in single buffers.  If this frame is split
\r 
 246         across multiple buffers then reject it (and if the frame is needed increase
\r 
 247         the ipconfigNETWORK_MTU setting). */
\r 
 248         if( ( xRXDescriptors[ xRxDescriptorIndex ].STATUS & emacEXPECTED_RX_STATUS_MASK ) != emacEXPECTED_RX_STATUS_MASK )
\r 
 250                 pxNetworkBuffer->xDataLength = 0;
\r 
 254                 pxNetworkBuffer->xDataLength = ( size_t ) prvReceivedDataLength() - ( ipETHERNET_CRC_BYTES - 1U );;
\r 
 257 /*-----------------------------------------------------------*/
\r 
 259 static void prvResetRxDescriptors( void )
\r 
 262 size_t xBufferSize = ipTOTAL_ETHERNET_FRAME_SIZE;
\r 
 264         for( x = 0; x < configNUM_RX_ETHERNET_DMA_DESCRIPTORS; x++ )
\r 
 266                 /* Obtain the buffer first, as the size of the buffer might be changed
\r 
 267                 within the pucEthernetBufferGet() call. */
\r 
 268                 xRXDescriptors[ x ].B1ADD  = ( uint32_t ) pucEthernetBufferGet( &xBufferSize );
\r 
 269                 xRXDescriptors[ x ].STATUS = RDES_OWN;
\r 
 270                 xRXDescriptors[ x ].CTRL  = xBufferSize;
\r 
 271                 xRXDescriptors[ x ].B2ADD = ( uint32_t ) &xRXDescriptors[ x + 1 ];
\r 
 273                 configASSERT( ( ( ( uint32_t ) xRXDescriptors[x].B1ADD ) & 0x07 ) == 0 );
\r 
 276         /* Last Descriptor */
\r 
 277         xRXDescriptors[ configNUM_RX_ETHERNET_DMA_DESCRIPTORS - 1 ].CTRL |= RDES_ENH_RER;
\r 
 279         xRxDescriptorIndex = 0;
\r 
 281         /* Set Starting address of RX Descriptor list */
\r 
 282         LPC_ETHERNET->DMA_REC_DES_ADDR = ( uint32_t ) xRXDescriptors;
\r 
 284 /*-----------------------------------------------------------*/
\r 
 286 static void prvResetTxDescriptors( void )
\r 
 288 /* Initialize Transmit Descriptor and Status array. */
\r 
 291         for( x = 0; x < configNUM_TX_ETHERNET_DMA_DESCRIPTORS; x++ )
\r 
 293                 xTxDescriptors[ x ].CTRLSTAT = TDES_ENH_FS | TDES_ENH_LS;
\r 
 294                 xTxDescriptors[ x ].BSIZE  = 0;
\r 
 295                 xTxDescriptors[ x ].B2ADD = ( uint32_t ) &xTxDescriptors[ x + 1 ];
\r 
 297                 /* Packet is assigned when a Tx is initiated. */
\r 
 298                 xTxDescriptors[ x ].B1ADD   = ( uint32_t )NULL;
\r 
 301         /* Last Descriptor? */
\r 
 302         xTxDescriptors[ configNUM_TX_ETHERNET_DMA_DESCRIPTORS-1 ].CTRLSTAT |= TDES_ENH_TER;
\r 
 304         /* Set Starting address of TX Descriptor list */
\r 
 305         LPC_ETHERNET->DMA_TRANS_DES_ADDR = ( uint32_t ) xTxDescriptors;
\r 
 307 /*-----------------------------------------------------------*/
\r 
 309 void ETH_IRQHandler( void )
\r 
 311 uint32_t ulInterruptCause;
\r 
 312 extern xSemaphoreHandle xEMACRxEventSemaphore;
\r 
 314         configASSERT( xEMACRxEventSemaphore );
\r 
 316         ulInterruptCause = LPC_ETHERNET->DMA_STAT ;
\r 
 318         /* Clear the interrupt. */
\r 
 319         LPC_ETHERNET->DMA_STAT |= ( DMA_ST_NIS | DMA_ST_RI );
\r 
 321         /* Clear fatal error conditions.  NOTE:  The driver does not clear all
\r 
 322         errors, only those actually experienced.  For future reference, range
\r 
 323         errors are not actually errors so can be ignored. */
\r 
 324         if( ( ulInterruptCause & DMA_ST_FBI ) != 0U )
\r 
 326                 LPC_ETHERNET->DMA_STAT |= DMA_ST_FBI;
\r 
 329         /* Unblock the deferred interrupt handler task if the event was an Rx. */
\r 
 330         if( ( ulInterruptCause & DMA_IE_RIE ) != 0UL )
\r 
 332                 xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL );
\r 
 335         /* ulInterruptCause is used for convenience here.  A context switch is
\r 
 336         wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a
\r 
 337         compiler warning. */
\r 
 338         portEND_SWITCHING_ISR( ulInterruptCause );
\r