I am working on a new feature for a firmware product based on the TM4C MCU. The feature is the ability to disable auto-negotiation and set the speed and duplex statically.
After reading the documentation (Tiva C Series TM4C129x Users Guide page 126). It states that if I use any of these values:
EMAC_PHY_FORCE_10B_T_HALF_DUPLEX
EMAC_PHY_FORCE_10B_T_FULL_DUPLEX
EMAC_PHY_FORCE_100B_T_FULL_DUPLEX
EMAC_PHY_FORCE_100B_T_HALF_DUPLEX
It will disable auto-negotiation and set the speed and duplex statically. However after testing this I am finding that it doesn't actually do that.
An auto-negotiation cycle is still initialized by lwip and the speed and duplex are set to the desired values, but with auto-negotiation enabled.
Code Sample:
Here are the defines for each of 5 options that the customer wants:
#define EMAC_PHY_CONFIG (EMAC_PHY_TYPE_INTERNAL | EMAC_PHY_INT_MDIX_EN | \
EMAC_PHY_AN_100B_T_FULL_DUPLEX)
#define EMAC_PHY_CONFIG_100_FULL (EMAC_PHY_TYPE_INTERNAL | EMAC_PHY_INT_MDIX_EN | \
EMAC_PHY_FORCE_100B_T_FULL_DUPLEX)
#define EMAC_PHY_CONFIG_100_HALF (EMAC_PHY_TYPE_INTERNAL | EMAC_PHY_INT_MDIX_EN | \
EMAC_PHY_FORCE_100B_T_HALF_DUPLEX)
#define EMAC_PHY_CONFIG_10_FULL (EMAC_PHY_TYPE_INTERNAL | EMAC_PHY_INT_MDIX_EN | \
EMAC_PHY_FORCE_10B_T_FULL_DUPLEX)
#define EMAC_PHY_CONFIG_10_HALF (EMAC_PHY_TYPE_INTERNAL | EMAC_PHY_INT_MDIX_EN | \
EMAC_PHY_FORCE_10B_T_HALF_DUPLEX)
Here is the initialization code that I placed in lwip (network_config is a struct that is read from flash memory before this function is executed which contains the user's desired settings)
void lwIPInit(uint32_t ui32SysClkHz, const uint8_t *pui8MAC, struct ip_addr ui32IPAddr, struct ip_addr ui32NetMask, struct ip_addr ui32GWAddr, uint32_t ui32IPMode) { // Check the parameters. #if LWIP_DHCP && LWIP_AUTOIP ASSERT((ui32IPMode == IPADDR_USE_STATIC) || (ui32IPMode == IPADDR_USE_DHCP) || (ui32IPMode == IPADDR_USE_AUTOIP)); #elif LWIP_DHCP ASSERT((ui32IPMode == IPADDR_USE_STATIC) || (ui32IPMode == IPADDR_USE_DHCP)); #elif LWIP_AUTOIP ASSERT((ui32IPMode == IPADDR_USE_STATIC) || (ui32IPMode == IPADDR_USE_AUTOIP)); #else ASSERT(ui32IPMode == IPADDR_USE_STATIC); #endif // Enable the ethernet peripheral. MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0); MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0); // Enable the internal PHY if it's present and we're being asked to use it. if((EMAC_PHY_CONFIG & EMAC_PHY_TYPE_MASK) == EMAC_PHY_TYPE_INTERNAL) { // We've been asked to configure for use with the internal PHY. Is it present? if(MAP_SysCtlPeripheralPresent(SYSCTL_PERIPH_EPHY0)) { // Yes - enable and reset it. MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0); MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0); } else { // Internal PHY is not present on this part so hang here. while(1) { debug_printf("No PHY!?\r\n"); } } } // Wait for the MAC to come out of reset. while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0)) {} if (network_config.auto_neg) { // Configure for use with whichever PHY the user requires. MAP_EMACPHYConfigSet(EMAC0_BASE, EMAC_PHY_CONFIG); debug_printf("Auto Negotiation Enabled\t\n"); } else if (!network_config.auto_neg) { if (network_config.full_duplex) { debug_printf("Link Duplex:Full\t\n"); if (network_config.full_speed) { MAP_EMACPHYConfigSet(EMAC0_BASE, EMAC_PHY_CONFIG_100_FULL); debug_printf("Link Speed:100 Mbps\t\n"); } else { MAP_EMACPHYConfigSet(EMAC0_BASE, EMAC_PHY_CONFIG_10_FULL); debug_printf("Link Speed:10 Mbps\t\n"); } } else { debug_printf("Link Duplex:Half\t\n"); if (network_config.full_speed) { MAP_EMACPHYConfigSet(EMAC0_BASE, EMAC_PHY_CONFIG_100_HALF); debug_printf("Link Speed:100 Mbps\t\n"); } else { MAP_EMACPHYConfigSet(EMAC0_BASE, EMAC_PHY_CONFIG_10_HALF); debug_printf("Link Speed:10 Mbps\t\n"); } } } // Initialize the MAC and set the DMA mode. MAP_EMACInit(EMAC0_BASE, ui32SysClkHz, EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED, 4, 4, 0); // Set MAC configuration options. MAP_EMACConfigSet(EMAC0_BASE, (EMAC_CONFIG_FULL_DUPLEX | EMAC_CONFIG_CHECKSUM_OFFLOAD | EMAC_CONFIG_7BYTE_PREAMBLE | EMAC_CONFIG_IF_GAP_96BITS | EMAC_CONFIG_USE_MACADDR0 | EMAC_CONFIG_SA_FROM_DESCRIPTOR | EMAC_CONFIG_BO_LIMIT_1024), (EMAC_MODE_RX_STORE_FORWARD | EMAC_MODE_TX_STORE_FORWARD | EMAC_MODE_TX_THRESHOLD_64_BYTES | EMAC_MODE_RX_THRESHOLD_64_BYTES), 0); // Program the hardware with its MAC address (for filtering). MAP_EMACAddrSet(EMAC0_BASE, 0, (uint8_t *)pui8MAC); // Save the network configuration for later use by the private initialization. g_ui32IPMode = ui32IPMode; g_ui32IPAddr = ui32IPAddr; g_ui32NetMask = ui32NetMask; g_ui32GWAddr = ui32GWAddr; // Initialize lwIP. // The remainder of initialization is done immediately if not using a RTOS and it is deferred to the TCP/IP thread's context if using a RTOS. #if NO_SYS lwIPPrivateInit(0); #else tcpip_init(lwIPPrivateInit, 0); #endif }
Any help on this would be great. I really wish these settings were a little more straight forward, I searched Google and the TI forms for any information about this and I came up with very little.
Thanks,
Jonathan L Clark