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

That was my issue too. MConw is absolutely right, we have to manually call netif_set_up / netif_set_down in ethernetif_notify_conn_changed callback whenever the link status changing event occurs

What ST and your are doing is wrong and unnecessary. My topic explains clearly how link state must be managed:

https://community.st.com/s/question/0D50X0000BOtfhnSQB/how-to-make-ethernet-and-lwip-working-on-stm32

And, when needed, why implement some additional bool variables, if one can just use netif_is_up() macro? Again - not reading the documentation and not looking at code...

C.Y.Yeh
Associate

I take the feature of LWIP(static IP address) with freertos, and the same issue occurs.

I used CubeMX to generate the lwip and freertos code for CubeIDE.

And by dividing a function(lwip.c) into two functions, the issue is fixed for me now.

In lwip.c, create three new functions(two created from MX_LWIP_Init)

//in lwip.c, and used in freertos task
void MX_LWIP_Init(void)
{
 /* IP addresses initialization */
 IP_ADDRESS[0] = 192;
 IP_ADDRESS[1] = 168;
 IP_ADDRESS[2] = 0;
 IP_ADDRESS[3] = 100;
 NETMASK_ADDRESS[0] = 255;
 NETMASK_ADDRESS[1] = 255;
 NETMASK_ADDRESS[2] = 255;
 NETMASK_ADDRESS[3] = 0;
 GATEWAY_ADDRESS[0] = 192;
 GATEWAY_ADDRESS[1] = 168;
 GATEWAY_ADDRESS[2] = 0;
 GATEWAY_ADDRESS[3] = 254;
/* USER CODE BEGIN IP_ADDRESSES */
/* USER CODE END IP_ADDRESSES */
 /* Initilialize the LwIP stack with RTOS */
 tcpip_init( NULL, NULL );
 /* IP addresses initialization without DHCP (IPv4) */
 IP4_ADDR(&ipaddr, IP_ADDRESS[0], IP_ADDRESS[1], IP_ADDRESS[2], IP_ADDRESS[3]);
 IP4_ADDR(&netmask, NETMASK_ADDRESS[0], NETMASK_ADDRESS[1] , NETMASK_ADDRESS[2], NETMASK_ADDRESS[3]);
 IP4_ADDR(&gw, GATEWAY_ADDRESS[0], GATEWAY_ADDRESS[1], GATEWAY_ADDRESS[2], GATEWAY_ADDRESS[3]);
 /* add the network interface (IPv4/IPv6) with RTOS */
 netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &tcpip_input);
 /* Registers the default network interface */
 netif_set_default(&gnetif);
 
 if (netif_is_link_up(&gnetif))
 {
  /* When the netif is fully configured this function must be called */
  netif_set_up(&gnetif);
 }
 else
 {
  /* When the netif link is down this function must be called */ 
  netif_set_down(&gnetif);
 }
 
 /* Set the link callback function, this function is called on change of link status*/
 netif_set_link_callback(&gnetif, ethernetif_update_config);
 
 /* create a binary semaphore used for informing ethernetif of frame reception */
 Netif_LinkSemaphore = osSemaphoreNew(1, 1, NULL);
 
 link_arg.netif = &gnetif;
 link_arg.semaphore = Netif_LinkSemaphore;
 
 /* Create the Ethernet link handler thread */
/* USER CODE BEGIN OS_THREAD_NEW_CMSIS_RTOS_V2 */
 memset(&attributes, 0x0, sizeof(osThreadAttr_t));
 attributes.name = "LinkThr";
 attributes.stack_size = INTERFACE_THREAD_STACK_SIZE;
 attributes.priority = osPriorityBelowNormal;
 osThreadNew(ethernetif_set_link, &link_arg, &attributes);
/* USER CODE END OS_THREAD_NEW_CMSIS_RTOS_V2 */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
 
