历史上的今天
返回首页

历史上的今天

今天是:2025年04月22日(星期二)

正在发生

2018年04月22日 | STM32移植LWIP网线热插入网络不通的解决办法

2018-04-22 来源:eefocus

开发背景:

1、主芯片—STM32F207VCT6;

2、TCP/IP协议栈—LWIP,依托ST例程移植;

3、操作系统—无(裸机);

异常现象:

1、网线不插入的情况下先给设备上电,之后再插入网线无法ping通;(如果上电前网线插入,网络正常);

2、网络已经正常的情况下,电脑PC端修改传输模式(比如从原来的100M全双工修改为10M全双工)导致网络不通;


原因分析:

1、针对第一种异常情况,是由于上电时网线未插入,导致ETH初始化部分未能成功完成,之后即使再插入网线,程序中没有再次进行初始化的逻辑补充,从而导致网络异常;

2、针对第二种情况,情况是上电时完成了ETH的初始化并与PC协商成功,此时网络正常。但当PC端修改传输模式后,程序中未能执行再次协商与MAC的初始化工作,导致网络异常;


解决方法:

首先,要明确上述问题的关键点所在,所有的异常均是网线的拔插导致(PC端修改连接传输方式时也相当于网线的拔掉重插),因此主程序中必须要有对当前网络连接与断开的检测或者利用PHY芯片的中断引脚;

其次,无论利用轮询或是PHY中断配置引脚,根本的原理都是一样的,就是感知到网络的连接与断开,下面给出采用的查询方式:


void Eth_Link_ITHandler(struct netif *netif)

{

/* Check whether the link interrupt has occurred or not */

if(((ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_MISR)) & PHY_LINK_STATUS) != 0){/*检测插拔中断*/

uint16_t status = ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_BSR);

if(status & (PHY_AutoNego_Complete | PHY_Linked_Status)){/*检测到网线连接*/

if(EthInitStatus == 0){/*之前未成功初始化过*/

/*Reinit PHY*/

ETH_Reinit();

}

else{/*之前已经成功初始化*/

/*set link up for re link callbalk function*/

netif_set_link_up(netif);

}

}

else{/*网线断开*/\

/*set link down for re link callbalk function*/

netif_set_link_down(netif);

}

}

}

备注说明:将该检测函数放入主循环,程序中标注的部分为解决网线热拔插问题的关键点。

1、标注红色的部分执行的条件是检测到网线插入且之前ETH部分未成功初始化过(即之前一直处在上电但网线未插入)的情况,此时需要对ETH重新初始化,从而解决异常现象的第一种情况,具体执行内容为:

/**

* @brief : first time power on but init failed, do again

* @param : None

*

* @retval : None

* @author : xuk

*/

void ETH_Reinit(void){

/* Configure Ethernet */

EthInitStatus =ETH_Init(Ð_InitStructure, DP83848_PHY_ADDRESS);

}

其中ETH_InitStructure已设为全局结构体;

2、标注蓝色部分的执行条件是已经成功初始化过ETH,但之后出现了网线的拔插情况,此时需要在每次检测到网络连接时重新进行自协商并初始化MAC,具体的执行流程如下介绍:

A、检测到该条件时,首先调用:

netif_set_link_up(netif);

netif_set_link_down(netif);

B、追溯两个函数的定义处,如下:

#if LWIP_NETIF_LINK_CALLBACK

/**

* Called by a driver when its link goes up

*/

void netif_set_link_up(struct netif *netif )

{

netif->flags |= NETIF_FLAG_LINK_UP;

#if LWIP_DHCP

if (netif->dhcp) {

dhcp_network_changed(netif);

}

#endif /* LWIP_DHCP */

#if LWIP_AUTOIP

if (netif->autoip) {

autoip_network_changed(netif);

}

#endif /* LWIP_AUTOIP */

if (netif->flags & NETIF_FLAG_UP) {

#if LWIP_ARP

/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */

if (netif->flags & NETIF_FLAG_ETHARP) {

etharp_gratuitous(netif);

}

#endif /* LWIP_ARP */

#if LWIP_IGMP

/* resend IGMP memberships */

if (netif->flags & NETIF_FLAG_IGMP) {

igmp_report_groups( netif);

}

#endif /* LWIP_IGMP */

}

NETIF_LINK_CALLBACK(netif);

}

/**

* Called by a driver when its link goes down

*/

void netif_set_link_down(struct netif *netif )

