cancel
Showing results for 
Search instead for 
Did you mean: 

Initialize LWIP with Ethernet disconnected

gaetanbusson
Associate II
Posted on November 04, 2016 at 14:45

Hello !

The board I am using for this topic is based on the ST

http://www.st.com/en/evaluation-tools/stm3220g-eval.html

hardware for the Ethernet part. I have generated a basic code with cubeMx (nice tool!) and Ethernet communication is working well on this board. The problem is that Ethernet is working only when Ethernet cable is connected at startup (especially when initialization function is run). If I start my board without cable, Ethernet is not working (ping test failed) and will never work even if I connect the cable. To solve this, I added the following function after LWIP initialization:

netif_set_link_callback(&gnetif, ethernetif_update_config);

The ''ethernetif_update_config'' function is generated by cubeMx (in ethernetif.c file) to restart auto-negotiation:

/**
* @brief Link callback function, this function is called on change of link status
* to update low level driver configuration.
* @param netif: The network interface
* @retval None
*/
void
ethernetif_update_config(
struct
netif *netif)
{
__IO uint32_t tickstart = 0;
uint32_t regvalue = 0;
if
(netif_is_link_up(netif))
{ 
/* Restart the auto-negotiation */
if
(heth.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE)
{
/* Enable Auto-Negotiation */
HAL_ETH_WritePHYRegister(&heth, PHY_BCR, PHY_AUTONEGOTIATION);
/* Get tick */
tickstart = HAL_GetTick();
/* Wait until the auto-negotiation will be completed */
do
{
HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, ®value);
/* Check for the Timeout ( 1s ) */
if
((HAL_GetTick() - tickstart ) > 1000)
{ 
/* In case of timeout */
goto
error;
} 
} 
while
(((regvalue & PHY_AUTONEGO_COMPLETE) != PHY_AUTONEGO_COMPLETE));
/* Read the result of the auto-negotiation */
HAL_ETH_ReadPHYRegister(&heth, PHY_SR, ®value);
/* Configure the MAC with the Duplex Mode fixed by the auto-negotiation process */
if
((regvalue & PHY_DUPLEX_STATUS) != (uint32_t)RESET)
{
/* Set Ethernet duplex mode to Full-duplex following the auto-negotiation */
heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX; 
}
else
{
/* Set Ethernet duplex mode to Half-duplex following the auto-negotiation */
heth.Init.DuplexMode = ETH_MODE_HALFDUPLEX; 
}
/* Configure the MAC with the speed fixed by the auto-negotiation process */
if
(regvalue & PHY_SPEED_STATUS)
{ 
/* Set Ethernet speed to 10M following the auto-negotiation */
heth.Init.Speed = ETH_SPEED_10M; 
}
else
{ 
/* Set Ethernet speed to 100M following the auto-negotiation */
heth.Init.Speed = ETH_SPEED_100M;
}
}
else
/* AutoNegotiation Disable */
{
error :
/* Check parameters */
assert_param(IS_ETH_SPEED(heth.Init.Speed));
assert_param(IS_ETH_DUPLEX_MODE(heth.Init.DuplexMode));
/* Set MAC Speed and Duplex Mode to PHY */
HAL_ETH_WritePHYRegister(&heth, PHY_BCR, ((uint16_t)(heth.Init.DuplexMode >> 3) |
(uint16_t)(heth.Init.Speed >> 1))); 
}
/* ETHERNET MAC Re-Configuration */
HAL_ETH_ConfigMAC(&heth, (ETH_MACInitTypeDef *) NULL);
/* Restart MAC interface */
HAL_ETH_Start(&heth); 
}
else
{
/* Stop MAC interface */
HAL_ETH_Stop(&heth);
}
ethernetif_notify_conn_changed(netif);
}

Unfortunately, when I manually launch this callback by calling the ''netif_set_link_up(&gnetif)'' function after connecting the cable, Ethernet is still not working. Is anybody having an idea on how to make Ethernet working in this configuration? Thank you for your help #lwip-ethernet-disconnected
23 REPLIES 23
Posted on April 03, 2018 at 19:08

