This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

EMAC_PHY_FORCE_100B_T_HALF_DUPLEX doesn't actually disable auto negotiation.

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

  • Hi Clark,

    I will do a test, then come back to you. Thanks

    Regards,
    QJ
  • Hi Clark,

    I tried on TM4C129 DK, The register values I read back from the PHY are correct. I don't have tools to capture the signal pulses. Is the auto-negotiate feature enabled on your PC side?

    Regards,

    QJ

  • Hi QJ,

    Yes auto-negotiate is enabled on my PC. The reason I think it is still enabled on the Tiva is because when I force the Tiva to 10Mbps full-duplex it negotiates to that speed and duplex correctly. According to IEE 802.3 section 28 if auto-negotiation is disabled then the device should only be allowed to communicate at half-duplex.

    Thanks,

    Jonathan L Clark

  • Hi....Anyone...

    Still having the problem. I am unable to disable auto-negotiation on Tiva. The customers want this feature and if we can't get it working then we are going to go to a different MCU for our final product. Is this a hardware problem?

    Thanks,

    Jonathan L Clark
  • Hello Jonathan,

    I don't think so. Can you please provide the following data

    1. Before disabling the Auto MDIX, read the EMAC PHY register
    2. Disable the register bit for Auto MDIX
    3. Read the EMAC PHY register again.

    Regards
    Amit
  • Jonathan Clark said:
    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.

    When you say an "auto-negotiation cycle is still initialized by lwip" do you mean the following call at the end of the tivaif_hwinit() function in third_party/lwip-1.4.1/ports/tiva-tm4c129/netif/tiva-tm4c129.c ?

      /* Tell the PHY to start an auto-negotiation cycle. */
      EMACPHYWrite(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_BMCR, (EPHY_BMCR_ANEN |
                   EPHY_BMCR_RESTARTAN));
    }
    

    It is not clear why tivaif_hwinit() forces the Auto-Negotiation Enable bit to be set in the Ethernet Phy Basic Control Register, but that explains why the auto-negotiation gets enabled regardless of the options passed to MAP_EMACPHYConfigSet().

    Using the enet_io example from TivaWare I set the EMAC_PHY_CONFIG in lwipopts.h to EMAC_PHY_FORCE_10B_T_FULL_DUPLEX (rather than the default EMAC_PHY_AN_100B_T_FULL_DUPLEX), and found that the EMACPHYWrite() call at the end of tivaif_hwinit() was forcing Auto-Negotiation to be enabled.

    As an experiment, the call to EMACPHYWrite() at the end of tivaif_hwinit() was commented out, to remove the forcing of Auto-Negotiation to be enabled. However, with that change the enet_io example was then stuck waiting for the Ethernet link status to be up. Therefore, further investigation is required in how to get the TM4C129 to establish an Ethernet link with forced speed and duplex.

  • That's it. I had to change what I was writing to the registers in tivaif_hwinit. I am able to get static settings to work using this:

    EMACPHYWrite(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_BMCR, (EPHY_BMCR_DUPLEXM));
    

    Unfortunately the Tiva won't establish a link if I set the speed statically to 10Mbps either on the client side or on the Tiva side. But I will start a new form for that issue.

    Thanks for helping me out Chester Gillon!

  • ​Hi,

    Even we have the same requirement and this information is helpful​​.​

    ​but this procedure seems to be applicable before BIOS_start().

    and we need to implement it after BIOS_Start().

    After BIOS_start(), we want to configure the auto-negotiation
    (On/Off) that is received via UART.

    a) PowerON(RESET)
    b) EMAC_Init()
    c) BIOS_start()
    d) Execute each task
    e) UART task has received auto-negotiation settings (On/Off).
    f) Update PHY settings by auto-negotiation settings (On/Off).

    Could you please let me know how if there is any advice on how
    to do this with the TI-RTOS(NDK).

    ​Best Regards
  • Hello Tmatsu

    I would suggest checking with the TI RTOS forum on the how to do this in NDK stack

    Regards
    Amit