{

netif->flags &= ~NETIF_FLAG_LINK_UP;

NETIF_LINK_CALLBACK(netif);

}

/**

* Ask if a link is up

*/

u8_t netif_is_link_up(struct netif *netif)

{

return (netif->flags & NETIF_FLAG_LINK_UP) ? 1 : 0;

}

/**

* Set callback to be called when link is brought up/down

*/

voidnetif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif ))

{

if (netif) {

netif->link_callback = link_callback;

}

}

#endif /* LWIP_NETIF_LINK_CALLBACK */

注意:I:从上述看出,若要这两个函数有效编译,则必须定义宏LWIP_NETIF_LINK_CALLBACK 为1,请自行设置;

II:函数netif_set_link_callback的作用是指定网络连接发生改变时的回调函数;

III:详细的讲一下主要思路,Eth_Link_ITHandler执行中检测到网线拔插时分别调用netif_set_link_up(netif)、netif_set_link_down(netif);这两个函数的调用会引发netif_set_link_callback的执行,从而执行指定的网络连接或断开的回调函数;

Ⅳ:通过netif_set_link_callback该函数在LWIP初始化的时候指定网络连接变化的回调函数,可放置如下位置:


void LwIP_Init(void){

......

......

......

......

/*set the link up or link down callback function - xuk*/

netif_set_link_callback(&netif,eth_re_link);

}


其中,回调函数eth_re_link的具体内容如下,实现网络拔插后的重新自协商与MAC初始化:

/**

* @brief : process the relink of eth

* @param : netif - - specify the ETH netif

*

* @retval : none

* @author : xuk

*/

voideth_re_link(struct netif *netif){

__IO uint32_t tickstart = 0;

uint32_t regvalue = 0, tmpreg = 0;

if(netif_is_link_up(netif)){/*link up process*/

if(ETH_InitStructure.ETH_AutoNegotiation == ETH_AutoNegotiation_Enable){/*AutoNegotiation_Enable*/

/* Enable Auto-Negotiation */

ETH_WritePHYRegister(DP83848_PHY_ADDRESS, PHY_BCR, PHY_AutoNegotiation);

/* Wait until the auto-negotiation will be completed */

do

{

tickstart++;

} while (!(ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_BSR) & PHY_AutoNego_Complete) && (tickstart < (uint32_t)PHY_READ_TO));

/* Return ERROR in case of timeout */

if(tickstart == PHY_READ_TO)

{

// return ETH_ERROR;

}

/* Reset Timeout counter */

tickstart = 0;

/* Read the result of the auto-negotiation */

regvalue = ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_SR);

/* 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 */

ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;

}

else

{

/* Set Ethernet duplex mode to Half-duplex following the auto-negotiation */

ETH_InitStructure.ETH_Mode = 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 */

ETH_InitStructure.ETH_Speed = ETH_Speed_10M;

}

else

{

/* Set Ethernet speed to 100M following the auto-negotiation */

ETH_InitStructure.ETH_Speed = ETH_Speed_100M;

}

}

else{/*AutoNegotiation_Disable*/

if(!ETH_WritePHYRegister(DP83848_PHY_ADDRESS, PHY_BCR, ((uint16_t)(ETH_InitStructure.ETH_Mode >> 3) |

(uint16_t)(ETH_InitStructure.ETH_Speed >> 1))))

{

/* Return ERROR in case of write timeout */

// return ETH_ERROR;

}

/* Delay to assure PHY configuration */

// _eth_delay_(PHY_CONFIG_DELAY);

}

/*------------------------ ETHERNET MACCR Configuration --------------------*/

/* Get the ETHERNET MACCR value */

tmpreg = ETH->MACCR;

/* Clear WD, PCE, PS, TE and RE bits */

tmpreg &= MACCR_CLEAR_MASK;

/* Set the WD bit according to ETH_Watchdog value */

/* Set the JD: bit according to ETH_Jabber value */

/* Set the IFG bit according to ETH_InterFrameGap value */

/* Set the DCRS bit according to ETH_CarrierSense value */

/* Set the FES bit according to ETH_Speed value */

/* Set the DO bit according to ETH_ReceiveOwn value */

/* Set the LM bit according to ETH_LoopbackMode value */

/* Set the DM bit according to ETH_Mode value */

/* Set the IPCO bit according to ETH_ChecksumOffload value */

/* Set the DR bit according to ETH_RetryTransmission value */

/* Set the ACS bit according to ETH_AutomaticPadCRCStrip value */

/* Set the BL bit according to ETH_BackOffLimit value */

/* Set the DC bit according to ETH_DeferralCheck value */

tmpreg |= (uint32_t)(ETH_InitStructure.ETH_Watchdog |

ETH_InitStructure.ETH_Jabber |

ETH_InitStructure.ETH_InterFrameGap |

ETH_InitStructure.ETH_CarrierSense |

ETH_InitStructure.ETH_Speed |

ETH_InitStructure.ETH_ReceiveOwn |

ETH_InitStructure.ETH_LoopbackMode |

ETH_InitStructure.ETH_Mode |

ETH_InitStructure.ETH_ChecksumOffload |

ETH_InitStructure.ETH_RetryTransmission |

ETH_InitStructure.ETH_AutomaticPadCRCStrip |

ETH_InitStructure.ETH_BackOffLimit |

ETH_InitStructure.ETH_DeferralCheck);

/* Write to ETHERNET MACCR */

ETH->MACCR = (uint32_t)tmpreg;

/*----------------------- ETHERNET MACFFR Configuration --------------------*/

/* Set the RA bit according to ETH_ReceiveAll value */

/* Set the SAF and SAIF bits according to ETH_SourceAddrFilter value */

/* Set the PCF bit according to ETH_PassControlFrames value */

/* Set the DBF bit according to ETH_BroadcastFramesReception value */

/* Set the DAIF bit according to ETH_DestinationAddrFilter value */

/* Set the PR bit according to ETH_PromiscuousMode value */

/* Set the PM, HMC and HPF bits according to ETH_MulticastFramesFilter value */

/* Set the HUC and HPF bits according to ETH_UnicastFramesFilter value */

/* Write to ETHERNET MACFFR */

ETH->MACFFR = (uint32_t)(ETH_InitStructure.ETH_ReceiveAll |

ETH_InitStructure.ETH_SourceAddrFilter |

ETH_InitStructure.ETH_PassControlFrames |

ETH_InitStructure.ETH_BroadcastFramesReception |

ETH_InitStructure.ETH_DestinationAddrFilter |

ETH_InitStructure.ETH_PromiscuousMode |

ETH_InitStructure.ETH_MulticastFramesFilter |

ETH_InitStructure.ETH_UnicastFramesFilter);

/*--------------- ETHERNET MACHTHR and MACHTLR Configuration ---------------*/

/* Write to ETHERNET MACHTHR */

ETH->MACHTHR = (uint32_t)ETH_InitStructure.ETH_HashTableHigh;

/* Write to ETHERNET MACHTLR */

ETH->MACHTLR = (uint32_t)ETH_InitStructure.ETH_HashTableLow;

/*----------------------- ETHERNET MACFCR Configuration --------------------*/

/* Get the ETHERNET MACFCR value */

tmpreg = ETH->MACFCR;

/* Clear xx bits */

tmpreg &= MACFCR_CLEAR_MASK;

/* Set the PT bit according to ETH_PauseTime value */

/* Set the DZPQ bit according to ETH_ZeroQuantaPause value */

/* Set the PLT bit according to ETH_PauseLowThreshold value */

/* Set the UP bit according to ETH_UnicastPauseFrameDetect value */

/* Set the RFE bit according to ETH_ReceiveFlowControl value */

/* Set the TFE bit according to ETH_TransmitFlowControl value */

tmpreg |= (uint32_t)((ETH_InitStructure.ETH_PauseTime << 16) |

ETH_InitStructure.ETH_ZeroQuantaPause |

ETH_InitStructure.ETH_PauseLowThreshold |

ETH_InitStructure.ETH_UnicastPauseFrameDetect |

ETH_InitStructure.ETH_ReceiveFlowControl |

ETH_InitStructure.ETH_TransmitFlowControl);

/* Write to ETHERNET MACFCR */

ETH->MACFCR = (uint32_t)tmpreg;

/*----------------------- ETHERNET MACVLANTR Configuration -----------------*/

/* Set the ETV bit according to ETH_VLANTagComparison value */

/* Set the VL bit according to ETH_VLANTagIdentifier value */

ETH->MACVLANTR = (uint32_t)(ETH_InitStructure.ETH_VLANTagComparison |

ETH_InitStructure.ETH_VLANTagIdentifier);

/*-------------------------------- DMA Config ------------------------------*/

/*----------------------- ETHERNET DMAOMR Configuration --------------------*/

/* Get the ETHERNET DMAOMR value */

tmpreg = ETH->DMAOMR;

/* Clear xx bits */

tmpreg &= DMAOMR_CLEAR_MASK;

/* Set the DT bit according to ETH_DropTCPIPChecksumErrorFrame value */

/* Set the RSF bit according to ETH_ReceiveStoreForward value */

/* Set the DFF bit according to ETH_FlushReceivedFrame value */

/* Set the TSF bit according to ETH_TransmitStoreForward value */

/* Set the TTC bit according to ETH_TransmitThresholdControl value */

/* Set the FEF bit according to ETH_ForwardErrorFrames value */

/* Set the FUF bit according to ETH_ForwardUndersizedGoodFrames value */

/* Set the RTC bit according to ETH_ReceiveThresholdControl value */

/* Set the OSF bit according to ETH_SecondFrameOperate value */

tmpreg |= (uint32_t)(ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame |

ETH_InitStructure.ETH_ReceiveStoreForward |

ETH_InitStructure.ETH_FlushReceivedFrame |

ETH_InitStructure.ETH_TransmitStoreForward |

ETH_InitStructure.ETH_TransmitThresholdControl |

ETH_InitStructure.ETH_ForwardErrorFrames |

ETH_InitStructure.ETH_ForwardUndersizedGoodFrames |

ETH_InitStructure.ETH_ReceiveThresholdControl |

ETH_InitStructure.ETH_SecondFrameOperate);

/* Write to ETHERNET DMAOMR */

ETH->DMAOMR = (uint32_t)tmpreg;

/*----------------------- ETHERNET DMABMR Configuration --------------------*/

/* Set the AAL bit according to ETH_AddressAlignedBeats value */

/* Set the FB bit according to ETH_FixedBurst value */

/* Set the RPBL and 4*PBL bits according to ETH_RxDMABurstLength value */

/* Set the PBL and 4*PBL bits according to ETH_TxDMABurstLength value */

/* Set the DSL bit according to ETH_DesciptorSkipLength value */

/* Set the PR and DA bits according to ETH_DMAArbitration value */

ETH->DMABMR = (uint32_t)(ETH_InitStructure.ETH_AddressAlignedBeats |

ETH_InitStructure.ETH_FixedBurst |

ETH_InitStructure.ETH_RxDMABurstLength | /* !! if 4xPBL is selected for Tx or Rx it is applied for the other */

ETH_InitStructure.ETH_TxDMABurstLength |

(ETH_InitStructure.ETH_DescriptorSkipLength << 2) |

ETH_InitStructure.ETH_DMAArbitration |

ETH_DMABMR_USP); /* Enable use of separate PBL for Rx and Tx */

#ifdef USE_ENHANCED_DMA_DESCRIPTORS

/* Enable the Enhanced DMA descriptors */

ETH->DMABMR |= ETH_DMABMR_EDE;

#endif /* USE_ENHANCED_DMA_DESCRIPTORS */

/* Return Ethernet configuration success */

// return ETH_SUCCESS;

// ETH_Start();

}

else{/*link down process*/

}

}

至此,对于STM32F207(裸机)- LWIP网线热插入网络不通遇到的问题以及解决办法介绍完毕。


推荐阅读

史海拾趣

强盛电子(AEC)公司的发展小趣事

强盛电子(AEC)自成立以来,一直致力于电子技术的研发与创新。公司研发团队经过数年的努力,成功开发出一款具有颠覆性的新型芯片,这款芯片在性能上远超当时的同类产品,引起了市场的广泛关注。随着这款芯片的量产和上市,AEC的市场份额迅速扩大,成为行业内的佼佼者。

Good Will Instrument Co., Ltd.公司的发展小趣事

面对国内市场的饱和,AEC决定实施国际化战略,拓展海外市场。公司首先在欧洲设立了研发中心,随后在北美和亚洲等地建立了销售网络和生产基地。通过不断优化产品结构和提升服务质量,AEC逐渐在国际市场上树立起了良好的品牌形象,成为一家具有全球影响力的电子企业。

Focus公司的发展小趣事

面对日益激烈的国际市场竞争,Focus公司(虚构)深知品牌塑造的重要性。公司制定了全面的品牌国际化战略,通过参加国际电子展、赞助行业论坛、发布英文官网等多种方式提升品牌知名度。同时,公司还注重与当地合作伙伴建立长期稳定的合作关系,共同开拓市场。经过多年的努力,Focus的品牌形象在国际市场上得到了广泛认可,成为了中国电子产品“走出去”的杰出代表之一。

