网上有很多基于自己移植lwip源码配置热插拔功能的实例,今天猛然发现,CUBEMX配置LWIP的STM32工程下的网线热插拔功能已经配置好了只需一步即可实现网线的热插拔。
- 首先可以在lwip.c文件中看到函数
MX_LWIP_Init()
,在这个函数里看到
这里很明确的说了这个回调函数在网络连接状态改变的时候会调用,既然已经说了,那我们只要在这个回调函数里做一些变化即可实现热插拔。 - 进入回调函数
ethernetif_update_config()
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);
}
看到代码,可以得知,生成的工程已经为我们做好了很多事情,比如重启自动协商,使能自动协商,再一次检测自动协商是否设置成功,配置MAC,设置工作模式,设置网速。这里要注意,CUBEMX配置的时候要使能自动协商功能。所以这个函数里面不需要我们自己做什么,但是这个函数中有一个函数特别重要,就是这个函数的最后的一个函数 ethernetif_notify_conn_changed(netif);
这个函数才是我们需要做的工作。
3. 修改函数ethernetif_notify_conn_changed(netif)
可以看到这个函数是个弱定义,需要我们进行完善。netif_is_link_up()
函数是判断此前网络是否成功初始化。
这样进行netif_is_link_up
函数操作和netif_set_link_down
函数就可以实现热插拔了。
经过实际测试,不论初始化时有没有插网线初始后再插入网线,还是中途拔了再重新插入都可以实现正常的网络功能了。