AnsweredAssumed Answered

Ethernet driver initialization fails when no link is present at start-up

Question asked by Daniel Glasser on Oct 12, 2017
Latest reply on Feb 13, 2018 by Jeanne Joly

Details: STM32CubeMX v4.22.1, firmware library for the STM32F7xxx family v1.8.0.

Created project for SW4STM32 using (nearly) default pin configuration for the Nucleo-144 with STM32F767ZI (rev Z).

If it matters, the project is configured to generate files for AC6 (sw4stm32).

 

The code generated in "Src/main.c" has some problems:

  1. USART3 is initialized after the Ethernet MAC or USB devices (minor problem)
  2. The generated function "MX_ETH_Init()" calls "HAL_ETH_Init()".  If "HAL_ETH_Init()" returns status other than "HAL_OK", "MX_ETH_Init()" calls "_Error_Handler()", which (of course) does not return. 
  3. If there is no Ethernet link present when "HAL_ETH_Init()" is called, it returns the status "HAL_TIMEOUT", and does so without fully configuring the PHY for auto-negotiation per the configuration passed in.
  4. Because USART3 has not yet been initialized, attempts to print failure over USART3 fail for things like the Ethernet and USB initialization.

 

#1, #2, and #4 are just annoying.  It would be less of a problem if the code for those things was not in the "immutable" sections of the code generated by STM32CubeMX -- every time the project is updated, any changes to the order of driver initialization or the result of the initialization gets overwritten because those changes don't appear between "/* USER CODE BEGIN xxx */" and "/* USER CODE END xxx */" markers.  The new vs. old file have to be manually merged, which is somewhat error prone.  I can live with it, just don't like it.

 

Issue #3 is the real problem, and it's in the HAL driver code for the STM32F7xx MAC ("stm32f7xx_hal_eth.c").  Througout the code in "HAL_ETH_Init()", there are loops that look like the following:

tickstart = HAL_GetTick();
do
{
   HAL_ETH_ReadPHYRegister(eth, PHY_BSR, &phyreg);
   if ((HAL_GetTick() - tickstart) > ETH_TIMEOUT_LINKED_STATE)
   {
      err = ETH_ERROR;
     ETH_MACDMAConfig(heth, err);
      heth->State = HAL_ETH_STATE_READY;
      __HAL_UNLOCK(heth);
      return HAL_TIMEOUT;
   }
} while (((phyreg & PHY_LINKED_STATUS) != PHY_LINKED_STATUS));

This is being done for operations where the current link status should not matter.  Initializing the Ethernet driver should not require that a link can be established at that time.  There are callbacks and other means of notifying user software when a link is established, but configuring the PHY itself should not expect a link to exist.

 

A timeout reading/writing one of the PHY registers is an error that can cause the driver init to fail, but please, not the Ethernet link itself.

 

The only workaround I can come up with is to edit the driver code, since I cannot guarentee that I will have a link at start-up (and can pretty much guarentee that it won't 90% of the time).

 

I've attached my STM32CubeMX project file for anyone who wants to reproduce the problem.

Outcomes