2 * FreeRTOS+TCP Labs Build 150406 (C) 2015 Real Time Engineers ltd.
\r
3 * Authors include Hein Tibosch and Richard Barry
\r
5 *******************************************************************************
\r
6 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
9 *** FREERTOS+TCP IS STILL IN THE LAB: ***
\r
11 *** This product is functional and is already being used in commercial ***
\r
12 *** products. Be aware however that we are still refining its design, ***
\r
13 *** the source code does not yet fully conform to the strict coding and ***
\r
14 *** style standards mandated by Real Time Engineers ltd., and the ***
\r
15 *** documentation and testing is not necessarily complete. ***
\r
17 *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
\r
18 *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
\r
19 *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
\r
20 *** under a license other than that described below. ***
\r
23 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
24 *******************************************************************************
\r
26 * - Open source licensing -
\r
27 * While FreeRTOS+TCP is in the lab it is provided only under version two of the
\r
28 * GNU General Public License (GPL) (which is different to the standard FreeRTOS
\r
29 * license). FreeRTOS+TCP is free to download, use and distribute under the
\r
30 * terms of that license provided the copyright notice and this text are not
\r
31 * altered or removed from the source files. The GPL V2 text is available on
\r
32 * the gnu.org web site, and on the following
\r
33 * URL: http://www.FreeRTOS.org/gpl-2.0.txt. Active early adopters may, and
\r
34 * solely at the discretion of Real Time Engineers Ltd., be offered versions
\r
35 * under a license other then the GPL.
\r
37 * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
\r
38 * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
\r
39 * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
\r
40 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
41 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
42 * implied, expressed, or statutory.
\r
44 * 1 tab == 4 spaces!
\r
46 * http://www.FreeRTOS.org
\r
47 * http://www.FreeRTOS.org/plus
\r
48 * http://www.FreeRTOS.org/labs
\r
52 /* Standard includes. */
\r
55 /* FreeRTOS includes. */
\r
56 #include "FreeRTOS.h"
\r
61 /* Hardware abstraction. */
\r
62 #include "FreeRTOS_IO.h"
\r
64 /* FreeRTOS+TCP includes. */
\r
65 #include "FreeRTOS_UDP_IP.h"
\r
66 #include "FreeRTOS_Sockets.h"
\r
67 #include "NetworkBufferManagement.h"
\r
69 /* Driver includes. */
\r
70 #include "lpc17xx_emac.h"
\r
71 #include "lpc17xx_pinsel.h"
\r
73 /* Demo includes. */
\r
74 #include "NetworkInterface.h"
\r
76 #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1
\r
77 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
\r
79 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
\r
82 /* When a packet is ready to be sent, if it cannot be sent immediately then the
\r
83 task performing the transmit will block for niTX_BUFFER_FREE_WAIT
\r
84 milliseconds. It will do this a maximum of niMAX_TX_ATTEMPTS before giving
\r
86 #define niTX_BUFFER_FREE_WAIT ( pdMS_TO_TICKS( 2UL ) )
\r
87 #define niMAX_TX_ATTEMPTS ( 5 )
\r
89 /* The length of the queue used to send interrupt status words from the
\r
90 interrupt handler to the deferred handler task. */
\r
91 #define niINTERRUPT_QUEUE_LENGTH ( 10 )
\r
93 /*-----------------------------------------------------------*/
\r
96 * A deferred interrupt handler task that processes
\r
98 static void prvEMACHandlerTask( void *pvParameters );
\r
100 /*-----------------------------------------------------------*/
\r
102 /* The queue used to communicate Ethernet events with the IP task. */
\r
103 extern QueueHandle_t xNetworkEventQueue;
\r
105 /* The semaphore used to wake the deferred interrupt handler task when an Rx
\r
106 interrupt is received. */
\r
107 static SemaphoreHandle_t xEMACRxEventSemaphore = NULL;
\r
108 /*-----------------------------------------------------------*/
\r
110 BaseType_t xNetworkInterfaceInitialise( void )
\r
112 EMAC_CFG_Type Emac_Config;
\r
113 PINSEL_CFG_Type xPinConfig;
\r
114 BaseType_t xStatus, xReturn;
\r
115 extern uint8_t ucMACAddress[ 6 ];
\r
117 /* Enable Ethernet Pins */
\r
118 boardCONFIGURE_ENET_PINS( xPinConfig );
\r
120 Emac_Config.Mode = EMAC_MODE_AUTO;
\r
121 Emac_Config.pbEMAC_Addr = ucMACAddress;
\r
122 xStatus = EMAC_Init( &Emac_Config );
\r
124 LPC_EMAC->IntEnable &= ~( EMAC_INT_TX_DONE );
\r
126 if( xStatus != ERROR )
\r
128 vSemaphoreCreateBinary( xEMACRxEventSemaphore );
\r
129 configASSERT( xEMACRxEventSemaphore );
\r
131 /* The handler task is created at the highest possible priority to
\r
132 ensure the interrupt handler can return directly to it. */
\r
133 xTaskCreate( prvEMACHandlerTask, "EMAC", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );
\r
135 /* Enable the interrupt and set its priority to the minimum
\r
136 interrupt priority. */
\r
137 NVIC_SetPriority( ENET_IRQn, configMAC_INTERRUPT_PRIORITY );
\r
138 NVIC_EnableIRQ( ENET_IRQn );
\r
147 configASSERT( xStatus != ERROR );
\r
151 /*-----------------------------------------------------------*/
\r
153 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
155 BaseType_t xReturn = pdFAIL;
\r
157 extern void EMAC_StartTransmitNextBuffer( uint32_t ulLength );
\r
158 extern void EMAC_SetNextPacketToSend( uint8_t * pucBuffer );
\r
161 /* Attempt to obtain access to a Tx buffer. */
\r
162 for( x = 0; x < niMAX_TX_ATTEMPTS; x++ )
\r
164 if( EMAC_CheckTransmitIndex() == TRUE )
\r
166 /* Will the data fit in the Tx buffer? */
\r
167 if( pxNetworkBuffer->xDataLength < EMAC_ETH_MAX_FLEN ) /*_RB_ The size needs to come from FreeRTOSIPConfig.h. */
\r
169 /* Assign the buffer to the Tx descriptor that is now known to
\r
171 EMAC_SetNextPacketToSend( pxNetworkBuffer->pucBuffer );
\r
173 /* The EMAC now owns the buffer. */
\r
174 pxNetworkBuffer->pucBuffer = NULL;
\r
176 /* Initiate the Tx. */
\r
177 EMAC_StartTransmitNextBuffer( pxNetworkBuffer->xDataLength );
\r
178 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
180 /* The Tx has been initiated. */
\r
187 vTaskDelay( niTX_BUFFER_FREE_WAIT );
\r
191 /* Finished with the network buffer. */
\r
192 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
196 /*-----------------------------------------------------------*/
\r
198 void ENET_IRQHandler( void )
\r
200 uint32_t ulInterruptCause;
\r
202 while( ( ulInterruptCause = LPC_EMAC->IntStatus ) != 0 )
\r
204 /* Clear the interrupt. */
\r
205 LPC_EMAC->IntClear = ulInterruptCause;
\r
207 /* Clear fatal error conditions. NOTE: The driver does not clear all
\r
208 errors, only those actually experienced. For future reference, range
\r
209 errors are not actually errors so can be ignored. */
\r
210 if( ( ulInterruptCause & EMAC_INT_TX_UNDERRUN ) != 0U )
\r
212 LPC_EMAC->Command |= EMAC_CR_TX_RES;
\r
215 /* Unblock the deferred interrupt handler task if the event was an
\r
217 if( ( ulInterruptCause & EMAC_INT_RX_DONE ) != 0UL )
\r
219 xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL );
\r
223 /* ulInterruptCause is used for convenience here. A context switch is
\r
224 wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a
\r
225 compiler warning. */
\r
226 portEND_SWITCHING_ISR( ulInterruptCause );
\r
228 /*-----------------------------------------------------------*/
\r
230 static void prvEMACHandlerTask( void *pvParameters )
\r
232 size_t xDataLength;
\r
233 const uint16_t usCRCLength = 4;
\r
234 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
235 IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
\r
237 /* This is not included in the header file for some reason. */
\r
238 extern uint8_t *EMAC_NextPacketToRead( void );
\r
240 ( void ) pvParameters;
\r
241 configASSERT( xEMACRxEventSemaphore );
\r
245 /* Wait for the EMAC interrupt to indicate that another packet has been
\r
246 received. The while() loop is only needed if INCLUDE_vTaskSuspend is
\r
247 set to 0 in FreeRTOSConfig.h. */
\r
248 while( xSemaphoreTake( xEMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE );
\r
250 /* At least one packet has been received. */
\r
251 while( EMAC_CheckReceiveIndex() != FALSE )
\r
253 /* Obtain the length, minus the CRC. The CRC is four bytes
\r
254 but the length is already minus 1. */
\r
255 xDataLength = ( size_t ) EMAC_GetReceiveDataSize() - ( usCRCLength - 1U );
\r
257 if( xDataLength > 0U )
\r
259 /* Obtain a network buffer to pass this data into the
\r
260 stack. No storage is required as the network buffer
\r
261 will point directly to the buffer that already holds
\r
262 the received data. */
\r
263 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( 0, ( TickType_t ) 0 );
\r
265 if( pxNetworkBuffer != NULL )
\r
267 pxNetworkBuffer->pucBuffer = EMAC_NextPacketToRead();
\r
268 pxNetworkBuffer->xDataLength = xDataLength;
\r
269 xRxEvent.pvData = ( void * ) pxNetworkBuffer;
\r
271 /* Data was received and stored. Send a message to the IP
\r
272 task to let it know. */
\r
273 if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
\r
275 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
276 iptraceETHERNET_RX_EVENT_LOST();
\r
281 iptraceETHERNET_RX_EVENT_LOST();
\r
284 iptraceNETWORK_INTERFACE_RECEIVE();
\r
287 /* Release the frame. */
\r
288 EMAC_UpdateRxConsumeIndex();
\r
292 /*-----------------------------------------------------------*/
\r