STM32一侧作为client向server发送数据过程中,如果将网线直接拔掉再插上,就再也连接不上server,也就是说不支持网线热插拔。
创建过程就不多讲了,和一般的工程没什么区别,请注意我这里是选用了FreeRTOS,另外需要注意的有以下两点:
LAN8742A芯片内部可以通过设置寄存器Interrupt Mask Resgister的bit4来使能link status中断。
然而在CubeMX所生成的工程中,对于这个设置有错误。
出错的函数是:
static void low_level_init(struct netif *netif)
具体代码片是:
/* Read Register Configuration */
HAL_ETH_ReadPHYRegister(&heth, PHY_ISFR, ®value);
regvalue |= (PHY_ISFR_INT4);
/* Enable Interrupt on change of link status */
HAL_ETH_WritePHYRegister(&heth, PHY_ISFR , regvalue );
/* Read Register Configuration */
HAL_ETH_ReadPHYRegister(&heth, PHY_ISFR , ®value);
错误原因是 LAN8742A 的ISFR寄存器属于只读寄存器,是不能对它设置的
当然这里要不要使能这个中断,我没有去做实验验证,因为最终我是通过查询如下图所示的LAN8742A的BSR的bit2来获取连接状态的。我怀疑开启这个中断后,当连接状态发生改变后,LAN8742A的14号引脚会产生低电平,但我这边因为用的是RII模式,这个引脚已经被占用了。回头这个疑问我如果有空解决,再更新吧。
修正后的代码是(用这段代码替换上面出问题的代码片):
#define PHY_IMR 0x001E
#define PHY_IMR_INT4 0x0010
HAL_ETH_WritePHYRegister(&heth, PHY_IMR, PHY_IMR_INT4);
其实由于我们在CubeMX中勾选相关选项,CubeMX会在void MX_LWIP_Init(void)中为我们创建一个ethernetif_set_link的任务,这个任务还附带有一个信号量,但是在实际代码中这个信号量并没有用到。我怀疑这可能与某个ST官方的开发板有关,在这个开发板上是有一个按键,按下按键就会释放这个信号量,写这个文档时,我没有再去找这部分代码。大家如果想找的话,可以在CubeMX下载的软件包里找,大致位置是在STM32Cube\Repository\STM32Cube_FW_F4_V1.25.0\Projects,另外这里面有很多参考工程可以学习。
我在实际测试时发现这个任务无法运行,因此我就直接删除了这个任务,然后新建了一个任务。
具体代码如下:
osThreadDef(Link_Status_T,NetCable_Dect_Task, osPriorityBelowNormal,0,configMINIMAL_STACK_SIZE);
LINKHandle = osThreadCreate(osThread(Link_Status_T),&gnetif);
/**
* @brief 检测网线连接状态线程.
* @param argument: gnetif
* @retval None
*/
void NetCable_Dect_Task(void const *argument)
{
uint32_t regvalue = 0;
struct netif *gnetif = (struct netif *)argument;
for(;;)
{
/* Read PHY_BSR*/
HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, ®value);
regvalue &= PHY_LINKED_STATUS;
/* Check whether the netif link down and the PHY link is up */
if(!netif_is_link_up(gnetif) && (regvalue))
{
/* network cable is connected */
netif_set_link_up(gnetif);
}
else if(netif_is_link_up(gnetif) && (!regvalue))
{
/* network cable is dis-connected */
netif_set_link_down(gnetif);
}
/* Suspend thread for 200 ms */
osDelay(200);
}
}
当网线连接时gnetif->flags的bit2将会被置1,否则清0。因此我就在TCP发送任务中添加了一下代码片:
for(;;)
{
if((gnetif)->flags & NETIF_FLAG_LINK_UP) //检测网线是否连接
{
break; //只有网线连接了才会进行接下来的操作
}
osDelay(200);
}
只有网线连接了才会执行new、connect、write等操作。如果发现网线被拔掉,将立即关闭删除相关连接,然后等待网线重新插好。
if((((gnetif)->flags & NETIF_FLAG_LINK_UP) == 0))
{
netconn_close(conn);
netconn_delete(conn);
break;
}
FreeRTOS的任务创建机制以及内存分配还需要仔细研究,如果大家有问题可以留言或者私聊,看到后我会尽力回复,如果想找我要源代码,请免开金口。