admin管理员组

文章数量:1530846

开发背景: 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 (&ETH_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 */ void netif_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 */ void eth_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网线热插入网络不通遇到的问题以及解决办法介绍完毕。


-xuk

本文标签: 网线解决办法网络lwIP