2 * Some constants, hardware definitions and comments taken from ST's HAL driver
\r
3 * library, COPYRIGHT(c) 2015 STMicroelectronics.
\r
7 * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
\r
8 * Authors include Hein Tibosch and Richard Barry
\r
10 *******************************************************************************
\r
11 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
14 *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
\r
15 *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
\r
18 *** FreeRTOS+TCP is functional and has been used in commercial products ***
\r
19 *** for some time. Be aware however that we are still refining its ***
\r
20 *** design, the source code does not yet quite conform to the strict ***
\r
21 *** coding and style standards mandated by Real Time Engineers ltd., and ***
\r
22 *** the documentation and testing is not necessarily complete. ***
\r
24 *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
\r
25 *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
\r
26 *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
\r
27 *** under a license other than that described below. ***
\r
30 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
31 *******************************************************************************
\r
33 * FreeRTOS+TCP can be used under two different free open source licenses. The
\r
34 * license that applies is dependent on the processor on which FreeRTOS+TCP is
\r
35 * executed, as follows:
\r
37 * If FreeRTOS+TCP is executed on one of the processors listed under the Special
\r
38 * License Arrangements heading of the FreeRTOS+TCP license information web
\r
39 * page, then it can be used under the terms of the FreeRTOS Open Source
\r
40 * License. If FreeRTOS+TCP is used on any other processor, then it can be used
\r
41 * under the terms of the GNU General Public License V2. Links to the relevant
\r
44 * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
\r
45 * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
\r
46 * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
\r
48 * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
\r
49 * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
\r
50 * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
\r
51 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
52 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
53 * implied, expressed, or statutory.
\r
55 * 1 tab == 4 spaces!
\r
57 * http://www.FreeRTOS.org
\r
58 * http://www.FreeRTOS.org/plus
\r
59 * http://www.FreeRTOS.org/labs
\r
63 /* Standard includes. */
\r
68 /* FreeRTOS includes. */
\r
69 #include "FreeRTOS.h"
\r
74 /* FreeRTOS+TCP includes. */
\r
75 #include "FreeRTOS_IP.h"
\r
76 #include "FreeRTOS_Sockets.h"
\r
77 #include "FreeRTOS_IP_Private.h"
\r
78 #include "FreeRTOS_DNS.h"
\r
79 #include "NetworkBufferManagement.h"
\r
80 #include "NetworkInterface.h"
\r
83 #include "stm32f4xx_hal.h"
\r
85 #ifndef BMSR_LINK_STATUS
\r
86 #define BMSR_LINK_STATUS 0x0004UL
\r
89 #ifndef PHY_LS_HIGH_CHECK_TIME_MS
\r
90 /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
\r
91 receiving packets. */
\r
92 #define PHY_LS_HIGH_CHECK_TIME_MS 15000
\r
95 #ifndef PHY_LS_LOW_CHECK_TIME_MS
\r
96 /* Check if the LinkSStatus in the PHY is still low every second. */
\r
97 #define PHY_LS_LOW_CHECK_TIME_MS 1000
\r
100 /* Interrupt events to process. Currently only the Rx event is processed
\r
101 although code for other events is included to allow for possible future
\r
103 #define EMAC_IF_RX_EVENT 1UL
\r
104 #define EMAC_IF_TX_EVENT 2UL
\r
105 #define EMAC_IF_ERR_EVENT 4UL
\r
106 #define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
\r
108 #define ETH_DMA_ALL_INTS \
\r
109 ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_ER | \
\r
110 ETH_DMA_IT_FBE | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \
\r
111 ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T )
\r
113 /* Naming and numbering of PHY registers. */
\r
114 #define PHY_REG_00_BMCR 0x00 /* Basic Mode Control Register. */
\r
115 #define PHY_REG_01_BMSR 0x01 /* Basic Mode Status Register. */
\r
116 #define PHY_REG_02_PHYSID1 0x02 /* PHYS ID 1 */
\r
117 #define PHY_REG_03_PHYSID2 0x03 /* PHYS ID 2 */
\r
118 #define PHY_REG_04_ADVERTISE 0x04 /* Advertisement control reg */
\r
120 #define PHY_ID_LAN8720 0x0007c0f0
\r
121 #define PHY_ID_DP83848I 0x20005C90
\r
123 #ifndef USE_STM324xG_EVAL
\r
124 #define USE_STM324xG_EVAL 1
\r
127 #if( USE_STM324xG_EVAL == 0 )
\r
128 #define EXPECTED_PHY_ID PHY_ID_LAN8720
\r
129 #define PHY_REG_1F_PHYSPCS 0x1F /* 31 RW PHY Special Control Status */
\r
130 /* Use 3 bits in register 31 */
\r
131 #define PHYSPCS_SPEED_MASK 0x0C
\r
132 #define PHYSPCS_SPEED_10 0x04
\r
133 #define PHYSPCS_SPEED_100 0x08
\r
134 #define PHYSPCS_FULL_DUPLEX 0x10
\r
136 #define EXPECTED_PHY_ID PHY_ID_DP83848I
\r
138 #define PHY_REG_10_PHY_SR 0x10 /* PHY status register Offset */
\r
139 #define PHY_REG_19_PHYCR 0x19 /* 25 RW PHY Control Register */
\r
142 /* Some defines used internally here to indicate preferences about speed, MDIX
\r
143 (wired direct or crossed), and duplex (half or full). */
\r
144 #define PHY_SPEED_10 1
\r
145 #define PHY_SPEED_100 2
\r
146 #define PHY_SPEED_AUTO (PHY_SPEED_10|PHY_SPEED_100)
\r
148 #define PHY_MDIX_DIRECT 1
\r
149 #define PHY_MDIX_CROSSED 2
\r
150 #define PHY_MDIX_AUTO (PHY_MDIX_CROSSED|PHY_MDIX_DIRECT)
\r
152 #define PHY_DUPLEX_HALF 1
\r
153 #define PHY_DUPLEX_FULL 2
\r
154 #define PHY_DUPLEX_AUTO (PHY_DUPLEX_FULL|PHY_DUPLEX_HALF)
\r
156 #define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */
\r
159 * Description of all capabilities that can be advertised to
\r
160 * the peer (usually a switch or router).
\r
162 #define ADVERTISE_CSMA 0x0001 /* Only selector supported. */
\r
163 #define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex. */
\r
164 #define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex. */
\r
165 #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex. */
\r
166 #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex. */
\r
168 #define ADVERTISE_ALL ( ADVERTISE_10HALF | ADVERTISE_10FULL | \
\r
169 ADVERTISE_100HALF | ADVERTISE_100FULL)
\r
172 * Value for the 'PHY_REG_00_BMCR', the PHY's Basic Mode Control Register.
\r
174 #define BMCR_FULLDPLX 0x0100 /* Full duplex. */
\r
175 #define BMCR_ANRESTART 0x0200 /* Auto negotiation restart. */
\r
176 #define BMCR_ANENABLE 0x1000 /* Enable auto negotiation. */
\r
177 #define BMCR_SPEED100 0x2000 /* Select 100Mbps. */
\r
178 #define BMCR_RESET 0x8000 /* Reset the PHY. */
\r
180 #define PHYCR_MDIX_EN 0x8000 /* Enable Auto MDIX. */
\r
181 #define PHYCR_MDIX_FORCE 0x4000 /* Force MDIX crossed. */
\r
183 #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */
\r
186 * Most users will want a PHY that negotiates about
\r
187 * the connection properties: speed, dmix and duplex.
\r
188 * On some rare cases, you want to select what is being
\r
189 * advertised, properties like MDIX and duplex.
\r
192 #if !defined( ipconfigETHERNET_AN_ENABLE )
\r
193 /* Enable auto-negotiation */
\r
194 #define ipconfigETHERNET_AN_ENABLE 1
\r
197 #if !defined( ipconfigETHERNET_AUTO_CROSS_ENABLE )
\r
198 #define ipconfigETHERNET_AUTO_CROSS_ENABLE 1
\r
201 #if( ipconfigETHERNET_AN_ENABLE == 0 )
\r
203 * The following three defines are only used in case there
\r
204 * is no auto-negotiation.
\r
206 #if !defined( ipconfigETHERNET_CROSSED_LINK )
\r
207 #define ipconfigETHERNET_CROSSED_LINK 1
\r
210 #if !defined( ipconfigETHERNET_USE_100MB )
\r
211 #define ipconfigETHERNET_USE_100MB 1
\r
214 #if !defined( ipconfigETHERNET_USE_FULL_DUPLEX )
\r
215 #define ipconfigETHERNET_USE_FULL_DUPLEX 1
\r
217 #endif /* ipconfigETHERNET_AN_ENABLE == 0 */
\r
219 /* Default the size of the stack used by the EMAC deferred handler task to twice
\r
220 the size of the stack used by the idle task - but allow this to be overridden in
\r
221 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
\r
222 #ifndef configEMAC_TASK_STACK_SIZE
\r
223 #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )
\r
226 /*-----------------------------------------------------------*/
\r
229 * A deferred interrupt handler task that processes
\r
231 static void prvEMACHandlerTask( void *pvParameters );
\r
234 * Force a negotiation with the Switch or Router and wait for LS.
\r
236 static void prvEthernetUpdateConfig( BaseType_t xForce );
\r
239 * See if there is a new packet and forward it to the IP-task.
\r
241 static BaseType_t prvNetworkInterfaceInput( void );
\r
243 #if( ipconfigUSE_LLMNR != 0 )
\r
245 * For LLMNR, an extra MAC-address must be configured to
\r
246 * be able to receive the multicast messages.
\r
248 static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr);
\r
252 * Check if a given packet should be accepted.
\r
254 static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer );
\r
257 * Initialise the TX descriptors.
\r
259 static void prvDMATxDescListInit( void );
\r
262 * Initialise the RX descriptors.
\r
264 static void prvDMARxDescListInit( void );
\r
266 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
267 /* After packets have been sent, the network
\r
268 buffers will be released. */
\r
269 static void vClearTXBuffers( void );
\r
270 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
272 /*-----------------------------------------------------------*/
\r
274 typedef struct _PhyProperties_t
\r
282 /* Bit map of outstanding ETH interrupt events for processing. Currently only
\r
283 the Rx interrupt is handled, although code is included for other events to
\r
284 enable future expansion. */
\r
285 static volatile uint32_t ulISREvents;
\r
287 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
\r
288 static uint32_t ulPHYLinkStatus = 0;
\r
290 #if( ipconfigUSE_LLMNR == 1 )
\r
291 static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
\r
294 /* Ethernet handle. */
\r
295 static ETH_HandleTypeDef xETH;
\r
297 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
298 /* xTXDescriptorSemaphore is a counting semaphore with
\r
299 a maximum count of ETH_TXBUFNB, which is the number of
\r
300 DMA TX descriptors. */
\r
301 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
\r
302 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
305 * Note: it is adviced to define both
\r
307 * #define ipconfigZERO_COPY_RX_DRIVER 1
\r
308 * #define ipconfigZERO_COPY_TX_DRIVER 1
\r
310 * The method using memcpy is slower and probaly uses more RAM memory.
\r
311 * The possibility is left in the code just for comparison.
\r
313 * It is adviced to define ETH_TXBUFNB at least 4. Note that no
\r
314 * TX buffers are allocated in a zero-copy driver.
\r
316 /* MAC buffers: ---------------------------------------------------------*/
\r
317 __ALIGN_BEGIN ETH_DMADescTypeDef DMARxDscrTab[ ETH_RXBUFNB ] __ALIGN_END;/* Ethernet Rx MA Descriptor */
\r
318 #if( ipconfigZERO_COPY_RX_DRIVER == 0 )
\r
319 __ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END; /* Ethernet Receive Buffer */
\r
322 __ALIGN_BEGIN ETH_DMADescTypeDef DMATxDscrTab[ ETH_TXBUFNB ] __ALIGN_END;/* Ethernet Tx DMA Descriptor */
\r
323 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
\r
324 __ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END; /* Ethernet Transmit Buffer */
\r
327 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
328 /* DMATxDescToClear points to the next TX DMA descriptor
\r
329 that must be cleared by vClearTXBuffers(). */
\r
330 static __IO ETH_DMADescTypeDef *DMATxDescToClear;
\r
333 /* Value to be written into the 'Basic mode Control Register'. */
\r
334 static uint32_t ulBCRvalue;
\r
336 /* Value to be written into the 'Advertisement Control Register'. */
\r
337 static uint32_t ulACRValue;
\r
339 /* ucMACAddress as it appears in main.c */
\r
340 extern const uint8_t ucMACAddress[ 6 ];
\r
342 /* Holds the handle of the task used as a deferred interrupt processor. The
\r
343 handle is used so direct notifications can be sent to the task for all EMAC/DMA
\r
344 related interrupts. */
\r
345 static TaskHandle_t xEMACTaskHandle = NULL;
\r
347 /* For local use only: describe the PHY's properties: */
\r
348 const PhyProperties_t xPHYProperties =
\r
350 #if( ipconfigETHERNET_AN_ENABLE != 0 )
\r
351 .speed = PHY_SPEED_AUTO,
\r
352 .duplex = PHY_DUPLEX_AUTO,
\r
354 #if( ipconfigETHERNET_USE_100MB != 0 )
\r
355 .speed = PHY_SPEED_100,
\r
357 .speed = PHY_SPEED_10,
\r
360 #if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 )
\r
361 .duplex = PHY_DUPLEX_FULL,
\r
363 .duplex = PHY_DUPLEX_HALF,
\r
367 #if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 )
\r
368 .mdix = PHY_MDIX_AUTO,
\r
369 #elif( ipconfigETHERNET_CROSSED_LINK != 0 )
\r
370 .mdix = PHY_MDIX_CROSSED,
\r
372 .mdix = PHY_MDIX_DIRECT,
\r
376 /*-----------------------------------------------------------*/
\r
378 void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth )
\r
380 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
382 /* Ethernet RX-Complete callback function, elsewhere declared as weak. */
\r
383 ulISREvents |= EMAC_IF_RX_EVENT;
\r
384 /* Wakeup the prvEMACHandlerTask. */
\r
385 if( xEMACTaskHandle != NULL )
\r
387 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
\r
388 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r
391 /*-----------------------------------------------------------*/
\r
393 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
394 void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth )
\r
396 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
398 /* This call-back is only useful in case packets are being sent
\r
399 zero-copy. Once they're sent, the buffers will be released
\r
400 by the function vClearTXBuffers(). */
\r
401 ulISREvents |= EMAC_IF_TX_EVENT;
\r
402 /* Wakeup the prvEMACHandlerTask. */
\r
403 if( xEMACTaskHandle != NULL )
\r
405 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
\r
406 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r
410 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
412 /*-----------------------------------------------------------*/
\r
414 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
415 static void vClearTXBuffers()
\r
417 __IO ETH_DMADescTypeDef *txLastDescriptor = xETH.TxDesc;
\r
418 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
419 uint8_t *ucPayLoad;
\r
420 size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
\r
422 /* This function is called after a TX-completion interrupt.
\r
423 It will release each Network Buffer used in xNetworkInterfaceOutput().
\r
424 'uxCount' represents the number of descriptors given to DMA for transmission.
\r
425 After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */
\r
426 while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) )
\r
428 if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) )
\r
433 ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr;
\r
435 if( ucPayLoad != NULL )
\r
437 pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );
\r
438 if( pxNetworkBuffer != NULL )
\r
440 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;
\r
442 DMATxDescToClear->Buffer1Addr = ( uint32_t )0u;
\r
445 DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr );
\r
448 /* Tell the counting semaphore that one more TX descriptor is available. */
\r
449 xSemaphoreGive( xTXDescriptorSemaphore );
\r
452 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
453 /*-----------------------------------------------------------*/
\r
455 BaseType_t xNetworkInterfaceInitialise( void )
\r
457 HAL_StatusTypeDef hal_eth_init_status;
\r
458 BaseType_t xResult;
\r
460 if( xEMACTaskHandle == NULL )
\r
462 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
464 if( xTXDescriptorSemaphore == NULL )
\r
466 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB );
\r
467 configASSERT( xTXDescriptorSemaphore );
\r
470 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
472 /* Initialise ETH */
\r
474 xETH.Instance = ETH;
\r
475 xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
\r
476 xETH.Init.Speed = ETH_SPEED_100M;
\r
477 xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
\r
478 xETH.Init.PhyAddress = 1;
\r
480 xETH.Init.MACAddr = ( uint8_t *) ucMACAddress;
\r
481 xETH.Init.RxMode = ETH_RXINTERRUPT_MODE;
\r
483 /* using the ETH_CHECKSUM_BY_HARDWARE option:
\r
484 both the IP and the protocol checksums will be calculated
\r
485 by the peripheral. */
\r
486 xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
\r
488 xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII;
\r
489 hal_eth_init_status = HAL_ETH_Init( &xETH );
\r
491 /* Only for inspection by debugger. */
\r
492 ( void ) hal_eth_init_status;
\r
494 /* Set the TxDesc and RxDesc pointers. */
\r
495 xETH.TxDesc = DMATxDscrTab;
\r
496 xETH.RxDesc = DMARxDscrTab;
\r
498 /* Make sure that all unused fields are cleared. */
\r
499 memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) );
\r
500 memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) );
\r
502 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
504 /* Initialize Tx Descriptors list: Chain Mode */
\r
505 DMATxDescToClear = DMATxDscrTab;
\r
507 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
509 /* Initialise TX-descriptors. */
\r
510 prvDMATxDescListInit();
\r
512 /* Initialise RX-descriptors. */
\r
513 prvDMARxDescListInit();
\r
515 #if( ipconfigUSE_LLMNR != 0 )
\r
517 /* Program the LLMNR address at index 1. */
\r
518 prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress );
\r
522 /* Force a negotiation with the Switch or Router and wait for LS. */
\r
523 prvEthernetUpdateConfig( pdTRUE );
\r
525 /* The deferred interrupt handler task is created at the highest
\r
526 possible priority to ensure the interrupt handler can return directly
\r
527 to it. The task's handle is stored in xEMACTaskHandle so interrupts can
\r
528 notify the task when there is something to process. */
\r
529 xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
\r
530 } /* if( xEMACTaskHandle == NULL ) */
\r
532 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
534 xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS;
\r
536 FreeRTOS_printf( ( "Link Status is high\n" ) ) ;
\r
540 /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running
\r
541 and it will keep on checking the PHY and set ulPHYLinkStatus when necessary. */
\r
543 FreeRTOS_printf( ( "Link Status still low\n" ) ) ;
\r
545 /* When returning non-zero, the stack will become active and
\r
546 start DHCP (in configured) */
\r
549 /*-----------------------------------------------------------*/
\r
551 static void prvDMATxDescListInit()
\r
553 ETH_DMADescTypeDef *pxDMADescriptor;
\r
556 /* Get the pointer on the first member of the descriptor list */
\r
557 pxDMADescriptor = DMATxDscrTab;
\r
559 /* Fill each DMA descriptor with the right values */
\r
560 for( xIndex = 0; xIndex < ETH_TXBUFNB; xIndex++, pxDMADescriptor++ )
\r
562 /* Set Second Address Chained bit */
\r
563 pxDMADescriptor->Status = ETH_DMATXDESC_TCH;
\r
565 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
\r
567 /* Set Buffer1 address pointer */
\r
568 pxDMADescriptor->Buffer1Addr = ( uint32_t )( Tx_Buff[ xIndex ] );
\r
572 if( xETH.Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE )
\r
574 /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */
\r
575 pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;
\r
578 /* Initialize the next descriptor with the Next Descriptor Polling Enable */
\r
579 if( xIndex < ETH_TXBUFNB - 1 )
\r
581 /* Set next descriptor address register with next descriptor base address */
\r
582 pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMADescriptor + 1 );
\r
586 /* For last descriptor, set next descriptor address register equal to the first descriptor base address */
\r
587 pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMATxDscrTab;
\r
591 /* Set Transmit Descriptor List Address Register */
\r
592 xETH.Instance->DMATDLAR = ( uint32_t ) DMATxDscrTab;
\r
594 /*-----------------------------------------------------------*/
\r
596 static void prvDMARxDescListInit()
\r
598 ETH_DMADescTypeDef *pxDMADescriptor;
\r
604 /* Get the pointer on the first member of the descriptor list */
\r
605 pxDMADescriptor = DMARxDscrTab;
\r
607 /* Fill each DMA descriptor with the right values */
\r
608 for( xIndex = 0; xIndex < ETH_RXBUFNB; xIndex++, pxDMADescriptor++ )
\r
611 /* Set Buffer1 size and Second Address Chained bit */
\r
612 pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;
\r
614 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
\r
616 /* Set Buffer1 address pointer */
\r
617 NetworkBufferDescriptor_t *pxBuffer;
\r
619 pxBuffer = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, 100ul );
\r
620 /* If the assert below fails, make sure that there are at least 'ETH_RXBUFNB'
\r
621 Network Buffers available during start-up ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) */
\r
622 configASSERT( pxBuffer != NULL );
\r
623 if( pxBuffer != NULL )
\r
625 pxDMADescriptor->Buffer1Addr = (uint32_t)pxBuffer->pucEthernetBuffer;
\r
626 pxDMADescriptor->Status = ETH_DMARXDESC_OWN;
\r
631 /* Set Buffer1 address pointer */
\r
632 pxDMADescriptor->Buffer1Addr = ( uint32_t )( Rx_Buff[ xIndex ] );
\r
633 /* Set Own bit of the Rx descriptor Status */
\r
634 pxDMADescriptor->Status = ETH_DMARXDESC_OWN;
\r
638 /* Initialize the next descriptor with the Next Descriptor Polling Enable */
\r
639 if( xIndex < ETH_RXBUFNB - 1 )
\r
641 /* Set next descriptor address register with next descriptor base address */
\r
642 pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t )( pxDMADescriptor + 1 );
\r
646 /* For last descriptor, set next descriptor address register equal to the first descriptor base address */
\r
647 pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMARxDscrTab;
\r
651 /* Set Receive Descriptor List Address Register */
\r
652 xETH.Instance->DMARDLAR = ( uint32_t ) DMARxDscrTab;
\r
654 /*-----------------------------------------------------------*/
\r
656 static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr)
\r
658 uint32_t ulTempReg;
\r
660 /* Calculate the selected MAC address high register. */
\r
661 ulTempReg = 0x80000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ];
\r
663 /* Load the selected MAC address high register. */
\r
664 ( *(__IO uint32_t *)( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + ulIndex ) ) ) = ulTempReg;
\r
666 /* Calculate the selected MAC address low register. */
\r
667 ulTempReg = ( ( uint32_t ) Addr[ 3 ] << 24 ) | ( ( uint32_t ) Addr[ 2 ] << 16 ) | ( ( uint32_t ) Addr[ 1 ] << 8 ) | Addr[ 0 ];
\r
669 /* Load the selected MAC address low register */
\r
670 ( *(__IO uint32_t *) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + ulIndex ) ) ) = ulTempReg;
\r
672 /*-----------------------------------------------------------*/
\r
674 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
\r
676 BaseType_t xReturn = pdFAIL;
\r
677 uint32_t ulTransmitSize = 0;
\r
678 __IO ETH_DMADescTypeDef *pxDmaTxDesc;
\r
679 /* Do not wait too long for a free TX DMA buffer. */
\r
680 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
\r
682 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
\r
684 ProtocolPacket_t *pxPacket;
\r
686 /* If the peripheral must calculate the checksum, it wants
\r
687 the protocol checksum to have a value of zero. */
\r
688 pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer );
\r
690 if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP )
\r
692 pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u;
\r
697 /* Open a do {} while ( 0 ) loop to be able to call break. */
\r
700 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
702 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
704 if( xTXDescriptorSemaphore == NULL )
\r
708 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
\r
710 /* Time-out waiting for a free TX descriptor. */
\r
714 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
716 /* This function does the actual transmission of the packet. The packet is
\r
717 contained in 'pxDescriptor' that is passed to the function. */
\r
718 pxDmaTxDesc = xETH.TxDesc;
\r
720 /* Is this buffer available? */
\r
721 if( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 )
\r
723 /* Is this buffer available? */
\r
724 /* Get bytes in current buffer. */
\r
725 ulTransmitSize = pxDescriptor->xDataLength;
\r
727 if( ulTransmitSize > ETH_TX_BUF_SIZE )
\r
729 ulTransmitSize = ETH_TX_BUF_SIZE;
\r
732 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
\r
734 /* Copy the bytes. */
\r
735 memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize );
\r
736 pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL;
\r
740 /* Move the buffer. */
\r
741 pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer;
\r
742 /* Ask to set the IPv4 checksum.
\r
743 Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */
\r
744 pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC;
\r
745 /* The Network Buffer has been passed to DMA, no need to release it. */
\r
746 bReleaseAfterSend = pdFALSE_UNSIGNED;
\r
748 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
750 /* Prepare transmit descriptors to give to DMA. */
\r
752 /* Set LAST and FIRST segment */
\r
753 pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS;
\r
754 /* Set frame size */
\r
755 pxDmaTxDesc->ControlBufferSize = ( ulTransmitSize & ETH_DMATXDESC_TBS1 );
\r
756 /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
\r
757 pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN;
\r
759 /* Point to next descriptor */
\r
760 xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr );
\r
762 /* Resume DMA transmission*/
\r
763 xETH.Instance->DMATPDR = 0;
\r
764 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
770 /* The PHY has no Link Status, packet shall be dropped. */
\r
773 /* The buffer has been sent so can be released. */
\r
774 if( bReleaseAfterSend != pdFALSE )
\r
776 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
\r
781 /*-----------------------------------------------------------*/
\r
783 static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer )
\r
785 const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer;
\r
787 switch( pxProtPacket->xTCPPacket.xEthernetHeader.usFrameType )
\r
789 case ipARP_FRAME_TYPE:
\r
790 /* Check it later. */
\r
792 case ipIPv4_FRAME_TYPE:
\r
793 /* Check it here. */
\r
796 /* Refuse the packet. */
\r
800 #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
\r
802 const IPHeader_t *pxIPHeader = &(pxProtPacket->xTCPPacket.xIPHeader);
\r
803 uint32_t ulDestinationIPAddress;
\r
805 /* Ensure that the incoming packet is not fragmented (only outgoing packets
\r
806 * can be fragmented) as these are the only handled IP frames currently. */
\r
807 if( ( pxIPHeader->usFragmentOffset & FreeRTOS_ntohs( ipFRAGMENT_OFFSET_BIT_MASK ) ) != 0U )
\r
811 /* HT: Might want to make the following configurable because
\r
812 * most IP messages have a standard length of 20 bytes */
\r
814 /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes
\r
815 * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */
\r
816 if( pxIPHeader->ucVersionHeaderLength < 0x45 || pxIPHeader->ucVersionHeaderLength > 0x4F )
\r
821 ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;
\r
822 /* Is the packet for this node? */
\r
823 if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&
\r
824 /* Is it a broadcast address x.x.x.255 ? */
\r
825 ( ( FreeRTOS_ntohl( ulDestinationIPAddress ) & 0xff ) != 0xff ) &&
\r
826 #if( ipconfigUSE_LLMNR == 1 )
\r
827 ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&
\r
829 ( *ipLOCAL_IP_ADDRESS_POINTER != 0 ) ) {
\r
830 FreeRTOS_printf( ( "Drop IP %lxip\n", FreeRTOS_ntohl( ulDestinationIPAddress ) ) );
\r
834 if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP )
\r
836 uint16_t port = pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort;
\r
838 if( ( xPortHasUDPSocket( port ) == pdFALSE )
\r
839 #if ipconfigUSE_LLMNR == 1
\r
840 && ( port != FreeRTOS_ntohs( ipLLMNR_PORT ) )
\r
842 #if ipconfigUSE_NBNS == 1
\r
843 && ( port != FreeRTOS_ntohs( ipNBNS_PORT ) )
\r
845 #if ipconfigUSE_DNS == 1
\r
846 && ( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort != FreeRTOS_ntohs( ipDNS_PORT ) )
\r
849 /* Drop this packet, not for this device. */
\r
854 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
\r
857 /*-----------------------------------------------------------*/
\r
859 static BaseType_t prvNetworkInterfaceInput( void )
\r
861 NetworkBufferDescriptor_t *pxCurDescriptor;
\r
862 NetworkBufferDescriptor_t *pxNewDescriptor = NULL;
\r
863 BaseType_t xReceivedLength, xAccepted;
\r
864 __IO ETH_DMADescTypeDef *pxDMARxDescriptor;
\r
865 xIPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
\r
866 const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 );
\r
867 uint8_t *pucBuffer;
\r
869 pxDMARxDescriptor = xETH.RxDesc;
\r
871 if( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN) == 0 )
\r
873 /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
\r
874 xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4;
\r
876 pucBuffer = (uint8_t *) pxDMARxDescriptor->Buffer1Addr;
\r
878 /* Update the ETHERNET DMA global Rx descriptor with next Rx descriptor */
\r
879 /* Chained Mode */
\r
880 /* Selects the next DMA Rx descriptor list for next buffer to read */
\r
881 xETH.RxDesc = ( ETH_DMADescTypeDef* )pxDMARxDescriptor->Buffer2NextDescAddr;
\r
885 xReceivedLength = 0;
\r
888 /* Obtain the size of the packet and put it into the "usReceivedLength" variable. */
\r
890 /* get received frame */
\r
891 if( xReceivedLength > 0ul )
\r
893 /* In order to make the code easier and faster, only packets in a single buffer
\r
894 will be accepted. This can be done by making the buffers large enough to
\r
895 hold a complete Ethernet packet (1536 bytes).
\r
896 Therefore, two sanity checks: */
\r
897 configASSERT( xReceivedLength <= ETH_RX_BUF_SIZE );
\r
899 if( ( pxDMARxDescriptor->Status & ( ETH_DMARXDESC_CE | ETH_DMARXDESC_IPV4HCE | ETH_DMARXDESC_FT ) ) != ETH_DMARXDESC_FT )
\r
901 /* Not an Ethernet frame-type or a checmsum error. */
\r
902 xAccepted = pdFALSE;
\r
906 /* See if this packet must be handled. */
\r
907 xAccepted = xMayAcceptPacket( pucBuffer );
\r
910 if( xAccepted != pdFALSE )
\r
912 /* The packet wil be accepted, but check first if a new Network Buffer can
\r
913 be obtained. If not, the packet will still be dropped. */
\r
914 pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, xDescriptorWaitTime );
\r
916 if( pxNewDescriptor == NULL )
\r
918 /* A new descriptor can not be allocated now. This packet will be dropped. */
\r
919 xAccepted = pdFALSE;
\r
922 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
\r
924 /* Find out which Network Buffer was originally passed to the descriptor. */
\r
925 pxCurDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
\r
926 configASSERT( pxCurDescriptor != NULL );
\r
930 /* In this mode, the two descriptors are the same. */
\r
931 pxCurDescriptor = pxNewDescriptor;
\r
932 if( pxNewDescriptor != NULL )
\r
934 /* The packet is acepted and a new Network Buffer was created,
\r
935 copy data to the Network Bufffer. */
\r
936 memcpy( pxNewDescriptor->pucEthernetBuffer, pucBuffer, xReceivedLength );
\r
941 if( xAccepted != pdFALSE )
\r
943 pxCurDescriptor->xDataLength = xReceivedLength;
\r
944 xRxEvent.pvData = ( void * ) pxCurDescriptor;
\r
946 /* Pass the data to the TCP/IP task for processing. */
\r
947 if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE )
\r
949 /* Could not send the descriptor into the TCP/IP stack, it
\r
950 must be released. */
\r
951 vReleaseNetworkBufferAndDescriptor( pxCurDescriptor );
\r
952 iptraceETHERNET_RX_EVENT_LOST();
\r
956 iptraceNETWORK_INTERFACE_RECEIVE();
\r
960 /* Release descriptors to DMA */
\r
961 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
\r
963 /* Set Buffer1 address pointer */
\r
964 if( pxNewDescriptor != NULL )
\r
966 pxDMARxDescriptor->Buffer1Addr = (uint32_t)pxNewDescriptor->pucEthernetBuffer;
\r
970 /* The packet was dropped and the same Network
\r
971 Buffer will be used to receive a new packet. */
\r
974 #endif /* ipconfigZERO_COPY_RX_DRIVER */
\r
976 /* Set Buffer1 size and Second Address Chained bit */
\r
977 pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;
\r
978 pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN;
\r
980 /* When Rx Buffer unavailable flag is set clear it and resume
\r
982 if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 )
\r
984 /* Clear RBUS ETHERNET DMA flag. */
\r
985 xETH.Instance->DMASR = ETH_DMASR_RBUS;
\r
987 /* Resume DMA reception. */
\r
988 xETH.Instance->DMARPDR = 0;
\r
992 return ( xReceivedLength > 0 );
\r
994 /*-----------------------------------------------------------*/
\r
996 void vMACBProbePhy( void )
\r
998 uint32_t ulConfig, ulAdvertise, ulLower, ulUpper, ulMACPhyID, ulValue;
\r
999 TimeOut_t xPhyTime;
\r
1000 TickType_t xRemTime = 0;
\r
1001 #if( EXPECTED_PHY_ID == PHY_ID_DP83848I )
\r
1002 uint32_t ulPhyControl;
\r
1005 HAL_ETH_ReadPHYRegister(&xETH, PHY_REG_03_PHYSID2, &ulLower);
\r
1006 HAL_ETH_ReadPHYRegister(&xETH, PHY_REG_02_PHYSID1, &ulUpper);
\r
1008 ulMACPhyID = ( ( ulUpper << 16 ) & 0xFFFF0000 ) | ( ulLower & 0xFFF0 );
\r
1010 /* The expected ID for the 'LAN8720' is 0x0007c0f0. */
\r
1011 /* The expected ID for the 'DP83848I' is 0x20005C90. */
\r
1013 FreeRTOS_printf( ( "PHY ID %lX (%s)\n", ulMACPhyID,
\r
1014 ( ulMACPhyID == EXPECTED_PHY_ID ) ? "OK" : "Unknown" ) );
\r
1016 /* Remove compiler warning if FreeRTOS_printf() is not defined. */
\r
1017 ( void ) ulMACPhyID;
\r
1019 /* Set advertise register. */
\r
1020 if( ( xPHYProperties.speed == PHY_SPEED_AUTO ) && ( xPHYProperties.duplex == PHY_DUPLEX_AUTO ) )
\r
1022 ulAdvertise = ADVERTISE_CSMA | ADVERTISE_ALL;
\r
1023 /* Reset auto-negotiation capability. */
\r
1027 ulAdvertise = ADVERTISE_CSMA;
\r
1029 if( xPHYProperties.speed == PHY_SPEED_AUTO )
\r
1031 if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
\r
1033 ulAdvertise |= ADVERTISE_10FULL | ADVERTISE_100FULL;
\r
1037 ulAdvertise |= ADVERTISE_10HALF | ADVERTISE_100HALF;
\r
1040 else if( xPHYProperties.duplex == PHY_DUPLEX_AUTO )
\r
1042 if( xPHYProperties.speed == PHY_SPEED_10 )
\r
1044 ulAdvertise |= ADVERTISE_10FULL | ADVERTISE_10HALF;
\r
1048 ulAdvertise |= ADVERTISE_100FULL | ADVERTISE_100HALF;
\r
1051 else if( xPHYProperties.speed == PHY_SPEED_100 )
\r
1053 if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
\r
1055 ulAdvertise |= ADVERTISE_100FULL;
\r
1059 ulAdvertise |= ADVERTISE_100HALF;
\r
1064 if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
\r
1066 ulAdvertise |= ADVERTISE_10FULL;
\r
1070 ulAdvertise |= ADVERTISE_10HALF;
\r
1075 /* Read Control register. */
\r
1076 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulConfig );
\r
1078 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulConfig | BMCR_RESET );
\r
1079 xRemTime = ( TickType_t ) pdMS_TO_TICKS( 1000UL );
\r
1080 vTaskSetTimeOutState( &xPhyTime );
\r
1084 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulValue );
\r
1085 if( ( ulValue & BMCR_RESET ) == 0 )
\r
1087 FreeRTOS_printf( ( "BMCR_RESET ready\n" ) );
\r
1090 if( xTaskCheckForTimeOut( &xPhyTime, &xRemTime ) != pdFALSE )
\r
1092 FreeRTOS_printf( ( "BMCR_RESET timed out\n" ) );
\r
1096 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulConfig & ~BMCR_RESET );
\r
1098 vTaskDelay( pdMS_TO_TICKS( 50ul ) );
\r
1100 /* Write advertise register. */
\r
1101 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_04_ADVERTISE, ulAdvertise );
\r
1104 AN_EN AN1 AN0 Forced Mode
\r
1105 0 0 0 10BASE-T, Half-Duplex
\r
1106 0 0 1 10BASE-T, Full-Duplex
\r
1107 0 1 0 100BASE-TX, Half-Duplex
\r
1108 0 1 1 100BASE-TX, Full-Duplex
\r
1109 AN_EN AN1 AN0 Advertised Mode
\r
1110 1 0 0 10BASE-T, Half/Full-Duplex
\r
1111 1 0 1 100BASE-TX, Half/Full-Duplex
\r
1112 1 1 0 10BASE-T Half-Duplex
\r
1113 100BASE-TX, Half-Duplex
\r
1114 1 1 1 10BASE-T, Half/Full-Duplex
\r
1115 100BASE-TX, Half/Full-Duplex
\r
1118 /* Read Control register. */
\r
1119 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulConfig );
\r
1121 ulConfig &= ~( BMCR_ANRESTART | BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX );
\r
1123 /* HT 12/9/14: always set AN-restart and AN-enable, even though the choices
\r
1125 ulConfig |= (BMCR_ANRESTART | BMCR_ANENABLE);
\r
1127 if( xPHYProperties.speed == PHY_SPEED_100 )
\r
1129 ulConfig |= BMCR_SPEED100;
\r
1131 else if( xPHYProperties.speed == PHY_SPEED_10 )
\r
1133 ulConfig &= ~BMCR_SPEED100;
\r
1136 if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
\r
1138 ulConfig |= BMCR_FULLDPLX;
\r
1140 else if( xPHYProperties.duplex == PHY_DUPLEX_HALF )
\r
1142 ulConfig &= ~BMCR_FULLDPLX;
\r
1145 #if( EXPECTED_PHY_ID == PHY_ID_LAN8720 )
\r
1148 #elif( EXPECTED_PHY_ID == PHY_ID_DP83848I )
\r
1150 /* Read PHY Control register. */
\r
1151 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_19_PHYCR, &ulPhyControl );
\r
1153 /* Clear bits which might get set: */
\r
1154 ulPhyControl &= ~( PHYCR_MDIX_EN|PHYCR_MDIX_FORCE );
\r
1156 if( xPHYProperties.mdix == PHY_MDIX_AUTO )
\r
1158 ulPhyControl |= PHYCR_MDIX_EN;
\r
1160 else if( xPHYProperties.mdix == PHY_MDIX_CROSSED )
\r
1162 /* Force direct link = Use crossed RJ45 cable. */
\r
1163 ulPhyControl &= ~PHYCR_MDIX_FORCE;
\r
1167 /* Force crossed link = Use direct RJ45 cable. */
\r
1168 ulPhyControl |= PHYCR_MDIX_FORCE;
\r
1170 /* update PHY Control Register. */
\r
1171 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_19_PHYCR, ulPhyControl );
\r
1174 FreeRTOS_printf( ( "+TCP: advertise: %lX config %lX\n", ulAdvertise, ulConfig ) );
\r
1176 /* Now the two values to global values for later use. */
\r
1177 ulBCRvalue = ulConfig;
\r
1178 ulACRValue = ulAdvertise;
\r
1180 /*-----------------------------------------------------------*/
\r
1182 static void prvEthernetUpdateConfig( BaseType_t xForce )
\r
1184 __IO uint32_t ulTimeout = 0;
\r
1185 uint32_t ulRegValue = 0;
\r
1187 FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS %d Force %d\n",
\r
1188 ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ,
\r
1191 if( ( xForce != pdFALSE ) || ( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) )
\r
1193 /* Restart the auto-negotiation. */
\r
1194 if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE )
\r
1196 /* Enable Auto-Negotiation. */
\r
1197 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulBCRvalue | BMCR_ANRESTART );
\r
1198 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_04_ADVERTISE, ulACRValue);
\r
1200 /* Wait until the auto-negotiation will be completed */
\r
1204 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &ulRegValue );
\r
1205 } while( ( ( ulRegValue & PHY_AUTONEGO_COMPLETE) == 0 ) && ( ulTimeout < PHY_READ_TO ) );
\r
1207 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulBCRvalue & ~BMCR_ANRESTART );
\r
1209 if( ulTimeout < PHY_READ_TO )
\r
1211 /* Reset Timeout counter. */
\r
1214 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &ulRegValue);
\r
1215 if( ( ulRegValue & BMSR_LINK_STATUS ) != 0 )
\r
1217 ulPHYLinkStatus |= BMSR_LINK_STATUS;
\r
1221 ulPHYLinkStatus &= ~( BMSR_LINK_STATUS );
\r
1224 #if( EXPECTED_PHY_ID == PHY_ID_LAN8720 )
\r
1226 /* 31 RW PHY Special Control Status */
\r
1227 uint32_t ulControlStatus;
\r
1229 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_1F_PHYSPCS, &ulControlStatus);
\r
1231 if( ( ulControlStatus & PHYSPCS_FULL_DUPLEX ) != 0 )
\r
1233 ulRegValue |= PHY_DUPLEX_STATUS;
\r
1235 if( ( ulControlStatus & PHYSPCS_SPEED_MASK ) == PHYSPCS_SPEED_10 )
\r
1237 ulRegValue |= PHY_SPEED_STATUS;
\r
1241 #elif( EXPECTED_PHY_ID == PHY_ID_DP83848I )
\r
1243 /* Read the result of the auto-negotiation. */
\r
1244 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_10_PHY_SR, &ulRegValue);
\r
1247 FreeRTOS_printf( ( ">> Autonego ready: %08lx: %s duplex %u mbit %s status\n",
\r
1249 (ulRegValue & PHY_DUPLEX_STATUS) ? "full" : "half",
\r
1250 (ulRegValue & PHY_SPEED_STATUS) ? 10 : 100,
\r
1251 ((ulPHYLinkStatus |= BMSR_LINK_STATUS) != 0) ? "high" : "low" ) );
\r
1253 /* Configure the MAC with the Duplex Mode fixed by the
\r
1254 auto-negotiation process. */
\r
1255 if( ( ulRegValue & PHY_DUPLEX_STATUS ) != ( uint32_t ) RESET )
\r
1257 /* Set Ethernet duplex mode to Full-duplex following the
\r
1258 auto-negotiation. */
\r
1259 xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
\r
1263 /* Set Ethernet duplex mode to Half-duplex following the
\r
1264 auto-negotiation. */
\r
1265 xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX;
\r
1268 /* Configure the MAC with the speed fixed by the
\r
1269 auto-negotiation process. */
\r
1270 if( ( ulRegValue & PHY_SPEED_STATUS) != 0 )
\r
1272 /* Set Ethernet speed to 10M following the
\r
1273 auto-negotiation. */
\r
1274 xETH.Init.Speed = ETH_SPEED_10M;
\r
1278 /* Set Ethernet speed to 100M following the
\r
1279 auto-negotiation. */
\r
1280 xETH.Init.Speed = ETH_SPEED_100M;
\r
1282 } /* if( ulTimeout < PHY_READ_TO ) */
\r
1284 else /* AutoNegotiation Disable */
\r
1288 /* Check parameters */
\r
1289 assert_param( IS_ETH_SPEED( xETH.Init.Speed ) );
\r
1290 assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) );
\r
1292 /* Set MAC Speed and Duplex Mode to PHY */
\r
1293 usValue = ( uint16_t ) ( xETH.Init.DuplexMode >> 3 ) | ( uint16_t ) ( xETH.Init.Speed >> 1 );
\r
1294 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, usValue );
\r
1297 /* ETHERNET MAC Re-Configuration */
\r
1298 HAL_ETH_ConfigMAC( &xETH, (ETH_MACInitTypeDef *) NULL);
\r
1300 /* Restart MAC interface */
\r
1301 HAL_ETH_Start( &xETH);
\r
1305 /* Stop MAC interface */
\r
1306 HAL_ETH_Stop( &xETH );
\r
1309 /*-----------------------------------------------------------*/
\r
1311 BaseType_t xGetPhyLinkStatus( void )
\r
1313 BaseType_t xReturn;
\r
1315 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
1326 /*-----------------------------------------------------------*/
\r
1328 static void prvEMACHandlerTask( void *pvParameters )
\r
1330 TimeOut_t xPhyTime;
\r
1331 TickType_t xPhyRemTime;
\r
1332 UBaseType_t uxLastMinBufferCount = 0;
\r
1333 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
1334 UBaseType_t uxLastMinQueueSpace = 0;
\r
1336 UBaseType_t uxCurrentCount;
\r
1337 BaseType_t xResult = 0;
\r
1339 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
\r
1341 /* Remove compiler warnings about unused parameters. */
\r
1342 ( void ) pvParameters;
\r
1344 vTaskSetTimeOutState( &xPhyTime );
\r
1345 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
1349 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
\r
1350 if( uxLastMinBufferCount != uxCurrentCount )
\r
1352 /* The logging produced below may be helpful
\r
1353 while tuning +TCP: see how many buffers are in use. */
\r
1354 uxLastMinBufferCount = uxCurrentCount;
\r
1355 FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
\r
1356 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
\r
1359 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
1360 if( xTXDescriptorSemaphore != NULL )
\r
1362 static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1;
\r
1364 uxCurrentCount = uxSemaphoreGetCount( xTXDescriptorSemaphore );
\r
1365 if( uxLowestSemCount > uxCurrentCount )
\r
1367 uxLowestSemCount = uxCurrentCount;
\r
1368 FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) );
\r
1373 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
1375 uxCurrentCount = uxGetMinimumIPQueueSpace();
\r
1376 if( uxLastMinQueueSpace != uxCurrentCount )
\r
1378 /* The logging produced below may be helpful
\r
1379 while tuning +TCP: see how many buffers are in use. */
\r
1380 uxLastMinQueueSpace = uxCurrentCount;
\r
1381 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
\r
1384 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
\r
1386 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
\r
1388 /* No events to process now, wait for the next. */
\r
1389 ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
\r
1392 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
\r
1394 ulISREvents &= ~EMAC_IF_RX_EVENT;
\r
1396 xResult = prvNetworkInterfaceInput();
\r
1399 while( prvNetworkInterfaceInput() > 0 )
\r
1405 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
\r
1407 /* Code to release TX buffers if zero-copy is used. */
\r
1408 ulISREvents &= ~EMAC_IF_TX_EVENT;
\r
1409 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
1411 /* Check if DMA packets have been delivered. */
\r
1412 vClearTXBuffers();
\r
1417 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
\r
1419 /* Future extension: logging about errors that occurred. */
\r
1420 ulISREvents &= ~EMAC_IF_ERR_EVENT;
\r
1425 /* A packet was received. No need to check for the PHY status now,
\r
1426 but set a timer to check it later on. */
\r
1427 vTaskSetTimeOutState( &xPhyTime );
\r
1428 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
1431 else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
\r
1433 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &xStatus );
\r
1434 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
\r
1436 ulPHYLinkStatus = xStatus;
\r
1437 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
\r
1438 prvEthernetUpdateConfig( pdFALSE );
\r
1441 vTaskSetTimeOutState( &xPhyTime );
\r
1442 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
1444 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
1448 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
1453 /*-----------------------------------------------------------*/
\r
1455 void ETH_IRQHandler( void )
\r
1457 HAL_ETH_IRQHandler( &xETH );
\r