STM32移植LWIP网线热插入网络不通的解决办法

发布者:美丽花朵最新更新时间:2018-04-22 来源: eefocus关键字:STM32  移植  LWIP网线  热插入网络 手机看文章 扫描二维码
随时随地手机看文章

开发背景:

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网线热插入网络不通遇到的问题以及解决办法介绍完毕。


关键字:STM32  移植  LWIP网线  热插入网络 引用地址:STM32移植LWIP网线热插入网络不通的解决办法

上一篇:STM32F4 LAN8720以及LWIP的移植调试记录 (3)
下一篇:stm32CubeMX上lwip的配置问题

推荐阅读最新更新时间:2024-03-16 16:00

世界上首例永久人工心脏移植患者术后75天死亡
    日前在法国乔治斯蓬皮杜欧洲医院接受世界上第一例真正意义上的人工心脏移植的患者在术后75天后死亡。医生表示目前还未查明死因。     该款人工心脏是模拟心脏工作原理和泵血功能。心脏靠外部锂电池供电,利用牛组织与主动脉连接。     该设备是由法国的Carmat设计的,设计目标是为那些没有供体进行心脏移植,或者年龄偏高的需要心脏移植的患者。     研发人员希望这款设备能够永久替代心脏,而不是暂时作为替代品。虽然第一位患者死亡,但是Carmat公司希望这款设备能进行更多的临床试验。     在经过临床试验后,Carmat公司的目标是让更多有心脏移植需求的患者用上人工心脏。查明死亡的75岁老人的死因将
[医疗电子]
STM32_固件库操作LED灯
流水灯,几乎是每种开发板第一个接触的实验,简单而又不可少。 今天,小编简要说明一下如何使用固件库操作LED灯。 硬件连接: 软件设计: void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; // 1,使能GPIO对应引脚时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOG ,ENABLE); // 2,定义GPIO引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出 GPIO_InitStructure.GP
[单片机]
STM32_固件库操作LED灯
基于语音识别汽车空调控制系统设计
  现在汽车上使用的电器越来越多,驾驶员需要手动操作的电器开关也越来越多,不但增加了驾驶员的负担,还影响了行车安全。本文以STM32F103VET6(以下简称STM32)芯片为控制核心,采用高性能LD3320语音识别芯片,设计基于语音识别的汽车空调控制系统。该系统可以用语音有效控制汽车空调,减轻了驾驶员的操作负担,保证行车过程中的安全。   1 系统硬件设计   运用语音识别技术,结合各种传感器对车身内外的环境(如气温、阳光强度等)以及制冷压缩机的状态等多种参数进行实时检测,与设定参数相比较,微控制器经过运算处理做出判断,输出相应的调节和控制信号。执行机构经过实时调整和修正,实现对车厢内空气环境全方位、多功能的调节和控制。系统
[单片机]
基于语音识别汽车空调控制系统设计
I.MX6Q(TQIMX6Q/TQE9)学习笔记——新版BSP之kernel移植
前篇文章已经在tqimx6q上成功跑起了新版BSP的uboot,本文来配置下新版BSP的kernel,使kernel能在tqimx6q上正常启动。 准备工作 每次移植kernel的时候都会做的工作就是找到与当前开发板接近的config,其实uboot移植的时候也是一样的。由于tqimx6q的芯片是imx6q的,所以,还是以mx6q_sabresd为例。另外,自己动手移植BSP时应该充分使用官方文档,本人以为,以下文档是非常有用的: (1) i.MX 6 BSP Porting Guide: 该文档详细的记载了BSP移植的流程。 (2) i.MX 6 SABRE-SD Linux User's Guide:
[单片机]
STM32控制两个舵机
原理:一个定时器的两路PWM输出 参考:正点原子代码 timer.c代码 void TIM5_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);//使能定时器5时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2P
[单片机]
8051单片机和STM32单片机的编程环境对比
单片机编程是一门实战性的技术,程序要在单片机平台上跑起来才能看到效果、才能积累编程经验。在学校学习单片机课程时,可能会感觉到一直有一种脱节的感觉,因为一直没有用武之地。其实学习单片机很简单,第一步就是搞清楚编程环境。 入门单片机时,我们常用51型8051单片机和STM32单片机。这两种单片机比较典型,因为学校里单片机课程是基于51单片机的,而STM32的单片机则具有较多的学习资料。下面就这两种单片机介绍一下编程环境。 1、单片机常用的编程环境 比较流行的单片机环境有keil和IAR,这两种环境可以覆盖市面上90%的单片机型号,而且都提供了函数库。根据单片机位数不同,这两个编程环境也有不同的版本。 1.1 Keil的常用版本
[单片机]
8051单片机和<font color='red'>STM32</font>单片机的编程环境对比
ARM硬件平台上基于UCOS移植Lwip网络协议栈
目录 1硬件平台 1 1.1硬件平台简介 1 1.2 硬件设计及电路原理图 2 2. Keil 开发工具及Keil工程简介 6 2.1 Keil开发工具 6 2.2 Keil工程简介 6 2.3 链接文件、启动文件分析 6 3. UCOS移植 11 3.1 ucos简介 11 3.2 ucos移植总述 11 3.3 和移植UCOS有关的ARM芯片知识 11 3.4 系统堆栈和UCOS的任务堆栈 14 3.5 系统时钟 14 3.6 任务级任务切换 14 3.7 中断级任务切换 16 4.Lwip移植 18 4.1 lwip简介 18 4.2 lwip移植总述 18 4.3移植lwip操作系统模拟层 19 4.4 根据l
[单片机]
ARM硬件平台上基于UCOS<font color='red'>移植</font><font color='red'>Lwip</font><font color='red'>网络</font>协议栈
意法半导体新型STM32系列获ARM RealView微控制器开发工具包支持
中国上海,2007年6月27日 —— ARM公司(伦敦证交所:ARM;纳斯达克:ARMHY)宣布即日起,RealView微控制器开发工具包将支持意法半导体基于ARM Cortex-M3处理器的全新 STM32F1xx系列器件。    STM32F101 (接入行)和STM32F103 (性能行)将是意法半导体首个基于ARM Cortex-M3处理器的器件系列,兼具卓越的高性能和低功耗,待机功耗仅为2?A。该系列器件拥有高达72MHz的CPU时钟速度、128Kbyte片上闪存ROM及20Kbyte片上RAM,还包括A/D、CAN、USB、SPI、I2C等众多外设及多达80个GPIO。    RealView微控制器开发工具包3.1可
[新品]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved