SMT32F407+FreeRTOS+LWIP+LAN8720使用Cube MX情况下无法实现网线热插拔

项目场景:

STM32F407+LAN8720使用Cube MX HAL库生成工程;


问题描述

使用Cube MX生成STM32F407+Free RTOS + LAN8720工程,在可以ping通后打开了LWIP->Key Options->LWIP_NETIF_LINK_CALLBACK选项,希望可以实现自动连接状态检测,发现在不插网线上电后,无法初始化完成,无法ping通,只有插着网线上电才可以;而插着网线上电后,在插拔2次之后发生卡死;

看了网上其他解决方法,多为旧版SDK在初始化阶段如果没有插入网线则会超时卡死,和新版SDK问题不同;


原因分析:

经过查阅源码发现了在LWIP初始化阶段会检测是否有网线连接,如果有连接则执行netif_set_up相关代码,如下:

文件路径: LWIP\Target\ethernetif.c
...
...
/**
 * @brief In this function, the hardware should be initialized.
 * Called from ethernetif_init().
 *
 * @param netif the already initialized lwip network interface structure
 *        for this ethernetif
 */
static void low_level_init(struct netif *netif)
{
...
...
    /* Get MAC Config MAC */
    HAL_ETH_GetMACConfig(&heth, &MACConf);
    MACConf.DuplexMode = duplex;
    MACConf.Speed = speed;
    HAL_ETH_SetMACConfig(&heth, &MACConf);

    HAL_ETH_Start_IT(&heth);
    netif_set_up(netif);
    netif_set_link_up(netif);
...
...

在增加了LWIP_NETIF_LINK_CALLBACK选项后,会在lwip.c中,增加ethernet_link_thread线程,用来监控网线是否插拔

文件路径:LWIP\App\lwip.c

/**
  * LwIP initialization function
  */
void MX_LWIP_Init(void)
{
 ...
 ...
  /* Set the link callback function, this function is called on change of link status*/
  netif_set_link_callback(&gnetif, ethernet_link_status_updated);

  /* Create the Ethernet link handler thread */
/* USER CODE BEGIN H7_OS_THREAD_NEW_CMSIS_RTOS_V2 */
  memset(&attributes, 0x0, sizeof(osThreadAttr_t));
  attributes.name = "EthLink";
  attributes.stack_size = INTERFACE_THREAD_STACK_SIZE;
  attributes.priority = osPriorityBelowNormal;
  osThreadNew(ethernet_link_thread, &gnetif, &attributes);
...
...
}

但是在检测到插入网线后,进行的netif_set_up相关代码中,却和low_level_init中不同,没有使用中断方式,如下:

文件路径: LWIP\Target\ethernetif.c

/**
  * @brief  Check the ETH link state then update ETH driver and netif link accordingly.
  * @retval None
  */
void ethernet_link_thread(void* argument)
{
...
...
    if(linkchanged)
    {
      /* Get MAC Config MAC */
      HAL_ETH_GetMACConfig(&heth, &MACConf);
      MACConf.DuplexMode = duplex;
      MACConf.Speed = speed;
      HAL_ETH_SetMACConfig(&heth, &MACConf);
      HAL_ETH_Start(&heth);		// 	此处没有使用    HAL_ETH_Start_IT(&heth);
      netif_set_up(netif);
      netif_set_link_up(netif);
    }
...
...

尝试修改了此处代码为如下,问题解决;

HAL_ETH_Start_IT(&heth);

解决方案:

将ethernet_link_thread线程中,检测到网线连接后的处理函数修改为中断模式,如下:

文件路径:LWIP\Target\ethernetif.c

/**
  * @brief  Check the ETH link state then update ETH driver and netif link accordingly.
  * @retval None
  */
void ethernet_link_thread(void* argument)
{
  ETH_MACConfigTypeDef MACConf = {0};
  int32_t PHYLinkState = 0;
  uint32_t linkchanged = 0U, speed = 0U, duplex = 0U;

  struct netif *netif = (struct netif *) argument;
/* USER CODE BEGIN ETH link init */

/* USER CODE END ETH link init */

  for(;;)
  {
  PHYLinkState = LAN8742_GetLinkState(&LAN8742);

  if(netif_is_link_up(netif) && (PHYLinkState <= LAN8742_STATUS_LINK_DOWN))
  {
    HAL_ETH_Stop_IT(&heth);
    netif_set_down(netif);
    netif_set_link_down(netif);
  }
  else if(!netif_is_link_up(netif) && (PHYLinkState > LAN8742_STATUS_LINK_DOWN))
  {
    switch (PHYLinkState)
    {
    case LAN8742_STATUS_100MBITS_FULLDUPLEX:
      duplex = ETH_FULLDUPLEX_MODE;
      speed = ETH_SPEED_100M;
      linkchanged = 1;
      break;
    case LAN8742_STATUS_100MBITS_HALFDUPLEX:
      duplex = ETH_HALFDUPLEX_MODE;
      speed = ETH_SPEED_100M;
      linkchanged = 1;
      break;
    case LAN8742_STATUS_10MBITS_FULLDUPLEX:
      duplex = ETH_FULLDUPLEX_MODE;
      speed = ETH_SPEED_10M;
      linkchanged = 1;
      break;
    case LAN8742_STATUS_10MBITS_HALFDUPLEX:
      duplex = ETH_HALFDUPLEX_MODE;
      speed = ETH_SPEED_10M;
      linkchanged = 1;
      break;
    default:
      break;
    }

    if(linkchanged)
    {
      /* Get MAC Config MAC */
      HAL_ETH_GetMACConfig(&heth, &MACConf);
      MACConf.DuplexMode = duplex;
      MACConf.Speed = speed;
      HAL_ETH_SetMACConfig(&heth, &MACConf);
      HAL_ETH_Start_IT(&heth);				// <<<<<<<<<<<<<  此处
      netif_set_up(netif);
      netif_set_link_up(netif);
    }
  }

/* USER CODE BEGIN ETH link Thread core code for User BSP */

/* USER CODE END ETH link Thread core code for User BSP */

    osDelay(100);
  }
}

问题得以解决。

回顾:

在新版Cube MX SDK中,LWIP已经可以实现了网线热插拔,只需打开LWIP_NETIF_LINK_CALLBACK选项即可生成相关代码;会开辟一个线程每隔100ms检测一次连接状态,在检测到插拔后会自动调用netif_set_up和netif_set_down,不需要特殊处理,并且会自动触发APP/lwip.c中相关的回调函数;只是这里调用的函数需要修改一下,可能是没有处理到这部分代码的生成。只需修改此处问题可以解决,增加回调函数打印,串口调试输出如下图。

/**
  * @brief  Notify the User about the network interface config status
  * @param  netif: the network interface
  * @retval None
  */
static void ethernet_link_status_updated(struct netif *netif)
{
  if (netif_is_up(netif))
  {
/* USER CODE BEGIN 5 */
  printf("netif_is_up...\r\n");
/* USER CODE END 5 */
  }
  else /* netif is down */
  {
/* USER CODE BEGIN 6 */
  printf("netif_is_down...\r\n");
/* USER CODE END 6 */
  }
}

在这里插入图片描述

  • 11
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值