summaryrefslogtreecommitdiff
path: root/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx')
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c1061
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/readme.txt81
2 files changed, 545 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 );
}
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/readme.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/readme.txt
new file mode 100644
index 000000000..1d244bae7
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/readme.txt
@@ -0,0 +1,81 @@
+This is a FreeeRTOS+TCP driver that works for both STM32F4xx and STM32F7xx parts.
+
+The code of stm32fxx_hal_eth.c is based on both drivers as provided by ST.
+
+These modules should be included:
+
+ NetworkInterface.c
+ stm32fxx_hal_eth.c
+
+It is assumed that one of these words are defined:
+
+ STM32F7xx
+ STM32F407xx
+ STM32F417xx
+ STM32F427xx
+ STM32F437xx
+ STM32F429xx
+ STM32F439xx
+
+The driver has been tested on both Eval and Discovery boards with both STM32F4 and STM32F7.
+
+Recommended settings for STM32Fxx Network Interface:
+
+// Defined in FreeRTOSIPConfig.h
+
+#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1
+#define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 1
+#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1
+#define ipconfigZERO_COPY_RX_DRIVER 1
+#define ipconfigZERO_COPY_TX_DRIVER 1
+#define ipconfigUSE_LINKED_RX_MESSAGES 1
+
+// Defined in stm32f4xx_hal_conf.h
+#define ETH_RXBUFNB 3 or 4
+#define ETH_TXBUFNB 2 or 3
+#define ETH_RX_BUF_SIZE ( ipconfigNETWORK_MTU + 36 )
+#define ETH_TX_BUF_SIZE ( ipconfigNETWORK_MTU + 36 )
+
+The best size for 'ETH_RXBUFNB' and 'ETH_TXBUFNB' depends on the speed of the CPU. These macro's define the number of DMA buffers for reception and for transmission.
+In general, if the CPU is very fast, you will need less buffers. You can obtain an estimate empirically.
+
+The optimal value of 'ETH_RX_BUF_SIZE' and 'ETH_TX_BUF_SIZE' depends on the actual value of 'ipconfigNETWORK_MTU'.
+When MTU is 1500, MTU+36 becomes a well-aligned buffer of 1536 bytes ( 0x600 ).
+When MTU is 1200, MTU+48 will make 1248 ( 0x4E0 ), which is also well aligned.
+
+Having well aligned buffers is important for CPU with memory cache. Often the caching system divides memory in blocks of 32 bytes. When two buffers share the same cache buffer, you are bound to see data errors.
+
+Without memory caching, let the size be at least a multiple of 8 ( for DMA ), and make it at least "ipconfigNETWORK_MTU + 14".
+
+STM32F7xx only:
+
+Networkinterface.c will place the 2 DMA tables in a special section called 'first_data'.
+In case 'BufferAllocation_1.c' is used, the network packets will also be declared in this section 'first_data'.
+As long as the part has no caching, this section can be placed anywhere in RAM.
+On an STM32F7 with an L1 data cache, it shall be placed in the first 64KB of RAM, which is always uncached.
+The linker script must be changed for this, for instance as follows:
+
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; // create a global symbol at data start
++ *(.first_data) // .first_data sections
+ *(.data) // .data sections
+ *(.data*) // .data* sections
+
+ . = ALIGN(4);
+ _edata = .; // define a global symbol at data end
+ } >RAM AT> FLASH
+
+
+The driver contains these files:
+
+ stm32fxx_hal_eth.c
+ stm32f2xx_hal_eth.h
+ stm32f4xx_hal_eth.h
+ stm32f7xx_hal_eth.h
+ stm32fxx_hal_eth.h
+
+These files are copied from ST's HAL library. These work both for STM32F4 and STM32F7.
+Please remove or rename these files from the HAL distribution that you are using.
+