OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 15795|回复: 27

LWIP 不插网线初始化 断线重连 解决

[复制链接]

1

主题

6

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2018-1-24
在线时间
7 小时
发表于 2019-3-27 15:00:53 | 显示全部楼层 |阅读模式
在STM32+LAN8720硬件组合平台上,移植LWIP,使用的是原子哥的例程,但是这个例程需要在上电初始化时插上网线,否则插网线晚了,初始化就失败了。参考其他网友的经验,我通过设置网线连接状态变化,进行重新初始化,实现了不插网线的上电初始化和断线重连。
究其原因,原来的初始化程序在上电的时候去读PHY的寄存器,等待网线连接状态和自动协商完成,但是如果没有网线插上,就会在超时后初始化失败。而在插上网线连接建立后,如果由于某种原因网线断线,这时候PHY寄存器网线连接状态会发生变化;如果网线另一端改变了传输速率和全半双工状态,网络双方需要再次协调,PHY寄存器自动协商会发生变化,这也是造成断网的原因。只要能处理了网线连接状态和自动协商状态,就能够实现断线重连。
我方法如下:
1.减小读写PHY寄存器状态的超时时间,这一步是针对使用以前的库文件的,不是必须的,如果使用HAL库文件,且可以直接忽略。对于使用旧库文件的STM32F407处理器,在stm32f4x7_eth.h文件中,把PHY_READ_TO的值减小(原值大概是10到13秒,可修改为2或3秒对应值)。
2.写一个函数,检测网线连接状态和自动协商状态,并把它放在主循环中,轮询网线连接状态,执行初始化、掉线、上线等操作。我的代码如下,其它硬件平台应该也可以采用这个思路。
[mw_shl_code=c,true]
void Eth_Link_ITHandler(struct netif *netif)//检查自动协商状态、网线连接状态是否有变化
{
        link_status_new = (LAN8720_ReadPHY(PHY_BSR) & (0x0020 | 0x0004));//读PHY的状态寄存器,获取连接状态0x0020HY_AutoNego_Complete;0x0004HY_Linked_Status
        if(link_status_new != link_status_old)//自动协商状态或连接状态有变化(自动协商状态变化也是种网线重插)
        {
                link_status_old = link_status_new;//记录连接状态的变化
                if(link_status_new)//检测到网线连接
                {
                        if(EthInitStatus != ETH_SUCCESS)//之前没有成功初始化过
                        {
                                EthInitStatus =lwip_comm_init();
#if LWIP_DHCP   //使用DHCP
                                while((lwipdev.dhcpstatus!=2)&&(lwipdev.dhcpstatus!=0XFF))//等待DHCP获取成功/超时溢出
                                {  
                                        lwip_periodic_handle();        //LWIP内核需要定时处理的函数
                                }
#endif
                                httpd_init();
                        }
                        else                                                                //之前已经成功初始化过
                                netif_set_link_up(netif);//set link up for re link callbalk function
                }
                else//网线断开
                        netif_set_link_down(netif);//set link down for re link callbalk function       
        }
}[/mw_shl_code]



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

6

主题

29

帖子

0

精华

初级会员

Rank: 2

积分
83
金钱
83
注册时间
2013-9-7
在线时间
24 小时
发表于 2020-5-9 20:11:36 | 显示全部楼层
uint16_t        link_status_new = 0;
uint16_t        link_status_old = 0;

void Eth_Link_ITHandler(struct netif *netif)
{
                //static u8 i=0;
                link_status_new = ((ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_BSR)) & (PHY_AutoNego_Complete | PHY_Linked_Status));
                //printf("link_status_new is  %d\r\n",link_status_new);
                if(EthStatus != ETH_SUCCESS)
                {
                                printf("EthStatus != ETH_SUCCESS \r\n");

                                if((ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_BSR)) & PHY_Linked_Status)
                                {       
                                                /* Configure Ethernet */
                                                EthStatus = ETH_Init(&ETH_InitStructure, DP83848_PHY_ADDRESS);
                                                if(EthStatus==ETH_SUCCESS)
                                                {
                                                                ETH_DMAITConfig(ETH_DMA_IT_NIS|ETH_DMA_IT_R,ENABLE);   
                                                                printf("EthStatus == ETH_SUCCESS \r\n");
                                                }
                                }                       
