diff options
Diffstat (limited to 'FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c')
-rw-r--r-- | FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c | 1061 |
1 files changed, 464 insertions, 597 deletions
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c index b9278c042..84019d637 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c @@ -44,26 +44,23 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "FreeRTOS_Sockets.h" #include "FreeRTOS_IP_Private.h" #include "FreeRTOS_DNS.h" +#include "FreeRTOS_ARP.h" #include "NetworkBufferManagement.h" #include "NetworkInterface.h" +#include "phyHandling.h" /* ST includes. */ -#include "stm32f4xx_hal.h" - -#ifndef BMSR_LINK_STATUS - #define BMSR_LINK_STATUS 0x0004UL -#endif - -#ifndef PHY_LS_HIGH_CHECK_TIME_MS - /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not - receiving packets. */ - #define PHY_LS_HIGH_CHECK_TIME_MS 15000 +#if defined( STM32F7xx ) + #include "stm32f7xx_hal.h" +#elif defined( STM32F4xx ) + #include "stm32f4xx_hal.h" +#elif defined( STM32F2xx ) + #include "stm32f2xx_hal.h" +#elif !defined( _lint ) /* Lint does not like an #error */ + #error What part? #endif -#ifndef PHY_LS_LOW_CHECK_TIME_MS - /* Check if the LinkSStatus in the PHY is still low every second. */ - #define PHY_LS_LOW_CHECK_TIME_MS 1000 -#endif +#include "stm32fxx_hal_eth.h" /* Interrupt events to process. Currently only the Rx event is processed although code for other events is included to allow for possible future @@ -78,77 +75,19 @@ expansion. */ ETH_DMA_IT_FBE | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \ ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T ) -/* Naming and numbering of PHY registers. */ -#define PHY_REG_00_BMCR 0x00 /* Basic Mode Control Register */ -#define PHY_REG_01_BMSR 0x01 /* Basic Mode Status Register */ -#define PHY_REG_02_PHYSID1 0x02 /* PHYS ID 1 */ -#define PHY_REG_03_PHYSID2 0x03 /* PHYS ID 2 */ -#define PHY_REG_04_ADVERTISE 0x04 /* Advertisement control reg */ - -#define PHY_ID_LAN8720 0x0007c0f0 -#define PHY_ID_DP83848I 0x20005C90 - -#ifndef USE_STM324xG_EVAL - #define USE_STM324xG_EVAL 1 +#ifndef niEMAC_HANDLER_TASK_PRIORITY + #define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 1 #endif -#if( USE_STM324xG_EVAL == 0 ) - #define EXPECTED_PHY_ID PHY_ID_LAN8720 - #define PHY_REG_1F_PHYSPCS 0x1F /* 31 RW PHY Special Control Status */ - /* Use 3 bits in register 31 */ - #define PHYSPCS_SPEED_MASK 0x0C - #define PHYSPCS_SPEED_10 0x04 - #define PHYSPCS_SPEED_100 0x08 - #define PHYSPCS_FULL_DUPLEX 0x10 -#else - #define EXPECTED_PHY_ID PHY_ID_DP83848I +#define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */ - #define PHY_REG_10_PHY_SR 0x10 /* PHY status register Offset */ - #define PHY_REG_19_PHYCR 0x19 /* 25 RW PHY Control Register */ +#if( ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) || ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) ) + #warning Consider enabling checksum offloading #endif -/* Some defines used internally here to indicate preferences about speed, MDIX -(wired direct or crossed), and duplex (half or full). */ -#define PHY_SPEED_10 1 -#define PHY_SPEED_100 2 -#define PHY_SPEED_AUTO (PHY_SPEED_10|PHY_SPEED_100) - -#define PHY_MDIX_DIRECT 1 -#define PHY_MDIX_CROSSED 2 -#define PHY_MDIX_AUTO (PHY_MDIX_CROSSED|PHY_MDIX_DIRECT) - -#define PHY_DUPLEX_HALF 1 -#define PHY_DUPLEX_FULL 2 -#define PHY_DUPLEX_AUTO (PHY_DUPLEX_FULL|PHY_DUPLEX_HALF) - -#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ - -/* - * Description of all capabilities that can be advertised to - * the peer (usually a switch or router). - */ -#define ADVERTISE_CSMA 0x0001 /* Only selector supported. */ -#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex. */ -#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex. */ -#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex. */ -#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex. */ - -#define ADVERTISE_ALL ( ADVERTISE_10HALF | ADVERTISE_10FULL | \ - ADVERTISE_100HALF | ADVERTISE_100FULL) - -/* - * Value for the 'PHY_REG_00_BMCR', the PHY's Basic Mode Control Register - */ -#define BMCR_FULLDPLX 0x0100 /* Full duplex. */ -#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart. */ -#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation. */ -#define BMCR_SPEED100 0x2000 /* Select 100Mbps. */ -#define BMCR_RESET 0x8000 /* Reset the PHY. */ - -#define PHYCR_MDIX_EN 0x8000 /* Enable Auto MDIX. */ -#define PHYCR_MDIX_FORCE 0x4000 /* Force MDIX crossed. */ - -#define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */ +#ifndef niDESCRIPTOR_WAIT_TIME_MS + #define niDESCRIPTOR_WAIT_TIME_MS 250uL +#endif /* * Most users will want a PHY that negotiates about @@ -191,6 +130,31 @@ FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */ #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE ) #endif +/* Two choices must be made: RMII versus MII, +and the index of the PHY in use ( between 0 and 31 ). */ +#ifndef ipconfigUSE_RMII + #ifdef STM32F7xx + #define ipconfigUSE_RMII 1 + #else + #define ipconfigUSE_RMII 0 + #endif /* STM32F7xx */ +#endif /* ipconfigUSE_RMII */ + +#if( ipconfigUSE_RMII != 0 ) + #warning Using RMII, make sure if this is correct +#else + #warning Using MII, make sure if this is correct +#endif + +typedef enum +{ + eMACInit, /* Must initialise MAC. */ + eMACPass, /* Initialisation was successful. */ + eMACFailed, /* Initialisation failed. */ +} eMAC_INIT_STATUS_TYPE; + +static eMAC_INIT_STATUS_TYPE xMacInitStatus = eMACInit; + /*-----------------------------------------------------------*/ /* @@ -231,43 +195,30 @@ static void prvDMATxDescListInit( void ); */ static void prvDMARxDescListInit( void ); -#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) - /* After packets have been sent, the network - buffers will be released. */ - static void vClearTXBuffers( void ); -#endif /* ipconfigZERO_COPY_TX_DRIVER */ +/* After packets have been sent, the network +buffers will be released. */ +static void vClearTXBuffers( void ); /*-----------------------------------------------------------*/ -typedef struct _PhyProperties_t -{ - uint8_t speed; - uint8_t mdix; - uint8_t duplex; - uint8_t spare; -} PhyProperties_t; - /* Bit map of outstanding ETH interrupt events for processing. Currently only the Rx interrupt is handled, although code is included for other events to enable future expansion. */ static volatile uint32_t ulISREvents; -/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */ -static uint32_t ulPHYLinkStatus = 0; - #if( ipconfigUSE_LLMNR == 1 ) static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC }; #endif +static EthernetPhy_t xPhyObject; + /* Ethernet handle. */ static ETH_HandleTypeDef xETH; -#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) - /* xTXDescriptorSemaphore is a counting semaphore with - a maximum count of ETH_TXBUFNB, which is the number of - DMA TX descriptors. */ - static SemaphoreHandle_t xTXDescriptorSemaphore = NULL; -#endif /* ipconfigZERO_COPY_TX_DRIVER */ +/* xTXDescriptorSemaphore is a counting semaphore with +a maximum count of ETH_TXBUFNB, which is the number of +DMA TX descriptors. */ +static SemaphoreHandle_t xTXDescriptorSemaphore = NULL; /* * Note: it is adviced to define both @@ -282,30 +233,39 @@ static ETH_HandleTypeDef xETH; * TX buffers are allocated in a zero-copy driver. */ /* MAC buffers: ---------------------------------------------------------*/ -__ALIGN_BEGIN ETH_DMADescTypeDef DMARxDscrTab[ ETH_RXBUFNB ] __ALIGN_END;/* Ethernet Rx MA Descriptor */ -#if( ipconfigZERO_COPY_RX_DRIVER == 0 ) - __ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END; /* Ethernet Receive Buffer */ -#endif -__ALIGN_BEGIN ETH_DMADescTypeDef DMATxDscrTab[ ETH_TXBUFNB ] __ALIGN_END;/* Ethernet Tx DMA Descriptor */ -#if( ipconfigZERO_COPY_TX_DRIVER == 0 ) - __ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END; /* Ethernet Transmit Buffer */ +/* Put the DMA descriptors in '.first_data'. +This is important for STM32F7, which has an L1 data cache. +The first 64KB of the SRAM is not cached. +See README.TXT in this folder. */ + +/* Ethernet Rx MA Descriptor */ +__attribute__ ((aligned (32))) +#if defined(STM32F7xx) + __attribute__ ((section(".first_data"))) #endif + ETH_DMADescTypeDef DMARxDscrTab[ ETH_RXBUFNB ]; -#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) - /* DMATxDescToClear points to the next TX DMA descriptor - that must be cleared by vClearTXBuffers(). */ - static __IO ETH_DMADescTypeDef *DMATxDescToClear; +#if( ipconfigZERO_COPY_RX_DRIVER == 0 ) + /* Ethernet Receive Buffer */ + __ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END; #endif -/* Value to be written into the 'Basic mode Control Register'. */ -static uint32_t ulBCRvalue; +/* Ethernet Tx DMA Descriptor */ +__attribute__ ((aligned (32))) +#if defined(STM32F7xx) + __attribute__ ((section(".first_data"))) +#endif + ETH_DMADescTypeDef DMATxDscrTab[ ETH_TXBUFNB ]; -/* Value to be written into the 'Advertisement Control Register'. */ -static uint32_t ulACRValue; +#if( ipconfigZERO_COPY_TX_DRIVER == 0 ) + /* Ethernet Transmit Buffer */ + __ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END; +#endif -/* ucMACAddress as it appears in main.c */ -extern const uint8_t ucMACAddress[ 6 ]; +/* DMATxDescToClear points to the next TX DMA descriptor +that must be cleared by vClearTXBuffers(). */ +static __IO ETH_DMADescTypeDef *DMATxDescToClear; /* Holds the handle of the task used as a deferred interrupt processor. The handle is used so direct notifications can be sent to the task for all EMAC/DMA @@ -316,28 +276,28 @@ static TaskHandle_t xEMACTaskHandle = NULL; const PhyProperties_t xPHYProperties = { #if( ipconfigETHERNET_AN_ENABLE != 0 ) - .speed = PHY_SPEED_AUTO, - .duplex = PHY_DUPLEX_AUTO, + .ucSpeed = PHY_SPEED_AUTO, + .ucDuplex = PHY_DUPLEX_AUTO, #else #if( ipconfigETHERNET_USE_100MB != 0 ) - .speed = PHY_SPEED_100, + .ucSpeed = PHY_SPEED_100, #else - .speed = PHY_SPEED_10, + .ucSpeed = PHY_SPEED_10, #endif #if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 ) - .duplex = PHY_DUPLEX_FULL, + .ucDuplex = PHY_DUPLEX_FULL, #else - .duplex = PHY_DUPLEX_HALF, + .ucDuplex = PHY_DUPLEX_HALF, #endif #endif #if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 ) - .mdix = PHY_MDIX_AUTO, + .ucMDI_X = PHY_MDIX_AUTO, #elif( ipconfigETHERNET_CROSSED_LINK != 0 ) - .mdix = PHY_MDIX_CROSSED, + .ucMDI_X = PHY_MDIX_CROSSED, #else - .mdix = PHY_MDIX_DIRECT, + .ucMDI_X = PHY_MDIX_DIRECT, #endif }; @@ -347,6 +307,8 @@ void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth ) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; + ( void ) heth; + /* Ethernet RX-Complete callback function, elsewhere declared as weak. */ ulISREvents |= EMAC_IF_RX_EVENT; /* Wakeup the prvEMACHandlerTask. */ @@ -358,46 +320,46 @@ BaseType_t xHigherPriorityTaskWoken = pdFALSE; } /*-----------------------------------------------------------*/ -#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) - void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth ) - { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - /* This call-back is only useful in case packets are being sent - zero-copy. Once they're sent, the buffers will be released - by the function vClearTXBuffers(). */ - ulISREvents |= EMAC_IF_TX_EVENT; - /* Wakeup the prvEMACHandlerTask. */ - if( xEMACTaskHandle != NULL ) - { - vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); - portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); - } +void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth ) +{ +BaseType_t xHigherPriorityTaskWoken = pdFALSE; - } -#endif /* ipconfigZERO_COPY_TX_DRIVER */ + ( void ) heth; + /* This call-back is only useful in case packets are being sent + zero-copy. Once they're sent, the buffers will be released + by the function vClearTXBuffers(). */ + ulISREvents |= EMAC_IF_TX_EVENT; + /* Wakeup the prvEMACHandlerTask. */ + if( xEMACTaskHandle != NULL ) + { + vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } +} /*-----------------------------------------------------------*/ +static void vClearTXBuffers() +{ +__IO ETH_DMADescTypeDef *txLastDescriptor = xETH.TxDesc; +size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore ); #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) - static void vClearTXBuffers() - { - __IO ETH_DMADescTypeDef *txLastDescriptor = xETH.TxDesc; NetworkBufferDescriptor_t *pxNetworkBuffer; uint8_t *ucPayLoad; - size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore ); +#endif - /* This function is called after a TX-completion interrupt. - It will release each Network Buffer used in xNetworkInterfaceOutput(). - 'uxCount' represents the number of descriptors given to DMA for transmission. - After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */ - while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) ) + /* This function is called after a TX-completion interrupt. + It will release each Network Buffer used in xNetworkInterfaceOutput(). + 'uxCount' represents the number of descriptors given to DMA for transmission. + After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */ + while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) ) + { + if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) ) + { + break; + } + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) { - if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) ) - { - break; - } - ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr; if( ucPayLoad != NULL ) @@ -409,15 +371,16 @@ BaseType_t xHigherPriorityTaskWoken = pdFALSE; } DMATxDescToClear->Buffer1Addr = ( uint32_t )0u; } + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ - DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr ); + DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr ); - uxCount--; - /* Tell the counting semaphore that one more TX descriptor is available. */ - xSemaphoreGive( xTXDescriptorSemaphore ); - } + uxCount--; + /* Tell the counting semaphore that one more TX descriptor is available. */ + xSemaphoreGive( xTXDescriptorSemaphore ); } -#endif /* ipconfigZERO_COPY_TX_DRIVER */ +} /*-----------------------------------------------------------*/ BaseType_t xNetworkInterfaceInitialise( void ) @@ -425,90 +388,117 @@ BaseType_t xNetworkInterfaceInitialise( void ) HAL_StatusTypeDef hal_eth_init_status; BaseType_t xResult; - if( xEMACTaskHandle == NULL ) + if( xMacInitStatus == eMACInit ) { - #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB ); + if( xTXDescriptorSemaphore == NULL ) { - if( xTXDescriptorSemaphore == NULL ) - { - xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB ); - configASSERT( xTXDescriptorSemaphore ); - } + xMacInitStatus = eMACFailed; } - #endif /* ipconfigZERO_COPY_TX_DRIVER */ + else + { + /* Initialise ETH */ - /* Initialise ETH */ + xETH.Instance = ETH; + xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE; + xETH.Init.Speed = ETH_SPEED_100M; + xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; + /* Value of PhyAddress doesn't matter, will be probed for. */ + xETH.Init.PhyAddress = 0; - xETH.Instance = ETH; - xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE; - xETH.Init.Speed = ETH_SPEED_100M; - xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; - xETH.Init.PhyAddress = 1; + xETH.Init.MACAddr = ( uint8_t * ) FreeRTOS_GetMACAddress(); + xETH.Init.RxMode = ETH_RXINTERRUPT_MODE; - xETH.Init.MACAddr = ( uint8_t *) ucMACAddress; - xETH.Init.RxMode = ETH_RXINTERRUPT_MODE; + #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) + { + /* using the ETH_CHECKSUM_BY_HARDWARE option: + both the IP and the protocol checksums will be calculated + by the peripheral. */ + xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE; + } + #else + { + xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_SOFTWARE; + } + #endif - /* using the ETH_CHECKSUM_BY_HARDWARE option: - both the IP and the protocol checksums will be calculated - by the peripheral. */ - xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE; + #if( ipconfigUSE_RMII != 0 ) + { + xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII; + } + #else + { + xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII; + } + #endif /* ipconfigUSE_RMII */ - xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII; - hal_eth_init_status = HAL_ETH_Init( &xETH ); + hal_eth_init_status = HAL_ETH_Init( &xETH ); - /* Only for inspection by debugger. */ - ( void ) hal_eth_init_status; + /* Only for inspection by debugger. */ + ( void ) hal_eth_init_status; - /* Set the TxDesc and RxDesc pointers. */ - xETH.TxDesc = DMATxDscrTab; - xETH.RxDesc = DMARxDscrTab; + /* Set the TxDesc and RxDesc pointers. */ + xETH.TxDesc = DMATxDscrTab; + xETH.RxDesc = DMARxDscrTab; - /* Make sure that all unused fields are cleared. */ - memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) ); - memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) ); + /* Make sure that all unused fields are cleared. */ + memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) ); + memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) ); - #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) - { /* Initialize Tx Descriptors list: Chain Mode */ DMATxDescToClear = DMATxDscrTab; - } - #endif /* ipconfigZERO_COPY_TX_DRIVER */ - /* Initialise TX-descriptors. */ - prvDMATxDescListInit(); + /* Initialise TX-descriptors. */ + prvDMATxDescListInit(); - /* Initialise RX-descriptors. */ - prvDMARxDescListInit(); + /* Initialise RX-descriptors. */ + prvDMARxDescListInit(); - #if( ipconfigUSE_LLMNR != 0 ) - { - /* Program the LLMNR address at index 1. */ - prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress ); - } - #endif + #if( ipconfigUSE_LLMNR != 0 ) + { + /* Program the LLMNR address at index 1. */ + prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress ); + } + #endif - /* Force a negotiation with the Switch or Router and wait for LS. */ - prvEthernetUpdateConfig( pdTRUE ); + /* Force a negotiation with the Switch or Router and wait for LS. */ + prvEthernetUpdateConfig( pdTRUE ); - /* The deferred interrupt handler task is created at the highest - possible priority to ensure the interrupt handler can return directly - to it. The task's handle is stored in xEMACTaskHandle so interrupts can - notify the task when there is something to process. */ - xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle ); + /* The deferred interrupt handler task is created at the highest + possible priority to ensure the interrupt handler can return directly + to it. The task's handle is stored in xEMACTaskHandle so interrupts can + notify the task when there is something to process. */ + if( xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle ) == pdPASS ) + { + /* The xTXDescriptorSemaphore and the task are created successfully. */ + xMacInitStatus = eMACPass; + } + else + { + xMacInitStatus = eMACFailed; + } + } } /* if( xEMACTaskHandle == NULL ) */ - if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) + if( xMacInitStatus != eMACPass ) { - xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS; - xResult = pdPASS; - FreeRTOS_printf( ( "Link Status is high\n" ) ) ; + /* EMAC initialisation failed, return pdFAIL. */ + xResult = pdFAIL; } else { - /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running - and it will keep on checking the PHY and set ulPHYLinkStatus when necessary. */ - xResult = pdFAIL; - FreeRTOS_printf( ( "Link Status still low\n" ) ) ; + if( xPhyObject.ulLinkStatusMask != 0uL ) + { + xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS; + xResult = pdPASS; + FreeRTOS_printf( ( "Link Status is high\n" ) ) ; + } + else + { + /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running + and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */ + xResult = pdFAIL; + } } /* When returning non-zero, the stack will become active and start DHCP (in configured) */ @@ -542,6 +532,10 @@ BaseType_t xIndex; /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */ pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL; } + else + { + pxDMADescriptor->Status &= ~( ( uint32_t ) ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL ); + } /* Initialize the next descriptor with the Next Descriptor Polling Enable */ if( xIndex < ETH_TXBUFNB - 1 ) @@ -625,6 +619,8 @@ static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8 { uint32_t ulTempReg; + ( void ) heth; + /* Calculate the selected MAC address high register. */ ulTempReg = 0x80000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ]; @@ -647,46 +643,38 @@ __IO ETH_DMADescTypeDef *pxDmaTxDesc; /* Do not wait too long for a free TX DMA buffer. */ const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u ); - #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) + /* Open a do {} while ( 0 ) loop to be able to call break. */ + do { - ProtocolPacket_t *pxPacket; + #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) + { + ProtocolPacket_t *pxPacket; - /* If the peripheral must calculate the checksum, it wants - the protocol checksum to have a value of zero. */ - pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer ); + /* If the peripheral must calculate the checksum, it wants + the protocol checksum to have a value of zero. */ + pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer ); - if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP ) - { - pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u; + if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) + { + pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u; + } } - } - #endif - - /* Open a do {} while ( 0 ) loop to be able to call break. */ - do - { - if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) + #endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */ + if( xPhyObject.ulLinkStatusMask != 0 ) { - #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS ) { - if( xTXDescriptorSemaphore == NULL ) - { - break; - } - if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS ) - { - /* Time-out waiting for a free TX descriptor. */ - break; - } + /* Time-out waiting for a free TX descriptor. */ + break; } - #endif /* ipconfigZERO_COPY_TX_DRIVER */ /* This function does the actual transmission of the packet. The packet is contained in 'pxDescriptor' that is passed to the function. */ pxDmaTxDesc = xETH.TxDesc; /* Is this buffer available? */ - if( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 ) + configASSERT ( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 ); + { /* Is this buffer available? */ /* Get bytes in current buffer. */ @@ -701,32 +689,54 @@ const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u ); { /* Copy the bytes. */ memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize ); - pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL; } #else { + configASSERT( bReleaseAfterSend != 0 ); + /* Move the buffer. */ pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer; - /* Ask to set the IPv4 checksum. - Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */ - pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC; /* The Network Buffer has been passed to DMA, no need to release it. */ bReleaseAfterSend = pdFALSE_UNSIGNED; } #endif /* ipconfigZERO_COPY_TX_DRIVER */ + /* Ask to set the IPv4 checksum. + Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */ + #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) + { + pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC; + } + #else + { + pxDmaTxDesc->Status &= ~( ( uint32_t ) ETH_DMATXDESC_CIC ); + pxDmaTxDesc->Status |= ETH_DMATXDESC_IC; + } + #endif + + /* Prepare transmit descriptors to give to DMA. */ /* Set LAST and FIRST segment */ pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS; /* Set frame size */ pxDmaTxDesc->ControlBufferSize = ( ulTransmitSize & ETH_DMATXDESC_TBS1 ); + + #if( NETWORK_BUFFERS_CACHED != 0 ) + { + BaseType_t xlength = CACHE_LINE_SIZE * ( ( ulTransmitSize + NETWORK_BUFFER_HEADER_SIZE + CACHE_LINE_SIZE - 1 ) / CACHE_LINE_SIZE ); + uint32_t *pulBuffer = ( uint32_t )( pxDescriptor->pucEthernetBuffer - NETWORK_BUFFER_HEADER_SIZE ); + cache_clean_invalidate_by_addr( pulBuffer, xlength ); + } + #endif + /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN; /* Point to next descriptor */ xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr ); - + /* Ensure completion of memory access */ + __DSB(); /* Resume DMA transmission*/ xETH.Instance->DMATPDR = 0; iptraceNETWORK_INTERFACE_TRANSMIT(); @@ -801,20 +811,24 @@ const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer; if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP ) { - uint16_t port = pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort; + uint16_t usSourcePort = FreeRTOS_ntohs( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort ); + uint16_t usDestinationPort = FreeRTOS_ntohs( pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort ); - if( ( xPortHasUDPSocket( port ) == pdFALSE ) + if( ( xPortHasUDPSocket( pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort ) == pdFALSE ) #if ipconfigUSE_LLMNR == 1 - && ( port != FreeRTOS_ntohs( ipLLMNR_PORT ) ) + && ( usDestinationPort != ipLLMNR_PORT ) + && ( usSourcePort != ipLLMNR_PORT ) #endif #if ipconfigUSE_NBNS == 1 - && ( port != FreeRTOS_ntohs( ipNBNS_PORT ) ) + && ( usDestinationPort != ipNBNS_PORT ) + && ( usSourcePort != ipNBNS_PORT ) #endif #if ipconfigUSE_DNS == 1 - && ( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort != FreeRTOS_ntohs( ipDNS_PORT ) ) + && ( usSourcePort != ipDNS_PORT ) #endif ) { /* Drop this packet, not for this device. */ + FreeRTOS_printf( ( "Drop: UDP port %d -> %d\n", usSourcePort, usDestinationPort ) ); return pdFALSE; } } @@ -824,20 +838,59 @@ const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer; } /*-----------------------------------------------------------*/ +static void prvPassEthMessages( NetworkBufferDescriptor_t *pxDescriptor ) +{ +IPStackEvent_t xRxEvent; + + xRxEvent.eEventType = eNetworkRxEvent; + xRxEvent.pvData = ( void * ) pxDescriptor; + + if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS ) + { + /* The buffer could not be sent to the stack so must be released again. + This is a deferred handler taskr, not a real interrupt, so it is ok to + use the task level function here. */ + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + { + do + { + NetworkBufferDescriptor_t *pxNext = pxDescriptor->pxNextBuffer; + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + pxDescriptor = pxNext; + } while( pxDescriptor != NULL ); + } + #else + { + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + iptraceETHERNET_RX_EVENT_LOST(); + FreeRTOS_printf( ( "prvPassEthMessages: Can not queue return packet!\n" ) ); + } + else + { + iptraceNETWORK_INTERFACE_RECEIVE(); + } +} + static BaseType_t prvNetworkInterfaceInput( void ) { NetworkBufferDescriptor_t *pxCurDescriptor; NetworkBufferDescriptor_t *pxNewDescriptor = NULL; -BaseType_t xReceivedLength, xAccepted; +#if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + NetworkBufferDescriptor_t *pxFirstDescriptor = NULL; + NetworkBufferDescriptor_t *pxLastDescriptor = NULL; +#endif +BaseType_t xReceivedLength = 0; __IO ETH_DMADescTypeDef *pxDMARxDescriptor; -xIPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; -const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 ); +const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( niDESCRIPTOR_WAIT_TIME_MS ); uint8_t *pucBuffer; pxDMARxDescriptor = xETH.RxDesc; - if( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN) == 0 ) + while( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN ) == 0u ) { + BaseType_t xAccepted = pdTRUE; /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */ xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4; @@ -847,18 +900,13 @@ uint8_t *pucBuffer; /* Chained Mode */ /* Selects the next DMA Rx descriptor list for next buffer to read */ xETH.RxDesc = ( ETH_DMADescTypeDef* )pxDMARxDescriptor->Buffer2NextDescAddr; - } - else - { - xReceivedLength = 0; - } - /* Obtain the size of the packet and put it into the "usReceivedLength" variable. */ - /* In order to make the code easier and faster, only packets in a single buffer - will be accepted. This can be done by making the buffers large enough to - hold a complete Ethernet packet (1536 bytes). */ - if( xReceivedLength > 0ul && xReceivedLength < ETH_RX_BUF_SIZE ) - { + /* In order to make the code easier and faster, only packets in a single buffer + will be accepted. This can be done by making the buffers large enough to + hold a complete Ethernet packet (1536 bytes). + Therefore, two sanity checks: */ + configASSERT( xReceivedLength <= ETH_RX_BUF_SIZE ); + if( ( pxDMARxDescriptor->Status & ( ETH_DMARXDESC_CE | ETH_DMARXDESC_IPV4HCE | ETH_DMARXDESC_FT ) ) != ETH_DMARXDESC_FT ) { /* Not an Ethernet frame-type or a checmsum error. */ @@ -904,20 +952,28 @@ uint8_t *pucBuffer; if( xAccepted != pdFALSE ) { pxCurDescriptor->xDataLength = xReceivedLength; - xRxEvent.pvData = ( void * ) pxCurDescriptor; - - /* Pass the data to the TCP/IP task for processing. */ - if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE ) + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) { - /* Could not send the descriptor into the TCP/IP stack, it - must be released. */ - vReleaseNetworkBufferAndDescriptor( pxCurDescriptor ); - iptraceETHERNET_RX_EVENT_LOST(); + pxCurDescriptor->pxNextBuffer = NULL; + + if( pxFirstDescriptor == NULL ) + { + // Becomes the first message + pxFirstDescriptor = pxCurDescriptor; + } + else if( pxLastDescriptor != NULL ) + { + // Add to the tail + pxLastDescriptor->pxNextBuffer = pxCurDescriptor; + } + + pxLastDescriptor = pxCurDescriptor; } - else + #else { - iptraceNETWORK_INTERFACE_RECEIVE(); + prvPassEthMessages( pxCurDescriptor ); } + #endif } /* Release descriptors to DMA */ @@ -940,6 +996,8 @@ uint8_t *pucBuffer; pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE; pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN; + /* Ensure completion of memory access */ + __DSB(); /* When Rx Buffer unavailable flag is set clear it and resume reception. */ if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 ) @@ -950,311 +1008,138 @@ uint8_t *pucBuffer; /* Resume DMA reception. */ xETH.Instance->DMARPDR = 0; } + pxDMARxDescriptor = xETH.RxDesc; } - return ( xReceivedLength > 0 ); -} -/*-----------------------------------------------------------*/ - -void vMACBProbePhy( void ) -{ -uint32_t ulConfig, ulAdvertise, ulLower, ulUpper, ulMACPhyID, ulValue; -TimeOut_t xPhyTime; -TickType_t xRemTime = 0; -#if( EXPECTED_PHY_ID == PHY_ID_DP83848I ) - uint32_t ulPhyControl; -#endif - - HAL_ETH_ReadPHYRegister(&xETH, PHY_REG_03_PHYSID2, &ulLower); - HAL_ETH_ReadPHYRegister(&xETH, PHY_REG_02_PHYSID1, &ulUpper); - - ulMACPhyID = ( ( ulUpper << 16 ) & 0xFFFF0000 ) | ( ulLower & 0xFFF0 ); - - /* The expected ID for the 'LAN8720' is 0x0007c0f0. */ - /* The expected ID for the 'DP83848I' is 0x20005C90. */ - - FreeRTOS_printf( ( "PHY ID %lX (%s)\n", ulMACPhyID, - ( ulMACPhyID == EXPECTED_PHY_ID ) ? "OK" : "Unknown" ) ); - - /* Remove compiler warning if FreeRTOS_printf() is not defined. */ - ( void ) ulMACPhyID; - - /* Set advertise register. */ - if( ( xPHYProperties.speed == PHY_SPEED_AUTO ) && ( xPHYProperties.duplex == PHY_DUPLEX_AUTO ) ) + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) { - ulAdvertise = ADVERTISE_CSMA | ADVERTISE_ALL; - /* Reset auto-negotiation capability. */ - } - else - { - ulAdvertise = ADVERTISE_CSMA; - - if( xPHYProperties.speed == PHY_SPEED_AUTO ) - { - if( xPHYProperties.duplex == PHY_DUPLEX_FULL ) - { - ulAdvertise |= ADVERTISE_10FULL | ADVERTISE_100FULL; - } - else - { - ulAdvertise |= ADVERTISE_10HALF | ADVERTISE_100HALF; - } - } - else if( xPHYProperties.duplex == PHY_DUPLEX_AUTO ) + if( pxFirstDescriptor != NULL ) { - if( xPHYProperties.speed == PHY_SPEED_10 ) - { - ulAdvertise |= ADVERTISE_10FULL | ADVERTISE_10HALF; - } - else - { - ulAdvertise |= ADVERTISE_100FULL | ADVERTISE_100HALF; - } - } - else if( xPHYProperties.speed == PHY_SPEED_100 ) - { - if( xPHYProperties.duplex == PHY_DUPLEX_FULL ) - { - ulAdvertise |= ADVERTISE_100FULL; - } - else - { - ulAdvertise |= ADVERTISE_100HALF; - } - } - else - { - if( xPHYProperties.duplex == PHY_DUPLEX_FULL ) - { - ulAdvertise |= ADVERTISE_10FULL; - } - else - { - ulAdvertise |= ADVERTISE_10HALF; - } + prvPassEthMessages( pxFirstDescriptor ); } } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ - /* Read Control register. */ - HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulConfig ); - - HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulConfig | BMCR_RESET ); - xRemTime = ( TickType_t ) pdMS_TO_TICKS( 1000UL ); - vTaskSetTimeOutState( &xPhyTime ); + return ( xReceivedLength > 0 ); +} +/*-----------------------------------------------------------*/ - for( ; ; ) - { - HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulValue ); - if( ( ulValue & BMCR_RESET ) == 0 ) - { - FreeRTOS_printf( ( "BMCR_RESET ready\n" ) ); - break; - } - if( xTaskCheckForTimeOut( &xPhyTime, &xRemTime ) != pdFALSE ) - { - FreeRTOS_printf( ( "BMCR_RESET timed out\n" ) ); - break; - } - } - HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulConfig & ~BMCR_RESET ); - vTaskDelay( pdMS_TO_TICKS( 50ul ) ); +BaseType_t xSTM32_PhyRead( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue ) +{ +uint16_t usPrevAddress = xETH.Init.PhyAddress; +BaseType_t xResult; +HAL_StatusTypeDef xHALResult; - /* Write advertise register. */ - HAL_ETH_WritePHYRegister( &xETH, PHY_REG_04_ADVERTISE, ulAdvertise ); + xETH.Init.PhyAddress = xAddress; + xHALResult = HAL_ETH_ReadPHYRegister( &xETH, ( uint16_t )xRegister, pulValue ); + xETH.Init.PhyAddress = usPrevAddress; - /* - AN_EN AN1 AN0 Forced Mode - 0 0 0 10BASE-T, Half-Duplex - 0 0 1 10BASE-T, Full-Duplex - 0 1 0 100BASE-TX, Half-Duplex - 0 1 1 100BASE-TX, Full-Duplex - AN_EN AN1 AN0 Advertised Mode - 1 0 0 10BASE-T, Half/Full-Duplex - 1 0 1 100BASE-TX, Half/Full-Duplex - 1 1 0 10BASE-T Half-Duplex - 100BASE-TX, Half-Duplex - 1 1 1 10BASE-T, Half/Full-Duplex - 100BASE-TX, Half/Full-Duplex - */ - - /* Read Control register. */ - HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulConfig ); - - ulConfig &= ~( BMCR_ANRESTART | BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX ); - - /* HT 12/9/14: always set AN-restart and AN-enable, even though the choices - are limited. */ - ulConfig |= (BMCR_ANRESTART | BMCR_ANENABLE); - - if( xPHYProperties.speed == PHY_SPEED_100 ) + if( xHALResult == HAL_OK ) { - ulConfig |= BMCR_SPEED100; + xResult = 0; } - else if( xPHYProperties.speed == PHY_SPEED_10 ) + else { - ulConfig &= ~BMCR_SPEED100; + xResult = -1; } + return xResult; +} +/*-----------------------------------------------------------*/ - if( xPHYProperties.duplex == PHY_DUPLEX_FULL ) - { - ulConfig |= BMCR_FULLDPLX; - } - else if( xPHYProperties.duplex == PHY_DUPLEX_HALF ) - { - ulConfig &= ~BMCR_FULLDPLX; - } +BaseType_t xSTM32_PhyWrite( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue ) +{ +uint16_t usPrevAddress = xETH.Init.PhyAddress; +BaseType_t xResult; +HAL_StatusTypeDef xHALResult; + + xETH.Init.PhyAddress = xAddress; + xHALResult = HAL_ETH_WritePHYRegister( &xETH, ( uint16_t )xRegister, ulValue ); + xETH.Init.PhyAddress = usPrevAddress; - #if( EXPECTED_PHY_ID == PHY_ID_LAN8720 ) + if( xHALResult == HAL_OK ) { + xResult = 0; } - #elif( EXPECTED_PHY_ID == PHY_ID_DP83848I ) + else { - /* Read PHY Control register. */ - HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_19_PHYCR, &ulPhyControl ); - - /* Clear bits which might get set: */ - ulPhyControl &= ~( PHYCR_MDIX_EN|PHYCR_MDIX_FORCE ); - - if( xPHYProperties.mdix == PHY_MDIX_AUTO ) - { - ulPhyControl |= PHYCR_MDIX_EN; - } - else if( xPHYProperties.mdix == PHY_MDIX_CROSSED ) - { - /* Force direct link = Use crossed RJ45 cable. */ - ulPhyControl &= ~PHYCR_MDIX_FORCE; - } - else - { - /* Force crossed link = Use direct RJ45 cable. */ - ulPhyControl |= PHYCR_MDIX_FORCE; - } - /* update PHY Control Register. */ - HAL_ETH_WritePHYRegister( &xETH, PHY_REG_19_PHYCR, ulPhyControl ); + xResult = -1; } - #endif - FreeRTOS_printf( ( "+TCP: advertise: %lX config %lX\n", ulAdvertise, ulConfig ) ); + return xResult; +} +/*-----------------------------------------------------------*/ - /* Now the two values to global values for later use. */ - ulBCRvalue = ulConfig; - ulACRValue = ulAdvertise; +void vMACBProbePhy( void ) +{ + vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite ); + xPhyDiscover( &xPhyObject ); + xPhyConfigure( &xPhyObject, &xPHYProperties ); } /*-----------------------------------------------------------*/ static void prvEthernetUpdateConfig( BaseType_t xForce ) { -__IO uint32_t ulTimeout = 0; -uint32_t ulRegValue = 0; - - FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS %d Force %d\n", - ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 , - xForce ) ); + FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02lX Force %d\n", + xPhyObject.ulLinkStatusMask, + ( int )xForce ) ); - if( ( xForce != pdFALSE ) || ( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) ) + if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) ) { /* Restart the auto-negotiation. */ if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE ) { - /* Enable Auto-Negotiation. */ - HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulBCRvalue | BMCR_ANRESTART ); - HAL_ETH_WritePHYRegister( &xETH, PHY_REG_04_ADVERTISE, ulACRValue); + xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) ); - /* Wait until the auto-negotiation will be completed */ - do + /* Configure the MAC with the Duplex Mode fixed by the + auto-negotiation process. */ + if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL ) { - ulTimeout++; - HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &ulRegValue ); - } while( ( ( ulRegValue & PHY_AUTONEGO_COMPLETE) == 0 ) && ( ulTimeout < PHY_READ_TO ) ); - - HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulBCRvalue & ~BMCR_ANRESTART ); - - if( ulTimeout < PHY_READ_TO ) + xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; + } + else { - /* Reset Timeout counter. */ - ulTimeout = 0; - - HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &ulRegValue); - if( ( ulRegValue & BMSR_LINK_STATUS ) != 0 ) - { - ulPHYLinkStatus |= BMSR_LINK_STATUS; - } - else - { - ulPHYLinkStatus &= ~( BMSR_LINK_STATUS ); - } - - #if( EXPECTED_PHY_ID == PHY_ID_LAN8720 ) - { - /* 31 RW PHY Special Control Status */ - uint32_t ulControlStatus; - - HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_1F_PHYSPCS, &ulControlStatus); - ulRegValue = 0; - if( ( ulControlStatus & PHYSPCS_FULL_DUPLEX ) != 0 ) - { - ulRegValue |= PHY_DUPLEX_STATUS; - } - if( ( ulControlStatus & PHYSPCS_SPEED_MASK ) == PHYSPCS_SPEED_10 ) - { - ulRegValue |= PHY_SPEED_STATUS; - } - - } - #elif( EXPECTED_PHY_ID == PHY_ID_DP83848I ) - { - /* Read the result of the auto-negotiation. */ - HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_10_PHY_SR, &ulRegValue); - } - #endif - FreeRTOS_printf( ( ">> Autonego ready: %08lx: %s duplex %u mbit %s status\n", - ulRegValue, - (ulRegValue & PHY_DUPLEX_STATUS) ? "full" : "half", - (ulRegValue & PHY_SPEED_STATUS) ? 10 : 100, - ((ulPHYLinkStatus |= BMSR_LINK_STATUS) != 0) ? "high" : "low" ) ); - - /* Configure the MAC with the Duplex Mode fixed by the - auto-negotiation process. */ - if( ( ulRegValue & PHY_DUPLEX_STATUS ) != ( uint32_t ) RESET ) - { - /* Set Ethernet duplex mode to Full-duplex following the - auto-negotiation. */ - xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; - } - else - { - /* Set Ethernet duplex mode to Half-duplex following the - auto-negotiation. */ - xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX; - } + xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX; + } - /* Configure the MAC with the speed fixed by the - auto-negotiation process. */ - if( ( ulRegValue & PHY_SPEED_STATUS) != 0 ) - { - /* Set Ethernet speed to 10M following the - auto-negotiation. */ - xETH.Init.Speed = ETH_SPEED_10M; - } - else - { - /* Set Ethernet speed to 100M following the - auto-negotiation. */ - xETH.Init.Speed = ETH_SPEED_100M; - } - } /* if( ulTimeout < PHY_READ_TO ) */ + /* Configure the MAC with the speed fixed by the + auto-negotiation process. */ + if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 ) + { + xETH.Init.Speed = ETH_SPEED_10M; + } + else + { + xETH.Init.Speed = ETH_SPEED_100M; + } } else /* AutoNegotiation Disable */ { - uint16_t usValue; - /* Check parameters */ assert_param( IS_ETH_SPEED( xETH.Init.Speed ) ); assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) ); - /* Set MAC Speed and Duplex Mode to PHY */ - usValue = ( uint16_t ) ( xETH.Init.DuplexMode >> 3 ) | ( uint16_t ) ( xETH.Init.Speed >> 1 ); - HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, usValue ); + if( xETH.Init.DuplexMode == ETH_MODE_FULLDUPLEX ) + { + xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_HALF; + } + else + { + xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_FULL; + } + + if( xETH.Init.Speed == ETH_SPEED_10M ) + { + xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_10; + } + else + { + xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_100; + } + + xPhyObject.xPhyPreferences.ucMDI_X = PHY_MDIX_AUTO; + + /* Use predefined (fixed) configuration. */ + xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) ); } /* ETHERNET MAC Re-Configuration */ @@ -1275,7 +1160,7 @@ BaseType_t xGetPhyLinkStatus( void ) { BaseType_t xReturn; - if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) + if( xPhyObject.ulLinkStatusMask != 0 ) { xReturn = pdPASS; } @@ -1288,27 +1173,43 @@ BaseType_t xReturn; } /*-----------------------------------------------------------*/ +/* Uncomment this in case BufferAllocation_1.c is used. */ + +void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) +{ +static +#if defined(STM32F7xx) + __attribute__ ((section(".first_data"))) +#endif + uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * ETH_MAX_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) ); +uint8_t *ucRAMBuffer = ucNetworkPackets; +uint32_t ul; + + for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ ) + { + pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING; + *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) ); + ucRAMBuffer += ETH_MAX_PACKET_SIZE; + } +} +/*-----------------------------------------------------------*/ + static void prvEMACHandlerTask( void *pvParameters ) { -TimeOut_t xPhyTime; -TickType_t xPhyRemTime; UBaseType_t uxLastMinBufferCount = 0; #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) UBaseType_t uxLastMinQueueSpace = 0; #endif UBaseType_t uxCurrentCount; -BaseType_t xResult = 0; -uint32_t xStatus; +BaseType_t xResult; const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); /* Remove compiler warnings about unused parameters. */ ( void ) pvParameters; - vTaskSetTimeOutState( &xPhyTime ); - xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS ); - for( ;; ) { + xResult = 0; uxCurrentCount = uxGetMinimumFreeNetworkBuffers(); if( uxLastMinBufferCount != uxCurrentCount ) { @@ -1319,7 +1220,6 @@ const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) ); } - #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) if( xTXDescriptorSemaphore != NULL ) { static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1; @@ -1332,7 +1232,7 @@ const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); } } - #endif + #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) { uxCurrentCount = uxGetMinimumIPQueueSpace(); @@ -1357,24 +1257,14 @@ const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); ulISREvents &= ~EMAC_IF_RX_EVENT; xResult = prvNetworkInterfaceInput(); - if( xResult > 0 ) - { - while( prvNetworkInterfaceInput() > 0 ) - { - } - } } if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 ) { /* Code to release TX buffers if zero-copy is used. */ ulISREvents &= ~EMAC_IF_TX_EVENT; - #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) - { - /* Check if DMA packets have been delivered. */ - vClearTXBuffers(); - } - #endif + /* Check if DMA packets have been delivered. */ + vClearTXBuffers(); } if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 ) @@ -1382,34 +1272,10 @@ const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); /* Future extension: logging about errors that occurred. */ ulISREvents &= ~EMAC_IF_ERR_EVENT; } - - if( xResult > 0 ) + if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 ) { - /* A packet was received. No need to check for the PHY status now, - but set a timer to check it later on. */ - vTaskSetTimeOutState( &xPhyTime ); - xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS ); - xResult = 0; - } - else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) - { - HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &xStatus ); - if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) ) - { - ulPHYLinkStatus = xStatus; - FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) ); - prvEthernetUpdateConfig( pdFALSE ); - } - - vTaskSetTimeOutState( &xPhyTime ); - if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) - { - xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS ); - } - else - { - xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS ); - } + /* Something has changed to a Link Status, need re-check. */ + prvEthernetUpdateConfig( pdFALSE ); } } } @@ -1419,3 +1285,4 @@ void ETH_IRQHandler( void ) { HAL_ETH_IRQHandler( &xETH ); } + |