//separate MX_LWIP_Init into two function, function 1 and function 2
//located at the same file lwip.c
//new function 1
void NEW_LWIP_Init_Netif(void){
	  /* IP addresses initialization */
	  IP_ADDRESS[0] = 192;
	  IP_ADDRESS[1] = 168;
	  IP_ADDRESS[2] = 0;
	  IP_ADDRESS[3] = 100;
	  NETMASK_ADDRESS[0] = 255;
	  NETMASK_ADDRESS[1] = 255;
	  NETMASK_ADDRESS[2] = 255;
	  NETMASK_ADDRESS[3] = 0;
	  GATEWAY_ADDRESS[0] = 192;
	  GATEWAY_ADDRESS[1] = 168;
	  GATEWAY_ADDRESS[2] = 0;
	  GATEWAY_ADDRESS[3] = 254;
	  /* Initilialize the LwIP stack with RTOS */
	  tcpip_init( NULL, NULL );
 
	  /* IP addresses initialization without DHCP (IPv4) */
	  IP4_ADDR(&ipaddr, IP_ADDRESS[0], IP_ADDRESS[1], IP_ADDRESS[2], IP_ADDRESS[3]);
	  IP4_ADDR(&netmask, NETMASK_ADDRESS[0], NETMASK_ADDRESS[1] , NETMASK_ADDRESS[2], NETMASK_ADDRESS[3]);
	  IP4_ADDR(&gw, GATEWAY_ADDRESS[0], GATEWAY_ADDRESS[1], GATEWAY_ADDRESS[2], GATEWAY_ADDRESS[3]);
 
	  /* add the network interface (IPv4/IPv6) with RTOS */
	  netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &tcpip_input);
 
	  /* Registers the default network interface */
	  netif_set_default(&gnetif);
}
//new function 2
void NEW_LWIP_Init_Thread(void){
	  if (netif_is_link_up(&gnetif))
	  {
	    /* When the netif is fully configured this function must be called */
	    netif_set_up(&gnetif);
	  }
	  else
	  {
	    /* When the netif link is down this function must be called */
	    netif_set_down(&gnetif);
	  }
	  /* Set the link callback function, this function is called on change of link status*/
	  netif_set_link_callback(&gnetif, ethernetif_update_config);
 
	  /* create a binary semaphore used for informing ethernetif of frame reception */
	  Netif_LinkSemaphore = osSemaphoreNew(1, 1, NULL);
 
	  link_arg.netif = &gnetif;
	  link_arg.semaphore = Netif_LinkSemaphore;
	  /* Create the Ethernet link handler thread */
	/* USER CODE BEGIN OS_THREAD_NEW_CMSIS_RTOS_V2 */
	  memset(&attributes, 0x0, sizeof(osThreadAttr_t));
	  attributes.name = "LinkThr";
	  attributes.stack_size = INTERFACE_THREAD_STACK_SIZE;
	  attributes.priority = osPriorityBelowNormal;
	  osThreadNew(ethernetif_set_link, &link_arg, &attributes);
}
//and more, check the cable connection
static uint32_t regvalue = 0;
uint8_t NEW_LWIP_Link_Status(uint8_t mNetworkInit){
    /* Read PHY_BSR*/
    HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, &regvalue);
 
    regvalue &= PHY_LINKED_STATUS;
 
    /* Check whether the netif link down and the PHY link is up */
    if (mNetworkInit == 1){
    	if(!netif_is_link_up(&gnetif) && (regvalue))
    	{
    		printf("network cable link is connected\r\n");
    		netif_set_link_up(&gnetif);
    		return 1;
    	}
    }
    return 0;
}

and then in freertos.c, modify the default task of network initialization.

//in freertos.c, the default task
void StartDefaultTask(void *argument)
{
  /* init code for LWIP */
  //MX_LWIP_Init(); //the original code of initializing network, marked
  /* USER CODE BEGIN StartDefaultTask */
  static uint8_t mNetworkInit = 1;
  NEW_LWIP_Init_Netif();
 
  /* Infinite loop */
  for(;;)
  { 
       //fix the issue of network cable not plugged at  device booting up
	if (NEW_LWIP_Link_Status(mNetworkInit)){
		printf("Initialize Network Thread only once\r\n");
		mNetworkInit = 0;
		NEW_LWIP_Init_Thread();
	}
    osDelay(10);
  }
  /* USER CODE END StartDefaultTask */
}

Hi C.Y.

I am facing the issue of the Cable disconnection.

1 - In your code, what is the declaration for link_arg ?

2 - How do you use the Semaphore in ethernetif.c ? Can you share your modified code ?

 

Thanks