android 以太网 热插拔,网口热插拔调试过程分享!

本文是一位STM32和lwip初学者分享的关于网口热插拔功能的调试经验。在尝试使用中断方式通过LAN8720 PHY芯片检测网线插拔状态失败后,作者转向了轮询方案。通过创建低优先级任务定期检查链路状态,实现了网口动态连接和断开的正确处理。在中断方案中,作者遇到了中断状态与实际连接状态不符的问题,而在轮询方案中,问题得到了解决,实现了对MAC和DMA的正确初始化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

STM32和lwip初学者,分享一下网口热插拔功能调试过程。

PHY芯片使用的lan8720,使用原子哥的lwip扩展例程,原例程初始化LAN8720后是死等。实际项目中网口初始可能不插网线,中途插拔网线等,因此对程序进行修改。

1)先是参考ST官方以太网库,最新版以太网库为2015年5月份(keil5中software packs中下载,或到keil官网下载较快),在此库中采用了外部中断的方式判断网口插拔状态。由于LAN8720的中断口和CLKOUT复用,因此使用中断,只能使用50MHZ方案。电路按照50MHZ更改后。参照官网实现思路,添加程序到工程中。结果发现插拔网口能够检测到中断,但是检测的状态始终是link_down. 苦苦寻找原因,未果。最终放弃中断方式,采用轮询方案。

2)轮询方案的思路是,建立一个低优先级任务,每隔一段时间检测link状态,如果程序运行第一次检测,检测结果为连接,则将该任务挂起。如果第一次检测为断开,则程序会继续检测,直到检测到连接,则对MAC和DMA重新做一遍初始化。经过调试该方法可行。

附中断方案:(调试未成功,主要原因为中断中检测link状态与实际不符,另ST官网例程检测到网口重新连接后只进行了MAC的重新初始化,未进行DMA初始化,经过实验,发现初始化MAC和DMA才正常,只初始化MAC,会出错)[C] 纯文本查看 复制代码

ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;  //????DMA?????????·????????ETH_InitStructure.ETH_Fixedburst = ETH_FixedBurst_Enable;            //???????¨??·?????    ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;     //DMA·?????×??ó??·??¤????32??????   ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;//DMA??????×??ó??·??¤????32??????ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;rval=ETH_Init(Ð_InitStructure,LAN8720_PHY_ADDRESS);//????ETH//=======2015/07/08  added by sucore ????????°????í???ò========================//?ù??ST??·???????????????????IF( rval ==  ETH_ERROR )    {        printf(\"ETH init error, may be no link\n\");    }   EthStatus=rval;      if(ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR) & 4)  {    EthStatus |= ETH_LINK_FLAG;  }  /* Configure the PHY to generate an interrupt on change of link status */  Eth_Link_PHYITConfig(LAN8720_PHY_ADDRESS);    /* Configure the EXTI for Ethernet link status. */  Eth_Link_EXTIConfig();    /* Enable the Ethernet Rx Interrupt */  ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R , ENABLE);  //==============================================================================[C] 纯文本查看 复制代码

