Ethernet driver initialization fails when no link is present at start-up
- October 12, 2017
- 5 replies
- 3057 views
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:
- USART3 is initialized after the Ethernet MAC or USB devices (minor problem)
- 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.
- 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.
- Because USART3 has not yet been initialized, attempts to print failure over USART3 fail for things like the Ethernet and USB initialization.
&sharp1, &sharp2, and &sharp4 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 &sharp3 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.
#stm32cubemx #hal-drivers #hal_eth_init #ethernet #stm32f7