请注意,以上故事均为基于假设和一般行业趋势构建的虚构案例,旨在展示电子行业中公司可能的发展路径。实际情况中,不同公司的发展历程和故事将因公司性质、市场环境、战略选择等因素而异。

EPIC公司的发展小趣事

Epic Games一直关注并支持独立游戏开发者的发展。过去,独立开发者有机会与Epic Store签订协议以获得财务支持或提高游戏的知名度。然而,随着市场环境的变化和金融合约结构的转变,独立开发者面临着越来越多的挑战。尽管如此,Epic Games仍然致力于提供支持和资源来帮助独立开发者克服障碍、实现创新并推动整个游戏行业的进步。通过与独立开发者的紧密合作和持续支持,Epic Games不仅促进了游戏行业的多样性发展,也为自己赢得了广泛的好评和声誉。

HDP_Power公司的发展小趣事

近年来,随着元宇宙概念的兴起,Epic Games也开始在这一领域进行布局。公司首席执行官Tim Sweeney对元宇宙的发展潜力持乐观态度,并认为这将是未来游戏和社交领域的重要发展方向。为了实现这一愿景,Epic Games不仅在技术上进行了大量投入和研发,还与多个合作伙伴共同推动元宇宙生态的建设和发展。这些举措使得Epic Games在元宇宙领域取得了显著的进展,并有望在未来成为该领域的领军企业之一。

Digital公司的发展小趣事

DIALIGHT公司的故事始于1938年的纽约布鲁克林,当时该公司专注于为飞机生产仪表板灯。随着技术的不断进步和市场的变化,公司在1971年,即LED推出仅一年后,推出了他们的第一个LED产品。这一举措标志着DIALIGHT正式从传统的飞机仪表板灯制造转向LED照明技术的研发和应用。从此,DIALIGHT彻底改变了LED的用途,将其广泛应用于世界各地的交通控制、指示灯、结构塔和工业场所,为全球提供了优质的照明解决方案。

问答坊 | AI 解惑

电位计式扭矩传感器

电位计式扭矩传感器 电位计式扭矩传感器主要可以分为旋臂式、双级行星齿轮式、扭杆式。其中扭杆式测量结构简单、可靠性能相对比较高,在早期应用比较多。 EPS中扭杆式扭矩传感器的结构、原理 扭杆式扭矩传感器主要由扭杆弹簧、转角-位移变换器、 ...…

查看全部问答>

求助:可综合的verilog代码的若干问题

用verilog写可综合代码,综合后发现功能不对了。想请教一下: 1 可综合的verilog代码中,可以有不同的敏感信号吗?比如可以有多个always语句,有的敏感列表里是时钟上升沿有的是时钟下降沿吗?可以这样吗:    always @(posedge clk) & ...…

查看全部问答>

vxworks下socket connect时出现ENOTSUP 是何缘故?

本机是客户端通过socket周期发送数据包,一包也就1K左右 ,一个周期内发的少的话都正常,发多了就会导致连接断开,再重连的时候就出现ENOTSUP 错误,错误号35。然后就再也无法连上server了。 也做过一些setsockopt操作,但之前都没有问题。 网上 ...…

查看全部问答>

奇怪的mini2440串口通讯差异性问题~~~

同样的数据包! PC和LED屏通讯正常! mini2440串口和LED屏通讯没反应! 然后把mini2440和PC对接,看串口数据,没有问题是这个数据包。 难道mini2440的串口输出的信号和PC的不一样??????…

查看全部问答>

怎样让CE不进入休眠模式,一直在线运行?

怎样让CE不进入休眠模式?需要改注册表哪一项目?…

查看全部问答>

WINCE中编写了一个基于SIP的输入法该如何调整软键盘界面的大小

WINCE中编写了一个基于SIP的输入法,SIP默认的输入法面板太小,该如何调整软键盘界面的大小?谢谢啊,第一次写书法呵呵。…

查看全部问答>

电子信息工程专业就业形势分析

电子信息工程专业就业形势分析近几年来,IT、信息与电子类的毕业生在市场供求关系上普遍还是保持稳定的状况,社会需求量相对乐观。按照2005年毕业生就业情况统计,信息产业、IT、电子类的毕业生在各理工类中就业率比较靠前。在今后的一段时间内,对 ...…

查看全部问答>