| 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,会出错)
 
[mw_shl_code=c,true]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);  
	//==============================================================================
	[/mw_shl_code]
 
[mw_shl_code=c,true]//==================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);
  }
}
[/mw_shl_code]
 轮询方案
 
 
[mw_shl_code=c,true]/**********************************************************
?????????? ???????í????×???  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);		
	
}	
[/mw_shl_code]
 
 
 
 
 |