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