2 * FreeRTOS+UDP V1.0.4
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software. If you wish to use our Amazon
\r
14 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
\r
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
29 /* FreeRTOS includes. */
\r
30 #include "FreeRTOS.h"
\r
34 /* FreeRTOS+UDP includes. */
\r
35 #include "FreeRTOS_UDP_IP.h"
\r
36 #include "FreeRTOS_IP_Private.h"
\r
37 #include "NetworkBufferManagement.h"
\r
39 /* Library includes. */
\r
42 /* Descriptors that reference received buffers are expected to have both the
\r
43 first and last frame bits set because buffers are dimensioned to hold complete
\r
45 #define emacEXPECTED_RX_STATUS_MASK ( RDES_LS | RDES_FS )
\r
47 /*-----------------------------------------------------------*/
\r
50 * Set the Rx and Tx descriptors into their expected initial state.
\r
52 static void prvResetRxDescriptors( void );
\r
53 static void prvResetTxDescriptors( void );
\r
56 * Returns the length of the data pointed to by the next Rx descriptor.
\r
58 static uint32_t prvReceivedDataLength( void );
\r
61 /*-----------------------------------------------------------*/
\r
63 /* Rx and Tx descriptors and data array. */
\r
64 static volatile IP_ENET_001_ENHRXDESC_T xRXDescriptors[ configNUM_RX_ETHERNET_DMA_DESCRIPTORS ];
\r
65 static volatile IP_ENET_001_ENHTXDESC_T xTxDescriptors[ configNUM_TX_ETHERNET_DMA_DESCRIPTORS ];
\r
67 /* Indexes into the Rx and Tx descriptor arrays. */
\r
68 static unsigned int xRxDescriptorIndex = 0;
\r
69 static unsigned int xTxDescriptorIndex = 0;
\r
71 /*-----------------------------------------------------------*/
\r
73 BaseType_t xEMACInit( uint8_t ucMACAddress[ 6 ] )
\r
76 uint32_t ulPHYStatus;
\r
78 /* Configure the hardware. */
\r
79 Chip_ENET_Init( LPC_ETHERNET );
\r
81 if( lpc_phy_init( pdTRUE, vTaskDelay ) == SUCCESS )
\r
83 /* The MAC address is passed in as the function parameter. */
\r
84 Chip_ENET_SetADDR( LPC_ETHERNET, ucMACAddress );
\r
86 /* Wait for autonegotiation to complete. */
\r
90 ulPHYStatus = lpcPHYStsPoll();
\r
91 } while( ( ulPHYStatus & PHY_LINK_CONNECTED ) == 0x00 );
\r
93 /* Configure the hardware as per the negotiated link. */
\r
94 if( ( ulPHYStatus & PHY_LINK_FULLDUPLX ) == PHY_LINK_FULLDUPLX )
\r
96 IP_ENET_SetDuplex( LPC_ETHERNET, pdTRUE );
\r
100 IP_ENET_SetDuplex( LPC_ETHERNET, pdFALSE );
\r
103 if( ( ulPHYStatus & PHY_LINK_SPEED100 ) == PHY_LINK_SPEED100 )
\r
105 IP_ENET_SetSpeed( LPC_ETHERNET, pdTRUE );
\r
109 IP_ENET_SetSpeed( LPC_ETHERNET, pdFALSE );
\r
112 /* Set descriptors to their initial state. */
\r
113 prvResetRxDescriptors();
\r
114 prvResetTxDescriptors();
\r
116 /* Enable RX and TX. */
\r
117 Chip_ENET_TXEnable( LPC_ETHERNET );
\r
118 Chip_ENET_RXEnable( LPC_ETHERNET );
\r
120 /* Enable the interrupt and set its priority as configured. THIS
\r
121 DRIVER REQUIRES configMAC_INTERRUPT_PRIORITY TO BE DEFINED, PREFERABLY
\r
122 IN FreeRTOSConfig.h. */
\r
123 NVIC_SetPriority( ETHERNET_IRQn, configMAC_INTERRUPT_PRIORITY );
\r
124 NVIC_EnableIRQ( ETHERNET_IRQn );
\r
126 /* Enable interrupts. */
\r
127 LPC_ETHERNET->DMA_INT_EN = DMA_IE_NIE | DMA_IE_RIE;
\r
138 /*-----------------------------------------------------------*/
\r
140 BaseType_t xEMACIsTxDescriptorAvailable( void )
\r
142 BaseType_t xReturn;
\r
144 if( ( xTxDescriptors[ xTxDescriptorIndex ].CTRLSTAT & RDES_OWN ) == 0 )
\r
155 /*-----------------------------------------------------------*/
\r
157 void vEMACAssignBufferToDescriptor( uint8_t * pucBuffer )
\r
159 /* The old packet is now finished with and can be freed. */
\r
160 vEthernetBufferRelease( ( void * ) xTxDescriptors[ xTxDescriptorIndex ].B1ADD );
\r
162 /* Assign the new packet to the descriptor. */
\r
163 xTxDescriptors[ xTxDescriptorIndex ].B1ADD = ( uint32_t ) pucBuffer;
\r
165 /*-----------------------------------------------------------*/
\r
167 void vEMACStartNextTransmission( uint32_t ulLength )
\r
169 xTxDescriptors[ xTxDescriptorIndex ].BSIZE = ulLength;
\r
170 xTxDescriptors[ xTxDescriptorIndex ].CTRLSTAT |= RDES_OWN;
\r
172 /* Wake Up the DMA if it's in Suspended Mode. */
\r
173 LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1;
\r
174 xTxDescriptorIndex++;
\r
176 if( xTxDescriptorIndex == configNUM_TX_ETHERNET_DMA_DESCRIPTORS )
\r
178 xTxDescriptorIndex = 0;
\r
181 /*-----------------------------------------------------------*/
\r
183 static uint32_t prvReceivedDataLength( void )
\r
185 unsigned short RxLen = 0;
\r
187 RxLen = ( xRXDescriptors[ xRxDescriptorIndex ].STATUS >> 16 ) & 0x03FFF;
\r
190 /*-----------------------------------------------------------*/
\r
192 void vEMACReturnRxDescriptor( void )
\r
194 xRXDescriptors[ xRxDescriptorIndex ].STATUS = RDES_OWN;
\r
195 xRxDescriptorIndex++;
\r
197 if( xRxDescriptorIndex == configNUM_RX_ETHERNET_DMA_DESCRIPTORS )
\r
199 xRxDescriptorIndex = 0;
\r
202 /*-----------------------------------------------------------*/
\r
204 BaseType_t xEMACRxDataAvailable( void )
\r
206 BaseType_t xReturn;
\r
208 if( ( xRXDescriptors[ xRxDescriptorIndex ].STATUS & RDES_OWN ) == 0 )
\r
219 /*-----------------------------------------------------------*/
\r
221 void vEMACSwapEmptyBufferForRxedData( xNetworkBufferDescriptor_t *pxNetworkBuffer )
\r
225 /* Swap the buffer in the network buffer with the buffer used by the DMA.
\r
226 This allows the data to be passed out without having to perform any copies. */
\r
227 pucTemp = ( uint8_t * ) xRXDescriptors[ xRxDescriptorIndex ].B1ADD;
\r
228 xRXDescriptors[ xRxDescriptorIndex ].B1ADD = ( uint32_t ) pxNetworkBuffer->pucEthernetBuffer;
\r
229 pxNetworkBuffer->pucEthernetBuffer = pucTemp;
\r
231 /* Only supports frames coming in single buffers. If this frame is split
\r
232 across multiple buffers then reject it (and if the frame is needed increase
\r
233 the ipconfigNETWORK_MTU setting). */
\r
234 if( ( xRXDescriptors[ xRxDescriptorIndex ].STATUS & emacEXPECTED_RX_STATUS_MASK ) != emacEXPECTED_RX_STATUS_MASK )
\r
236 pxNetworkBuffer->xDataLength = 0;
\r
240 pxNetworkBuffer->xDataLength = ( size_t ) prvReceivedDataLength() - ( ipETHERNET_CRC_BYTES - 1U );;
\r
243 /*-----------------------------------------------------------*/
\r
245 static void prvResetRxDescriptors( void )
\r
248 size_t xBufferSize = ipTOTAL_ETHERNET_FRAME_SIZE;
\r
250 for( x = 0; x < configNUM_RX_ETHERNET_DMA_DESCRIPTORS; x++ )
\r
252 /* Obtain the buffer first, as the size of the buffer might be changed
\r
253 within the pucEthernetBufferGet() call. */
\r
254 xRXDescriptors[ x ].B1ADD = ( uint32_t ) pucEthernetBufferGet( &xBufferSize );
\r
255 xRXDescriptors[ x ].STATUS = RDES_OWN;
\r
256 xRXDescriptors[ x ].CTRL = xBufferSize;
\r
257 xRXDescriptors[ x ].B2ADD = ( uint32_t ) &xRXDescriptors[ x + 1 ];
\r
259 configASSERT( ( ( ( uint32_t ) xRXDescriptors[x].B1ADD ) & 0x07 ) == 0 );
\r
262 /* Last Descriptor */
\r
263 xRXDescriptors[ configNUM_RX_ETHERNET_DMA_DESCRIPTORS - 1 ].CTRL |= RDES_ENH_RER;
\r
265 xRxDescriptorIndex = 0;
\r
267 /* Set Starting address of RX Descriptor list */
\r
268 LPC_ETHERNET->DMA_REC_DES_ADDR = ( uint32_t ) xRXDescriptors;
\r
270 /*-----------------------------------------------------------*/
\r
272 static void prvResetTxDescriptors( void )
\r
274 /* Initialize Transmit Descriptor and Status array. */
\r
277 for( x = 0; x < configNUM_TX_ETHERNET_DMA_DESCRIPTORS; x++ )
\r
279 xTxDescriptors[ x ].CTRLSTAT = TDES_ENH_FS | TDES_ENH_LS;
\r
280 xTxDescriptors[ x ].BSIZE = 0;
\r
281 xTxDescriptors[ x ].B2ADD = ( uint32_t ) &xTxDescriptors[ x + 1 ];
\r
283 /* Packet is assigned when a Tx is initiated. */
\r
284 xTxDescriptors[ x ].B1ADD = ( uint32_t )NULL;
\r
287 /* Last Descriptor? */
\r
288 xTxDescriptors[ configNUM_TX_ETHERNET_DMA_DESCRIPTORS-1 ].CTRLSTAT |= TDES_ENH_TER;
\r
290 /* Set Starting address of TX Descriptor list */
\r
291 LPC_ETHERNET->DMA_TRANS_DES_ADDR = ( uint32_t ) xTxDescriptors;
\r
293 /*-----------------------------------------------------------*/
\r
295 void ETH_IRQHandler( void )
\r
297 uint32_t ulInterruptCause;
\r
298 extern xSemaphoreHandle xEMACRxEventSemaphore;
\r
300 configASSERT( xEMACRxEventSemaphore );
\r
302 ulInterruptCause = LPC_ETHERNET->DMA_STAT ;
\r
304 /* Clear the interrupt. */
\r
305 LPC_ETHERNET->DMA_STAT |= ( DMA_ST_NIS | DMA_ST_RI );
\r
307 /* Clear fatal error conditions. NOTE: The driver does not clear all
\r
308 errors, only those actually experienced. For future reference, range
\r
309 errors are not actually errors so can be ignored. */
\r
310 if( ( ulInterruptCause & DMA_ST_FBI ) != 0U )
\r
312 LPC_ETHERNET->DMA_STAT |= DMA_ST_FBI;
\r
315 /* Unblock the deferred interrupt handler task if the event was an Rx. */
\r
316 if( ( ulInterruptCause & DMA_IE_RIE ) != 0UL )
\r
318 xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL );
\r
321 /* ulInterruptCause is used for convenience here. A context switch is
\r
322 wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a
\r
323 compiler warning. */
\r
324 portEND_SWITCHING_ISR( ulInterruptCause );
\r