That semaphore is probably best posted by an interrupt service routine, triggered by the real PHY MII interrupt signal. Depending on the PHY it might need extra configuration to actually toggle some pin and certainly you need GPIO configuration and extra code for that. The alternative is, as you write, to simply post the semaphore regularly.

Posted on July 09, 2018 at 17:31

Hello! 

I added this part of the code inside the

MX_LWIP_Process() function. I also changed 

LWIP_NETIF_LINK_CALLBACK to 1 manually in opt.h. Finally I also have the 

netif_set_link_callback() function in MX_LWIP_Init() (which was not automatically generated by Cube MX)

By the way if I ping my discovery board I don't get a reply from it, when I add 

netif_set_link_callback. 

Without this function it works, but I don't have the eth working if the cable is not connected during initialization..

Do we have a final solution to this problem? Thanks!

ph7
Associate

Just add ethernetif_set_link(netif_default); to main loop because:

/**

 * @brief This function sets the netif link status.

 * @note  This function should be included in the main loop to poll 

 *     for the link status update  

 * @param netif: the network interface

 * @retval None

 */

and handle event in user code:

void ethernetif_notify_conn_changed(struct netif *netif) {

if (netif_is_link_up(netif)) {

netif_set_up(netif);

} else {

netif_set_down(netif);

}

}

Gerardo Trotta
Associate II

Moreover.

If dhcp is enabled, raw 727 in dhcp.c (LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;);) should be comment out, otherwise dhcp will never start.

toroid
Associate III

I was looking for this solution also, thank you for the tips. However, there is one thing missing still.

I am using CubeMX 6.0.1 and firmware STM32Cube FW_F4 V1.25.1.

Freertos is enabled with V2 api.

Ethernet settings in Cubemx are:

auto negotiation enabled, rx mode = interrupt, checksum by hardware. Make sure you PHY register setting correspond to your PHY chip. I have KSZ8081 which required some register setting to be altered from what cubemx offers by default.

In lwip settings in cubemx, inside key options, enable LWIP_NETIF_LINK_CALLBACK if not yet enabled.

The cube generated code initially only works when link is up at boot. To fix this, insert the code mentioned earlier in this thread by @ph7​ to cubemx generated weak function ethernetif_notify_conn_changed() inside ethernetif.c. However, this alone wont suffice since this function will not be called at boot. So, add a call to ethernetif_notify_conn_changed() in MX_LWIP_Init() as the last call of the function. Cubemx nicely includes /*user code begin 3*/ for this so it wont be deleted by further cubemx code generations.

These two additions to the cubemx generated code will remove the bug that Ethernet will not work if the link is not up at reset.

Furthermore, there is a long delay waiting for the link inside HAL_ETH_Init() due to ETH_TIMEOUT_LINKED_STATE increasing boot time when there is no link. I dont know of any cubemx friendly way to fix this though. I just documented this in my readme file and change it by hand every time cubemx code is generated.

toroid
Associate III

I also had to fix this bug for a non-os program. Again CubeMX 6.0.1 and firmware STM32Cube FW_F4 V1.25.1.

No freertos.

Ethernet settings in Cubemx are:

auto negotiation enabled, rx mode = polling, checksum by hardware.

In lwip settings in cubemx, inside key options, enable LWIP_NETIF_LINK_CALLBACK.

In a polling application you will need to call MX_LWIP_Process() in the mainloop. Inside MX_LWIP_Process() add a call to function ethernetif_set_link(&gnetif), this function should be generated for you by cubemx. I put the call inside /* USER CODE BEGIN 4_3 */ so it's cubemx regeneration safe.

Now link should work properly even if not available at boot.

Hi,

I did it but not work,

My board is Nucleo F4439ZI

Oh, I resolved it,

comment out : in dhcp.c (LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;);)

Thank @Gerardo Trotta​ 

N L
Associate II
Mute
Nimal Lobo

I ran into this issue as well and was looking for the difference between the boot setup and the link/config change callbacks. I came to the forums to see if I could shortcut my search and this was definitely my issue. I added a bool to track if the netif_set_up() was called or not, and was able to call it when a link was sensed, if it wasn't called before.