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.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
28 /* FreeRTOS includes. */
\r
29 #include "FreeRTOS.h"
\r
33 /* FreeRTOS+UDP includes. */
\r
34 #include "FreeRTOS_UDP_IP.h"
\r
35 #include "FreeRTOS_IP_Private.h"
\r
36 #include "NetworkBufferManagement.h"
\r
38 /* Library includes. */
\r
41 /* Descriptors that reference received buffers are expected to have both the
\r
42 first and last frame bits set because buffers are dimensioned to hold complete
\r
44 #define emacEXPECTED_RX_STATUS_MASK ( RDES_LS | RDES_FS )
\r
46 /*-----------------------------------------------------------*/
\r
49 * Set the Rx and Tx descriptors into their expected initial state.
\r
51 static void prvResetRxDescriptors( void );
\r
52 static void prvResetTxDescriptors( void );
\r
55 * Returns the length of the data pointed to by the next Rx descriptor.
\r
57 static uint32_t prvReceivedDataLength( void );
\r
60 /*-----------------------------------------------------------*/
\r
62 /* Rx and Tx descriptors and data array. */
\r
63 static volatile IP_ENET_001_ENHRXDESC_T xRXDescriptors[ configNUM_RX_ETHERNET_DMA_DESCRIPTORS ];
\r
64 static volatile IP_ENET_001_ENHTXDESC_T xTxDescriptors[ configNUM_TX_ETHERNET_DMA_DESCRIPTORS ];
\r
66 /* Indexes into the Rx and Tx descriptor arrays. */
\r
67 static unsigned int xRxDescriptorIndex = 0;
\r
68 static unsigned int xTxDescriptorIndex = 0;
\r
70 /*-----------------------------------------------------------*/
\r
72 BaseType_t xEMACInit( uint8_t ucMACAddress[ 6 ] )
\r
75 uint32_t ulPHYStatus;
\r
77 /* Configure the hardware. */
\r
78 Chip_ENET_Init( LPC_ETHERNET );
\r
80 if( lpc_phy_init( pdTRUE, vTaskDelay ) == SUCCESS )
\r
82 /* The MAC address is passed in as the function parameter. */
\r
83 Chip_ENET_SetADDR( LPC_ETHERNET, ucMACAddress );
\r
85 /* Wait for autonegotiation to complete. */
\r
89 ulPHYStatus = lpcPHYStsPoll();
\r
90 } while( ( ulPHYStatus & PHY_LINK_CONNECTED ) == 0x00 );
\r
92 /* Configure the hardware as per the negotiated link. */
\r
93 if( ( ulPHYStatus & PHY_LINK_FULLDUPLX ) == PHY_LINK_FULLDUPLX )
\r
95 IP_ENET_SetDuplex( LPC_ETHERNET, pdTRUE );
\r
99 IP_ENET_SetDuplex( LPC_ETHERNET, pdFALSE );
\r
102 if( ( ulPHYStatus & PHY_LINK_SPEED100 ) == PHY_LINK_SPEED100 )
\r
104 IP_ENET_SetSpeed( LPC_ETHERNET, pdTRUE );
\r
108 IP_ENET_SetSpeed( LPC_ETHERNET, pdFALSE );
\r
111 /* Set descriptors to their initial state. */
\r
112 prvResetRxDescriptors();
\r
113 prvResetTxDescriptors();
\r
115 /* Enable RX and TX. */
\r
116 Chip_ENET_TXEnable( LPC_ETHERNET );
\r
117 Chip_ENET_RXEnable( LPC_ETHERNET );
\r
119 /* Enable the interrupt and set its priority as configured. THIS
\r
120 DRIVER REQUIRES configMAC_INTERRUPT_PRIORITY TO BE DEFINED, PREFERABLY
\r
121 IN FreeRTOSConfig.h. */
\r
122 NVIC_SetPriority( ETHERNET_IRQn, configMAC_INTERRUPT_PRIORITY );
\r
123 NVIC_EnableIRQ( ETHERNET_IRQn );
\r
125 /* Enable interrupts. */
\r
126 LPC_ETHERNET->DMA_INT_EN = DMA_IE_NIE | DMA_IE_RIE;
\r
137 /*-----------------------------------------------------------*/
\r
139 BaseType_t xEMACIsTxDescriptorAvailable( void )
\r
141 BaseType_t xReturn;
\r
143 if( ( xTxDescriptors[ xTxDescriptorIndex ].CTRLSTAT & RDES_OWN ) == 0 )
\r
154 /*-----------------------------------------------------------*/
\r
156 void vEMACAssignBufferToDescriptor( uint8_t * pucBuffer )
\r
158 /* The old packet is now finished with and can be freed. */
\r
159 vEthernetBufferRelease( ( void * ) xTxDescriptors[ xTxDescriptorIndex ].B1ADD );
\r
161 /* Assign the new packet to the descriptor. */
\r
162 xTxDescriptors[ xTxDescriptorIndex ].B1ADD = ( uint32_t ) pucBuffer;
\r
164 /*-----------------------------------------------------------*/
\r
166 void vEMACStartNextTransmission( uint32_t ulLength )
\r
168 xTxDescriptors[ xTxDescriptorIndex ].BSIZE = ulLength;
\r
169 xTxDescriptors[ xTxDescriptorIndex ].CTRLSTAT |= RDES_OWN;
\r
171 /* Wake Up the DMA if it's in Suspended Mode. */
\r
172 LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1;
\r
173 xTxDescriptorIndex++;
\r
175 if( xTxDescriptorIndex == configNUM_TX_ETHERNET_DMA_DESCRIPTORS )
\r
177 xTxDescriptorIndex = 0;
\r
180 /*-----------------------------------------------------------*/
\r
182 static uint32_t prvReceivedDataLength( void )
\r
184 unsigned short RxLen = 0;
\r
186 RxLen = ( xRXDescriptors[ xRxDescriptorIndex ].STATUS >> 16 ) & 0x03FFF;
\r
189 /*-----------------------------------------------------------*/
\r
191 void vEMACReturnRxDescriptor( void )
\r
193 xRXDescriptors[ xRxDescriptorIndex ].STATUS = RDES_OWN;
\r
194 xRxDescriptorIndex++;
\r
196 if( xRxDescriptorIndex == configNUM_RX_ETHERNET_DMA_DESCRIPTORS )
\r
198 xRxDescriptorIndex = 0;
\r
201 /*-----------------------------------------------------------*/
\r
203 BaseType_t xEMACRxDataAvailable( void )
\r
205 BaseType_t xReturn;
\r
207 if( ( xRXDescriptors[ xRxDescriptorIndex ].STATUS & RDES_OWN ) == 0 )
\r
218 /*-----------------------------------------------------------*/
\r
220 void vEMACSwapEmptyBufferForRxedData( xNetworkBufferDescriptor_t *pxNetworkBuffer )
\r
224 /* Swap the buffer in the network buffer with the buffer used by the DMA.
\r
225 This allows the data to be passed out without having to perform any copies. */
\r
226 pucTemp = ( uint8_t * ) xRXDescriptors[ xRxDescriptorIndex ].B1ADD;
\r
227 xRXDescriptors[ xRxDescriptorIndex ].B1ADD = ( uint32_t ) pxNetworkBuffer->pucEthernetBuffer;
\r
228 pxNetworkBuffer->pucEthernetBuffer = pucTemp;
\r
230 /* Only supports frames coming in single buffers. If this frame is split
\r
231 across multiple buffers then reject it (and if the frame is needed increase
\r
232 the ipconfigNETWORK_MTU setting). */
\r
233 if( ( xRXDescriptors[ xRxDescriptorIndex ].STATUS & emacEXPECTED_RX_STATUS_MASK ) != emacEXPECTED_RX_STATUS_MASK )
\r
235 pxNetworkBuffer->xDataLength = 0;
\r
239 pxNetworkBuffer->xDataLength = ( size_t ) prvReceivedDataLength() - ( ipETHERNET_CRC_BYTES - 1U );;
\r
242 /*-----------------------------------------------------------*/
\r
244 static void prvResetRxDescriptors( void )
\r
247 size_t xBufferSize = ipTOTAL_ETHERNET_FRAME_SIZE;
\r
249 for( x = 0; x < configNUM_RX_ETHERNET_DMA_DESCRIPTORS; x++ )
\r
251 /* Obtain the buffer first, as the size of the buffer might be changed
\r
252 within the pucEthernetBufferGet() call. */
\r
253 xRXDescriptors[ x ].B1ADD = ( uint32_t ) pucEthernetBufferGet( &xBufferSize );
\r
254 xRXDescriptors[ x ].STATUS = RDES_OWN;
\r
255 xRXDescriptors[ x ].CTRL = xBufferSize;
\r
256 xRXDescriptors[ x ].B2ADD = ( uint32_t ) &xRXDescriptors[ x + 1 ];
\r
258 configASSERT( ( ( ( uint32_t ) xRXDescriptors[x].B1ADD ) & 0x07 ) == 0 );
\r
261 /* Last Descriptor */
\r
262 xRXDescriptors[ configNUM_RX_ETHERNET_DMA_DESCRIPTORS - 1 ].CTRL |= RDES_ENH_RER;
\r
264 xRxDescriptorIndex = 0;
\r
266 /* Set Starting address of RX Descriptor list */
\r
267 LPC_ETHERNET->DMA_REC_DES_ADDR = ( uint32_t ) xRXDescriptors;
\r
269 /*-----------------------------------------------------------*/
\r
271 static void prvResetTxDescriptors( void )
\r
273 /* Initialize Transmit Descriptor and Status array. */
\r
276 for( x = 0; x < configNUM_TX_ETHERNET_DMA_DESCRIPTORS; x++ )
\r
278 xTxDescriptors[ x ].CTRLSTAT = TDES_ENH_FS | TDES_ENH_LS;
\r
279 xTxDescriptors[ x ].BSIZE = 0;
\r
280 xTxDescriptors[ x ].B2ADD = ( uint32_t ) &xTxDescriptors[ x + 1 ];
\r
282 /* Packet is assigned when a Tx is initiated. */
\r
283 xTxDescriptors[ x ].B1ADD = ( uint32_t )NULL;
\r
286 /* Last Descriptor? */
\r
287 xTxDescriptors[ configNUM_TX_ETHERNET_DMA_DESCRIPTORS-1 ].CTRLSTAT |= TDES_ENH_TER;
\r
289 /* Set Starting address of TX Descriptor list */
\r
290 LPC_ETHERNET->DMA_TRANS_DES_ADDR = ( uint32_t ) xTxDescriptors;
\r
292 /*-----------------------------------------------------------*/
\r
294 void ETH_IRQHandler( void )
\r
296 uint32_t ulInterruptCause;
\r
297 extern xSemaphoreHandle xEMACRxEventSemaphore;
\r
299 configASSERT( xEMACRxEventSemaphore );
\r
301 ulInterruptCause = LPC_ETHERNET->DMA_STAT ;
\r
303 /* Clear the interrupt. */
\r
304 LPC_ETHERNET->DMA_STAT |= ( DMA_ST_NIS | DMA_ST_RI );
\r
306 /* Clear fatal error conditions. NOTE: The driver does not clear all
\r
307 errors, only those actually experienced. For future reference, range
\r
308 errors are not actually errors so can be ignored. */
\r
309 if( ( ulInterruptCause & DMA_ST_FBI ) != 0U )
\r
311 LPC_ETHERNET->DMA_STAT |= DMA_ST_FBI;
\r
314 /* Unblock the deferred interrupt handler task if the event was an Rx. */
\r
315 if( ( ulInterruptCause & DMA_IE_RIE ) != 0UL )
\r
317 xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL );
\r
320 /* ulInterruptCause is used for convenience here. A context switch is
\r
321 wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a
\r
322 compiler warning. */
\r
323 portEND_SWITCHING_ISR( ulInterruptCause );
\r