2 * FreeRTOS+UDP V1.0.0 (C) 2013 Real Time Engineers ltd.
\r
4 * This file is part of the FreeRTOS+UDP distribution. The FreeRTOS+UDP license
\r
5 * terms are different to the FreeRTOS license terms.
\r
7 * FreeRTOS+UDP uses a dual license model that allows the software to be used
\r
8 * under a standard GPL open source license, or a commercial license. The
\r
9 * standard GPL license (unlike the modified GPL license under which FreeRTOS
\r
10 * itself is distributed) requires that all software statically linked with
\r
11 * FreeRTOS+UDP is also distributed under the same GPL V2 license terms.
\r
12 * Details of both license options follow:
\r
14 * - Open source licensing -
\r
15 * FreeRTOS+UDP is a free download and may be used, modified, evaluated and
\r
16 * distributed without charge provided the user adheres to version two of the
\r
17 * GNU General Public License (GPL) and does not remove the copyright notice or
\r
18 * this text. The GPL V2 text is available on the gnu.org web site, and on the
\r
19 * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.
\r
21 * - Commercial licensing -
\r
22 * Businesses and individuals that for commercial or other reasons cannot comply
\r
23 * with the terms of the GPL V2 license must obtain a commercial license before
\r
24 * incorporating FreeRTOS+UDP into proprietary software for distribution in any
\r
25 * form. Commercial licenses can be purchased from http://shop.freertos.org/udp
\r
26 * and do not require any source files to be changed.
\r
28 * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot
\r
29 * use FreeRTOS+UDP unless you agree that you use the software 'as is'.
\r
30 * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied
\r
31 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
32 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
33 * implied, expressed, or statutory.
\r
35 * 1 tab == 4 spaces!
\r
37 * http://www.FreeRTOS.org
\r
38 * http://www.FreeRTOS.org/udp
\r
42 /* FreeRTOS includes. */
\r
43 #include "FreeRTOS.h"
\r
47 /* FreeRTOS+UDP includes. */
\r
48 #include "FreeRTOS_UDP_IP.h"
\r
49 #include "FreeRTOS_IP_Private.h"
\r
50 #include "NetworkBufferManagement.h"
\r
52 /* Library includes. */
\r
55 /* Descriptors that reference received buffers are expected to have both the
\r
56 first and last frame bits set because buffers are dimensioned to hold complete
\r
58 #define emacEXPECTED_RX_STATUS_MASK ( RDES_LS | RDES_FS )
\r
60 /*-----------------------------------------------------------*/
\r
63 * Set the Rx and Tx descriptors into their expected initial state.
\r
65 static void prvResetRxDescriptors( void );
\r
66 static void prvResetTxDescriptors( void );
\r
69 * Returns the length of the data pointed to by the next Rx descriptor.
\r
71 static uint32_t prvReceivedDataLength( void );
\r
74 /*-----------------------------------------------------------*/
\r
76 /* Rx and Tx descriptors and data array. */
\r
77 static volatile IP_ENET_001_ENHRXDESC_T xRXDescriptors[ configNUM_RX_ETHERNET_DMA_DESCRIPTORS ];
\r
78 static volatile IP_ENET_001_ENHTXDESC_T xTxDescriptors[ configNUM_TX_ETHERNET_DMA_DESCRIPTORS ];
\r
80 /* Indexes into the Rx and Tx descriptor arrays. */
\r
81 static unsigned int xRxDescriptorIndex = 0;
\r
82 static unsigned int xTxDescriptorIndex = 0;
\r
84 /*-----------------------------------------------------------*/
\r
86 portBASE_TYPE xEMACInit( uint8_t ucMACAddress[ 6 ] )
\r
88 portBASE_TYPE xReturn;
\r
89 uint32_t ulPHYStatus;
\r
91 /* Configure the hardware. */
\r
92 Chip_ENET_Init( LPC_ETHERNET );
\r
94 if( lpc_phy_init( pdTRUE, vTaskDelay ) == SUCCESS )
\r
96 /* The MAC address is passed in as the function parameter. */
\r
97 Chip_ENET_SetADDR( LPC_ETHERNET, ucMACAddress );
\r
99 /* Wait for autonegotiation to complete. */
\r
103 ulPHYStatus = lpcPHYStsPoll();
\r
104 } while( ( ulPHYStatus & PHY_LINK_CONNECTED ) == 0x00 );
\r
106 /* Configure the hardware as per the negotiated link. */
\r
107 if( ( ulPHYStatus & PHY_LINK_FULLDUPLX ) == PHY_LINK_FULLDUPLX )
\r
109 IP_ENET_SetDuplex( LPC_ETHERNET, pdTRUE );
\r
113 IP_ENET_SetDuplex( LPC_ETHERNET, pdFALSE );
\r
116 if( ( ulPHYStatus & PHY_LINK_SPEED100 ) == PHY_LINK_SPEED100 )
\r
118 IP_ENET_SetSpeed( LPC_ETHERNET, pdTRUE );
\r
122 IP_ENET_SetSpeed( LPC_ETHERNET, pdFALSE );
\r
125 /* Set descriptors to their initial state. */
\r
126 prvResetRxDescriptors();
\r
127 prvResetTxDescriptors();
\r
129 /* Enable RX and TX. */
\r
130 Chip_ENET_TXEnable( LPC_ETHERNET );
\r
131 Chip_ENET_RXEnable( LPC_ETHERNET );
\r
133 /* Enable the interrupt and set its priority as configured. THIS
\r
134 DRIVER REQUIRES configMAC_INTERRUPT_PRIORITY TO BE DEFINED, PREFERABLY
\r
135 IN FreeRTOSConfig.h. */
\r
136 NVIC_SetPriority( ETHERNET_IRQn, configMAC_INTERRUPT_PRIORITY );
\r
137 NVIC_EnableIRQ( ETHERNET_IRQn );
\r
139 /* Enable interrupts. */
\r
140 LPC_ETHERNET->DMA_INT_EN = DMA_IE_NIE | DMA_IE_RIE;
\r
151 /*-----------------------------------------------------------*/
\r
153 portBASE_TYPE xEMACIsTxDescriptorAvailable( void )
\r
155 portBASE_TYPE xReturn;
\r
157 if( ( xTxDescriptors[ xTxDescriptorIndex ].CTRLSTAT & RDES_OWN ) == 0 )
\r
168 /*-----------------------------------------------------------*/
\r
170 void vEMACAssignBufferToDescriptor( uint8_t * pucBuffer )
\r
172 /* The old packet is now finished with and can be freed. */
\r
173 vEthernetBufferRelease( ( void * ) xTxDescriptors[ xTxDescriptorIndex ].B1ADD );
\r
175 /* Assign the new packet to the descriptor. */
\r
176 xTxDescriptors[ xTxDescriptorIndex ].B1ADD = ( uint32_t ) pucBuffer;
\r
178 /*-----------------------------------------------------------*/
\r
180 void vEMACStartNextTransmission( uint32_t ulLength )
\r
182 xTxDescriptors[ xTxDescriptorIndex ].BSIZE = ulLength;
\r
183 xTxDescriptors[ xTxDescriptorIndex ].CTRLSTAT |= RDES_OWN;
\r
185 /* Wake Up the DMA if it's in Suspended Mode. */
\r
186 LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1;
\r
187 xTxDescriptorIndex++;
\r
189 if( xTxDescriptorIndex == configNUM_TX_ETHERNET_DMA_DESCRIPTORS )
\r
191 xTxDescriptorIndex = 0;
\r
194 /*-----------------------------------------------------------*/
\r
196 static uint32_t prvReceivedDataLength( void )
\r
198 unsigned short RxLen = 0;
\r
200 RxLen = ( xRXDescriptors[ xRxDescriptorIndex ].STATUS >> 16 ) & 0x03FFF;
\r
203 /*-----------------------------------------------------------*/
\r
205 void vEMACReturnRxDescriptor( void )
\r
207 xRXDescriptors[ xRxDescriptorIndex ].STATUS = RDES_OWN;
\r
208 xRxDescriptorIndex++;
\r
210 if( xRxDescriptorIndex == configNUM_RX_ETHERNET_DMA_DESCRIPTORS )
\r
212 xRxDescriptorIndex = 0;
\r
215 /*-----------------------------------------------------------*/
\r
217 portBASE_TYPE xEMACRxDataAvailable( void )
\r
219 portBASE_TYPE xReturn;
\r
221 if( ( xRXDescriptors[ xRxDescriptorIndex ].STATUS & RDES_OWN ) == 0 )
\r
232 /*-----------------------------------------------------------*/
\r
234 void vEMACSwapEmptyBufferForRxedData( xNetworkBufferDescriptor_t *pxNetworkBuffer )
\r
238 /* Swap the buffer in the network buffer with the buffer used by the DMA.
\r
239 This allows the data to be passed out without having to perform any copies. */
\r
240 pucTemp = ( uint8_t * ) xRXDescriptors[ xRxDescriptorIndex ].B1ADD;
\r
241 xRXDescriptors[ xRxDescriptorIndex ].B1ADD = ( uint32_t ) pxNetworkBuffer->pucEthernetBuffer;
\r
242 pxNetworkBuffer->pucEthernetBuffer = pucTemp;
\r
244 /* Only supports frames coming in single buffers. If this frame is split
\r
245 across multiple buffers then reject it (and if the frame is needed increase
\r
246 the ipconfigNETWORK_MTU setting). */
\r
247 if( ( xRXDescriptors[ xRxDescriptorIndex ].STATUS & emacEXPECTED_RX_STATUS_MASK ) != emacEXPECTED_RX_STATUS_MASK )
\r
249 pxNetworkBuffer->xDataLength = 0;
\r
253 pxNetworkBuffer->xDataLength = ( size_t ) prvReceivedDataLength() - ( ipETHERNET_CRC_BYTES - 1U );;
\r
256 /*-----------------------------------------------------------*/
\r
258 static void prvResetRxDescriptors( void )
\r
261 size_t xBufferSize = ipTOTAL_ETHERNET_FRAME_SIZE;
\r
263 for( x = 0; x < configNUM_RX_ETHERNET_DMA_DESCRIPTORS; x++ )
\r
265 /* Obtain the buffer first, as the size of the buffer might be changed
\r
266 within the pucEthernetBufferGet() call. */
\r
267 xRXDescriptors[ x ].B1ADD = ( uint32_t ) pucEthernetBufferGet( &xBufferSize );
\r
268 xRXDescriptors[ x ].STATUS = RDES_OWN;
\r
269 xRXDescriptors[ x ].CTRL = xBufferSize;
\r
270 xRXDescriptors[ x ].B2ADD = ( uint32_t ) &xRXDescriptors[ x + 1 ];
\r
272 configASSERT( ( ( ( uint32_t ) xRXDescriptors[x].B1ADD ) & 0x07 ) == 0 );
\r
275 /* Last Descriptor */
\r
276 xRXDescriptors[ configNUM_RX_ETHERNET_DMA_DESCRIPTORS - 1 ].CTRL |= RDES_ENH_RER;
\r
278 xRxDescriptorIndex = 0;
\r
280 /* Set Starting address of RX Descriptor list */
\r
281 LPC_ETHERNET->DMA_REC_DES_ADDR = ( uint32_t ) xRXDescriptors;
\r
283 /*-----------------------------------------------------------*/
\r
285 static void prvResetTxDescriptors( void )
\r
287 /* Initialize Transmit Descriptor and Status array. */
\r
290 for( x = 0; x < configNUM_TX_ETHERNET_DMA_DESCRIPTORS; x++ )
\r
292 xTxDescriptors[ x ].CTRLSTAT = TDES_ENH_FS | TDES_ENH_LS;
\r
293 xTxDescriptors[ x ].BSIZE = 0;
\r
294 xTxDescriptors[ x ].B2ADD = ( uint32_t ) &xTxDescriptors[ x + 1 ];
\r
296 /* Packet is assigned when a Tx is initiated. */
\r
297 xTxDescriptors[ x ].B1ADD = ( uint32_t )NULL;
\r
300 /* Last Descriptor? */
\r
301 xTxDescriptors[ configNUM_TX_ETHERNET_DMA_DESCRIPTORS-1 ].CTRLSTAT |= TDES_ENH_TER;
\r
303 /* Set Starting address of TX Descriptor list */
\r
304 LPC_ETHERNET->DMA_TRANS_DES_ADDR = ( uint32_t ) xTxDescriptors;
\r
306 /*-----------------------------------------------------------*/
\r
308 void ETH_IRQHandler( void )
\r
310 uint32_t ulInterruptCause;
\r
311 extern xSemaphoreHandle xEMACRxEventSemaphore;
\r
313 configASSERT( xEMACRxEventSemaphore );
\r
315 ulInterruptCause = LPC_ETHERNET->DMA_STAT ;
\r
317 /* Clear the interrupt. */
\r
318 LPC_ETHERNET->DMA_STAT |= ( DMA_ST_NIS | DMA_ST_RI );
\r
320 /* Clear fatal error conditions. NOTE: The driver does not clear all
\r
321 errors, only those actually experienced. For future reference, range
\r
322 errors are not actually errors so can be ignored. */
\r
323 if( ( ulInterruptCause & DMA_ST_FBI ) != 0U )
\r
325 LPC_ETHERNET->DMA_STAT |= DMA_ST_FBI;
\r
328 /* Unblock the deferred interrupt handler task if the event was an Rx. */
\r
329 if( ( ulInterruptCause & DMA_IE_RIE ) != 0UL )
\r
331 xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL );
\r
334 /* ulInterruptCause is used for convenience here. A context switch is
\r
335 wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a
\r
336 compiler warning. */
\r
337 portEND_SWITCHING_ISR( ulInterruptCause );
\r