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