//==================2015/07/08 added by sucore ================================//==================????????°??à?????í????=====================================/**   * @brief  Configure the PHY to generate an interrupt on change of link status.  * @param PHYAddress: external PHY address    * @retval None  */uint32_t Eth_Link_PHYITConfig(uint16_t PHYAddress){  uint32_t tmpreg = 0;  /* Read MASK register */  tmpreg = ETH_ReadPHYRegister(PHYAddress, PHY_MASK);  /* Enable output interrupt events to signal via the INT pin */  tmpreg |= (uint32_t)PHY_MASK_LINK_INT_EN | PHY_MASK_ENERGYON_INT_EN;  if(!(ETH_WritePHYRegister(PHYAddress, PHY_MASK, tmpreg)))  {    /* Return ERROR in case of write timeout */    return ETH_ERROR;  }  /* Read INT register */  tmpreg = ETH_ReadPHYRegister(PHYAddress, PHY_INT);  /* Enable Interrupt on change of link status */  tmpreg |= (uint32_t)PHY_INT_LINK_STATUS|PHY_INT_ENERGYON_STATUS;  if(!(ETH_WritePHYRegister(PHYAddress, PHY_INT, tmpreg)))  {    /* Return ERROR in case of write timeout */    return ETH_ERROR;  }  /* Return SUCCESS */  return ETH_SUCCESS;   }//==================2015/07/08 added by sucore ================================//==================????????°??à?????í????=====================================/**  * @brief  EXTI configuration for Ethernet link status.  * @param PHYAddress: external PHY address    * @retval None  */void Eth_Link_EXTIConfig(void){  GPIO_InitTypeDef GPIO_InitStructure;  EXTI_InitTypeDef EXTI_InitStructure;  NVIC_InitTypeDef NVIC_InitStructure;  /* Enable the INT (PB14) clock */  RCC_AHB1PeriphClockCmd(ETH_LINK_GPIO_CLK, ENABLE);  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);  /* Configure INT pin as input */  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  GPIO_InitStructure.GPIO_Pin = ETH_LINK_PIN;  GPIO_Init(ETH_LINK_GPIO_PORT, &GPIO_InitStructure);  /* Connect EXTI Line to INT Pin */  SYSCFG_EXTILineConfig(ETH_LINK_EXTI_PORT_SOURCE, ETH_LINK_EXTI_PIN_SOURCE);  /* Configure EXTI line */  EXTI_InitStructure.EXTI_Line = ETH_LINK_EXTI_LINE;  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;  EXTI_InitStructure.EXTI_trigger = EXTI_Trigger_Falling;    EXTI_InitStructure.EXTI_LineCmd = ENABLE;  EXTI_Init(&EXTI_InitStructure);  /* Enable and set the EXTI interrupt to priority 1*/  NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  NVIC_Init(&NVIC_InitStructure);}//==================2015/07/08 added by sucore ================================//==================????????°??à?????í????=====================================/**  * @brief  This function handles Ethernet link status.  * @param  None  * @retval None  */void Eth_Link_ITHandler(uint16_t PHYAddress){u32 temp;//OS_CPU_SR cpu_sr;//OS_ENTER_CRITICAL();  /* Check whether the link interrupt has occurred or not */  if( ((ETH_ReadPHYRegister(PHYAddress, PHY_INT)) & PHY_INT_LINK_STATUS)!= 0)  {  delay_ms(1);temp=(ETH_ReadPHYRegister(PHYAddress, PHY_BSR) & 4);    if(temp)    {      netif_set_link_up(&lwip_netif);    }    else    {      netif_set_link_down(&lwip_netif);    }  }//OS_EXIT_CRITICAL();}//==================2015/07/08 added by sucore ================================//==================????????°??à?????í????=====================================/**  * @brief  This function handles External line 10 interrupt request.  * @param  None  * @retval None  */void EXTI15_10_IRQHandler(void){  if(EXTI_GetITStatus(ETH_LINK_EXTI_LINE) != RESET)  {    Eth_Link_ITHandler(LAN8720_PHY_ADDRESS);   // ETH_Init(Ð_InitStructure,LAN8720_PHY_ADDRESS);/* Clear interrupt pending bit */    EXTI_ClearITPendingBit(ETH_LINK_EXTI_LINE);  }}

轮询方案

[C] 纯文本查看 复制代码

/**********************************************************?????????? ???????í????×???  2015/07/11   added by sucore?????????? ???????????? ×?????   0????   1???????????÷?? ??**********************************************************/u8 netlink_status_check(void){ // u32 temp=0;    static u32 cursta,presta;  static u8 cnt;  //u8 retval;   cursta=(ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR) & 4); cnt++;   if(cursta!=presta)   {    if(cnt!=1) {  if(cursta) { netif_set_link_up(&lwip_netif); } else { netif_set_link_down(&lwip_netif); } }         else         {;}  cnt=2;   } else {cnt=2;}     presta=cursta;return  cursta;}void  netlink_task(void *pdata){  OS_CPU_SR cpu_sr;static u8 sta=0;  while(1)  {  //u32 temp;    OSTimeDlyHMSM(0,0,2,500);    /* Check whether the link interrupt has occurred or not */  OS_ENTER_CRITICAL();  if(netlink_status_check()){ sta=1;}OS_EXIT_CRITICAL();if(sta) break;}   OSTaskSuspend(OS_PRIO_SELF); OSTimeDlyHMSM(0,0,0,500);}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值