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
slimen
Senior
Posted on November 09, 2016 at 12:03

Hello,

You can start with a LwIP example under STM32CubeF2 with a similar type of your project to deduce what is going wrong in your case.

The working example available at this path can help you as an implementation example: 

STM32Cube_FW_F2_V1.4.0\STM32Cube_FW_F2_V1.4.0\Projects\STM322xG_EVAL\Applications\LwIP

Regards

N L
Associate II
Posted on December 16, 2016 at 22:48

Hi Gates,

Have you solved this issue?  I am running into the same problem.  I am using 429 Eval and the code is working on the eval board.  My hardware system is using a different 429 and is working well except for the ethernet cable disconnect issue.

Even though I set  CUBEMX to define LWIP_NETIF_LINK_CALLBACK        1, it did not do so.   I went in and defined LWIP_NETIF_LINK_CALLBACK        1

Like you, I added 

netif_set_link_callback(&gnetif, ethernetif_update_config); where it appears in the LWIP initialization function like in the example projects.  

I set a breakpoint in 

ethernetif_update_config to see if the code reaches and it does not.  In the LWIP HTTP RAW example, the breakpoint activates.  I am not sure what I am missing.

Thanks!

Posted on December 19, 2016 at 15:25

Hi All!

I have  same issue on stm32f746g-disco board. But for my case cubeMx generates code shich is not compiling in case 

I set  CUBEMX to define LWIP_NETIF_LINK_CALLBACK        1. It tries to use some interrupt masks which not defined in stm32f7xx_hal_conf.h. I investigated that PHY_MISR define and PHY_MICR not situated for my PHY, i have only PHY_ISFR_INT4, and have no ideas for now how to properly hadle that.

But if board got eth cable from the start it configuring properly and working.

If u'll got some tips to fix it please let me know.

Posted on December 19, 2016 at 23:49

Hi VK,

I have made some progress on my issue using the F429 MCU.  Maybe this will help you investigate.  

In the F429 eval board schematics, the PHY is configured to have a hardware interrupt and also PHY_MISR register bit that sets when a the link status changes. Link status in this case is ethernet cable status change. 

In the 429eval system, the INT pin of the PHY goes to the i2c module which has multiple inputs.  The i2c module sets an external interrupt on the MCU.   If you look at the HTTP_RAW example for the 429 eval board you will see this eternal interrupt in main.c HAL_GPIO_EXTI_Callback.

Since I do not have a physical connection between PHY INT pin and MCU, I have set a timer interrupt to run every 1 second. In that interrupt I am reading PHY_SR->PHY_LINK_STATUS bit to see if the link is active or not. I am also checking 

PHY_MISR->PHY_LINK_INTERRUPT bit.  If the PHY_LINK_INTERRUPT bit is set, I am calling ethernetif_set_link(&gnetif); 

In this PHY chip though, I have to modify the default ethernetif_set_link function created by CUBE because I can not read the

PHY_MISR->

PHY_LINK_INTERRUPT bit twice.  Once I read, the bit clears the interrupt.  The ethernetif_set_link handles the change in the ethernet cable's status.

ronen yacobi
Associate II
Posted on January 08, 2018 at 17:27

Don't know if it is relevant any more, but when you generate your CubeMx project with the ETH device you will see it generates the thread: 'ethernetif_set_link'. Make sure this is part of a thread of your OS. It observes the link and recovers it as soon you your ETH cable is pluged in again.

Terje K Wahl
Associate II
Posted on February 28, 2018 at 11:14

Hi,

I had a similar problem with Ethernet not working properly if the ethernet cable was unplugged on boot.

The solution was to make sure to call netif_set_up(). This should not be confused with netif_set_link_up(). The problem is that the CubeMX auto generated code only calls 

netif_set_up() (from MX_LWIP_Init() in lwip.c) if the network link is up...

In addition to this, you also have to provide a semaphore to the (auto generated) tcp link thread to be able to handle link up/down events in that thread from time to time.

PS: Also look out for the fact that DHCP is not started properly if dhcp_start() is called when the network interface is not 'up'.

Jim Kapcio
Associate II
Posted on February 28, 2018 at 14:50

Terje has nailed it. This is a persistent bug that should be fixed by ST. That said the other way to fix it locally is with but there are not many places to insert the solution without it getting overwritten by CUBEMX after every change.

But there is more going on here - Gates is correct about the 

LWIP_NETIF_LINK_CALLBACK. It is getting defined to 0 in opt.h and is not being overridden by the value lwiopts.h (set by CUBEMX).

For Cube projects without FreeRTOS, insert the following code into MX_LWIP_Process:

ethernetif_set_link(&gnetif);

/* Fix for un-plugged cable on start-up */

/* If the link is down at start-up, netif_set_up() never gets */

/* called by MX_LWIP_Init() */

if (netif_is_link_up(&gnetif) && !netif_is_up(&gnetif)) {

printf('Setting NETIF_FLAG_UP and restarting DHCP\r\n');

netif_set_up(&gnetif);

dhcp_start(&gnetif);

}

Still working on cleanest approach for FreeRTOS. 

Posted on March 01, 2018 at 14:30

I started with a new Cube project and the issue with opt.h vs lwipopts.h is gone - Enable 

LWIP_NETIF_LINK_CALLBACK is enough.

Add the following the 

netif_set_up() to ethernetif_notify_conn_changed().

Terje - can you elaborate on the tcp semaphore you mentioned?

Posted on March 06, 2018 at 14:33

When combining FreeRTOS and LWIP, enabling 

LWIP_NETIF_LINK_CALLBACK is important, but does not work 'out of the box'.

The auto generated code adds a 'LinkThr' FreeRTOS Task, with main function 'ethernetif_set_link()' created in ethernetif.c. The eternal loop here only executes the code that actually checks if the network link is up/down and calls  netif_set_link_up()/netif_set_link_down(), if it receives a signal from a semaphore:

' if (osSemaphoreWait( link_arg->semaphore, 100)== osOK)'

And that semaphore was not released anywhere in the code, so I had to make sure that  osSemaphoreRelease() is regularly called with the correct semaphore as an argument, or else the network link status change is not handled ever.