//                                link_status_old = ((ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_BSR)) & (PHY_AutoNego_Complete | PHY_Linked_Status));
//                                printf("link_status_new is  %d\r\n",link_status_new);
//                                printf("link_status_old is  %d\r\n",link_status_old);
                }
                else                                                               
                {
                               
                                if((link_status_new != 0)&&(link_status_old == 0))
                                {
                                                link_status_old = link_status_new;
                                       
                                                netif_set_link_up(netif);//set link up for re link callbalk function
                                                printf("netif_set_link_up \r\n");
                                }
                                else if((link_status_new == 0)&&(link_status_old != 0))
                                {
                                                link_status_old = link_status_new;
                                                netif_set_link_down(netif);//set link down for re link callbalk function   
                                                printf("netif_set_link_down \r\n");
                                }
                               
                }
}


楼主的逻辑有一点错误才导致,不插上网线上电后再插网线导致不能正常通信,改改后就好了,还是多谢楼主了~!
回复 支持 1 反对 0

使用道具 举报

153

主题

310

帖子

0

精华

高级会员

Rank: 4

积分
673
金钱
673
注册时间
2019-3-26
在线时间
18 小时
发表于 2019-3-27 15:11:24 | 显示全部楼层
现在解决了吗
http://www.iis7.com/c/90/
回复 支持 反对

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2018-1-24
在线时间
7 小时
 楼主| 发表于 2019-3-27 17:07:58 | 显示全部楼层

这就是我的解决方法。
回复 支持 反对

使用道具 举报

13

主题

69

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
237
金钱
237
注册时间
2016-6-22
在线时间
50 小时
发表于 2019-3-27 20:29:52 | 显示全部楼层
本帖最后由 huanghuang 于 2019-3-27 20:32 编辑

我在f429开发板里也遇到了。根据另一个帖子http://www.openedv.com/forum.php ... hlight=%CD%F8%CF%DF
应该是原子例程没有释放未正确初始化而分配的空间。C:\Users\Administrator\Desktop\1.jpg
1.jpg
回复 支持 反对

使用道具 举报

13

主题

69

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
237
金钱
237
注册时间
2016-6-22
在线时间
50 小时
发表于 2019-3-27 20:31:44 | 显示全部楼层
huanghuang 发表于 2019-3-27 20:29
我在f429开发板里也遇到了。根据另一个帖子http://www.openedv.com/forum.php?mod=viewthread&tid=66604&hi ...

但是这个时候在不插网线的时候,                液晶显示Lwip Init failed! 变慢了,是因为释放空间需要吗?;        
回复 支持 反对

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2018-1-24
在线时间
7 小时
 楼主| 发表于 2019-3-27 21:57:20 | 显示全部楼层
huanghuang 发表于 2019-3-27 20:31
但是这个时候在不插网线的时候,                液晶显示Lwip Init failed! 变慢了,是因为释放空间需要吗?;

我上面发的代码是在使用HAL库的情况下用的,就添加在lan8720.c文件末尾。
lan8720初始化函数最后调用了HAL_ETH_Init()函数,这个函数会在读取网线连接状态超时后出错退出。这时候再多少次初始化都没用,只能是先标记一下初始化状态,继续执行其它程序,在循环中轮询网线连接状态,连接好后再进行初始化。
无标题.png
回复 支持 反对

使用道具 举报

13

主题

69

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
237
金钱
237
注册时间
2016-6-22
在线时间
50 小时
发表于 2019-3-27 22:00:30 | 显示全部楼层
春春的阳光 发表于 2019-3-27 21:57
我上面发的代码是在使用HAL库的情况下用的,就添加在lan8720.c文件末尾。
在lan8720初始化函数最后调用 ...

搜嘎,你的这个是407的吗
回复 支持 反对

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2018-1-24
在线时间
7 小时
 楼主| 发表于 2019-3-27 23:03:58 | 显示全部楼层
回复 支持 反对

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2018-1-24
在线时间
7 小时
 楼主| 发表于 2019-3-28 16:40:56 | 显示全部楼层
以前我用老版本的库文件,是把lwip_comm_init()函数中循环执行LAN8720_init( )这个地方改成只执行一次,而且出错也不退出,继续把lwip_comm_init()函数剩余部分运行完。
在主程序中,先运行一次lwip_comm_init()函数,这时如果没有网线插上,初始化状态是失败的,但不管它,在主循环中运行Eth_Link_ITHandler( ),只要探测到连接状态就会再次进行初始化,这时就会成功了。

这是我在使用老版本的库文件情况下写的Eth_Link_ITHandler( ),也是放在了lan8720.c文件的最后,可以成功进行初始化和断线重连的,只是需要改小一下1楼提到的PHY_READ_TO的值。[mw_shl_code=c,true]void Eth_Link_ITHandler(struct netif *netif)//检查网线连接状态是否有变化
{
        //static u8 i=0;
        link_status_new = ((ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR)) & (PHY_AutoNego_Complete | PHY_Linked_Status));//读PHY的状态寄存器,获取连接状态
        if(EthInitStatus != ETH_SUCCESS)//之前没有成功初始化过
        {
                if((ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR)) & PHY_Linked_Status)
                {
                        EthInitStatus = ETH_Reinit(&ETH_InitStructure, LAN8720_PHY_ADDRESS);
                        if(EthInitStatus==ETH_SUCCESS)//配置成功
                        {
                                ETH_DMAITConfig(ETH_DMA_IT_NIS|ETH_DMA_IT_R,ENABLE);          //使能以太网接收中断       
                        }
                }
                link_status_old = ((ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR)) & (PHY_AutoNego_Complete | PHY_Linked_Status));
        }
        else                                                                //之前已经成功初始化过
        {
                if(link_status_new != link_status_old)//自动协商状态或连接状态有变化(自动协商状态变化也是种网线重插)
                {
                        link_status_old = link_status_new;//记录连接状态的变化
                        if(link_status_new)//检测到网线连接
                                netif_set_link_up(netif);//set link up for re link callbalk function
                        else//网线断开
                                netif_set_link_down(netif);//set link down for re link callbalk function       
                }
        }
}[/mw_shl_code]
回复 支持 反对

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2018-1-24
在线时间
7 小时
 楼主| 发表于 2019-3-28 16:56:24 | 显示全部楼层
1楼所附代码是使用HAL库情况下写的,同样需要在lwip_comm_init()中把循环执行LAN8720_init( )改为一次。在主程序中,选运行了一下LAN8720_init( ),当然没有网线是不会成功的,只是为了对用到的引脚进行初始化,以便能够读取LAN8720的寄存器。在主循环中,则是同样持续运行Eth_Link_ITHandler( )。HAL库文件中对读取网线连接状态和自动协调状态的超时时间也有定义,在stm32f4xx_hal_eth.c文件中,原值是5000,不知道是不是代表5秒,我把它改为1000,这样执行LAN8720_init( )时等待时间会短点,反正主循环在反复运行,一次不成功可以再来,这样实现了网线在任何时间都可以插上或拔掉,只要插上就会成功连接。
回复 支持 反对

使用道具 举报

0

主题

295

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
335
金钱
335
注册时间
2019-3-26
在线时间
9 小时
发表于 2019-3-29 08:29:48 | 显示全部楼层
谢谢分享!
回复 支持 反对

使用道具 举报

0

主题

3

帖子

0

精华

新手上路

积分
20
金钱
20
注册时间
2019-4-23
在线时间
5 小时
发表于 2019-6-3 17:16:04 | 显示全部楼层
能把老版本的完整程序发来看看吗?不太懂您的那个结构体,想学习下。
回复 支持 反对

使用道具 举报

2

主题

7

帖子

0

精华

初级会员

Rank: 2

积分
93
金钱
93
注册时间
2016-2-27
在线时间
16 小时
发表于 2019-9-12 22:39:55 | 显示全部楼层
本帖最后由 643166069 于 2019-9-22 09:25 编辑

CUBEMX 配置的LWIP 默认没有 lwip_comm_init() 这个函数吧。。。。
回复 支持 反对

使用道具 举报

1

主题

5

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2019-9-16
在线时间
15 小时
发表于 2019-11-19 14:12:11 | 显示全部楼层
春春的阳光 发表于 2019-3-28 16:56
1楼所附代码是使用HAL库情况下写的,同样需要在lwip_comm_init()中把循环执行LAN8720_init( )改为一次。在 ...

ETH_TIMEOUT_LINKED_STATE默认是5000U 如果不改有几率超时引起初始化失败,我把这个值改到50000就比较稳定,应该还可以改的更小,需要验证。ETH_TIMEOUT_AUTONEGO_COMPLETED默认也是5000,按照你的说法,改小了就会超时
回复 支持 反对

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
42
金钱
42
注册时间
2019-11-5
在线时间
10 小时
发表于 2019-12-13 17:22:48 | 显示全部楼层
收藏收藏收藏
回复 支持 反对

使用道具 举报

1

主题

3

帖子

0

精华

新手入门

积分
18
金钱
18
注册时间
2019-7-5
在线时间
3 小时
发表于 2020-2-26 14:55:38 | 显示全部楼层
非常好
回复 支持 反对

使用道具 举报

6

主题

29

帖子

0

精华

初级会员

Rank: 2

积分
83
金钱
83
注册时间
2013-9-7
在线时间
24 小时
发表于 2020-5-9 19:28:17 | 显示全部楼层
EthInitStatus = ETH_Reinit(&ETH_InitStructure, LAN8720_PHY_ADDRESS);   这个ETH_Reinit函数能够贴出来下吗???楼主!!
回复 支持 反对

使用道具 举报

6

主题

29

帖子

0

精华

初级会员

Rank: 2

积分
83
金钱
83
注册时间
2013-9-7
在线时间
24 小时
发表于 2020-5-9 19:52:43 | 显示全部楼层
楼主   在没有插上网线  然后  后面插上网线  情况 也就是程序会进入EthStatus != ETH_SUCCESS的这个初始化,但是显示初始化成功后依然,不能PING通,这个问题有发现吗??
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2020-8-13
在线时间
0 小时
发表于 2020-8-13 21:58:10 | 显示全部楼层
xiongliangxcl 发表于 2020-5-9 20:11
uint16_t        link_status_new = 0;
uint16_t        link_status_old = 0;

老哥 能加个qq好友吗? 2711642009
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2020-8-13
在线时间
0 小时
发表于 2020-8-13 21:59:50 | 显示全部楼层
老哥 能认识下吗?现在一直解决不了这个问题,头疼死了,能否加个qq2711642009
回复 支持 反对

使用道具 举报

0

主题

10

帖子

0

精华

新手上路

积分
45
金钱
45
注册时间
2019-12-27
在线时间
6 小时
发表于 2020-8-19 09:03:21 | 显示全部楼层
使用cubemax生成的LWIP,解决这个问题很简单。
使能回调函数,为解决热拔插网线问题(包括上电后插网线或上电后热拔插网线问题),
进入回调函数ethernetif_notify_conn_changed(netif);
添加以下代码:
__weak void ethernetif_notify_conn_changed(struct netif *netif)
{
  /* NOTE : This is function could be implemented in user file
            when the callback is needed,
  */
        if (netif_is_link_up(netif))
  {
    /* When the netif is fully configured this function must be called */
    netif_set_up(netif);
  }
  else
  {
    /* When the netif link is down this function must be called */
    netif_set_down(netif);
  }
       
}
回复 支持 反对

使用道具 举报

28

主题

294

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1790
金钱
1790
注册时间
2018-3-26
在线时间
294 小时
发表于 2020-10-29 18:06:56 | 显示全部楼层
xiongliangxcl 发表于 2020-5-9 20:11
uint16_t        link_status_new = 0;
uint16_t        link_status_old = 0;

为啥不管我插不插网线,都进不去这个判断
  1. if((ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR)) & PHY_Linked_Status)
复制代码
茵茵猪头
回复 支持 反对

使用道具 举报

9

主题

30

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
223
金钱
223
注册时间
2014-5-2
在线时间
49 小时
发表于 2020-11-24 20:30:11 | 显示全部楼层
春春的阳光 发表于 2019-3-28 16:56
1楼所附代码是使用HAL库情况下写的,同样需要在lwip_comm_init()中把循环执行LAN8720_init( )改为一次。在 ...

由systick中断时间决定的,如果是设置1ms中断一次(刚好freertos默认就是1ms切换线程),那就是5s,估计st编写库的人,也是按默认1ms来定义这个宏的
回复 支持 反对

使用道具 举报

9

主题

30

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
223
金钱
223
注册时间
2014-5-2
在线时间
49 小时
发表于 2020-11-24 20:31:28 | 显示全部楼层
htao 发表于 2020-10-29 18:06
为啥不管我插不插网线,都进不去这个判断

多加几个printf就知道是卡在哪里就退出了没执行到这里
回复 支持 反对

使用道具 举报

28

主题

294

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1790
金钱
1790
注册时间
2018-3-26
在线时间
294 小时
发表于 2020-11-25 08:59:01 | 显示全部楼层
yinshiyouquan 发表于 2020-11-24 20:31
多加几个printf就知道是卡在哪里就退出了没执行到这里

找到问题了,和串口2 的引脚冲突了
茵茵猪头
回复 支持 反对

使用道具 举报

9

主题

30

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
223
金钱
223
注册时间
2014-5-2
在线时间
49 小时
发表于 2020-11-26 01:38:34 | 显示全部楼层
louzhulz 发表于 2020-8-19 09:03
使用cubemax生成的LWIP,解决这个问题很简单。
使能回调函数,为解决热拔插网线问题(包括上电后插网线或 ...

lwip没有被初始化,你调用netif_set_up会告诉你netif指针未被分配空间,楼主方法是可行的,但是要再优化
回复 支持 反对

使用道具 举报

2

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
97
金钱
97
注册时间
2019-5-19
在线时间
23 小时
发表于 2020-12-16 16:11:58 | 显示全部楼层
louzhulz 发表于 2020-8-19 09:03
使用cubemax生成的LWIP,解决这个问题很简单。
使能回调函数,为解决热拔插网线问题(包括上电后插网线或 ...

这个很好用。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-24 15:43

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表