STM32F207+DP83848+RT-THREAD实现网线拔插重连试验

来源:互联网 发布:阿里云系统强制升级 编辑:程序博客网 时间:2024/06/18 14:27

我在刚开始遇到这个问题的时候,上网搜了下,讲得都不是很清楚。不非是重新初始化重新初始化MAC,但是都是在文字表面。下面直接上代码,附上的代码是自己测试通过的。

1、通过DP83848配置为link状态变化,相应管教会有电平变化(具体看手册),从而触发STM32外部中断,通知STM32网线状态。下面是配置PHY

/**************************************************************配置DP83848芯片当网线状态变化时产生一个变化电平通知MCU。*************************************************************/uint32_t Eth_Link_PHYITConfig(uint16_t PHYAddress){/* PHY registers */  uint32_t tmpreg = 0;  tmpreg = ETH_ReadPHYRegister(PHYAddress, 2);  tmpreg = ETH_ReadPHYRegister(PHYAddress, 3);  /* Read MICR register */  tmpreg = ETH_ReadPHYRegister(PHYAddress, PHY_MICR);  /* Enable output interrupt events to signal via the INT pin */  tmpreg |= (uint32_t)PHY_MICR_INT_EN | PHY_MICR_INT_OE;  if(!(ETH_WritePHYRegister(PHYAddress, PHY_MICR, tmpreg)))  {    /* Return ERROR in case of write timeout */    return ETH_ERROR;  }  /* Read MISR register */  tmpreg = ETH_ReadPHYRegister(PHYAddress, PHY_MISR);  /* Enable Interrupt on change of link status */  tmpreg |= (uint32_t)PHY_MISR_LINK_INT_EN;  if(!(ETH_WritePHYRegister(PHYAddress, PHY_MISR, tmpreg)))  {    /* Return ERROR in case of write timeout */    return ETH_ERROR;  }  /* Return SUCCESS */  return ETH_SUCCESS;   }

2、代码是配置STM32的管脚为下降沿触发中断:

/**************************************************************配置GPIOA3为下降沿触发中断,通知MCU网线连接状态变化。************************************************************/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 the highest priority */  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  NVIC_Init(&NVIC_InitStructure);}
3、MACDMA相关初始化代码(这部分的初始化我们再系统启动的时候已经初始化过了)
static void ETH_MACDMA_Config(void){  ETH_InitTypeDef ETH_InitStructure;  /* Enable ETHERNET clock  */  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx |                        RCC_AHB1Periph_ETH_MAC_Rx, ENABLE);                          /* Reset ETHERNET on AHB Bus */  ETH_DeInit();  /* Software reset */  ETH_SoftwareReset();  /* Wait for software reset */  while (ETH_GetSoftwareResetStatus() == SET);  /* ETHERNET Configuration --------------------------------------------------*/  /* Call ETH_StructInit if you don't like to configure all ETH_InitStructure parameter */  ETH_StructInit(Ð_InitStructure);  /* Fill ETH_InitStructure parametrs */  /*------------------------   MAC   -----------------------------------*/  ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;  //ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Disable;   //  ETH_InitStructure.ETH_Speed = ETH_Speed_10M;  //  ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;     ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;  ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;  ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;  ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;  ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;  ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;  ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;  ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;#ifdef CHECKSUM_BY_HARDWARE  ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable;#endif  /*------------------------   DMA   -----------------------------------*/    /* When we use the Checksum offload feature, we need to enable the Store and Forward mode:   the store and forward guarantee that a whole frame is stored in the FIFO, so the MAC can insert/verify the checksum,   if the checksum is OK the DMA can handle the frame otherwise the frame is dropped */  ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable;   ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;           ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;       ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;         ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;     ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable;  ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;        ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable;                  ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;            ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;  ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;  /* Configure Ethernet */  if( ETH_Init(Ð_InitStructure, DP83848_PHY_ADDRESS) ==  ETH_ERROR )    rt_kprintf("ETH init error, may be no link\n");  {       /* Configure the PHY to generate an interrupt on change of link status */      Eth_Link_PHYITConfig(DP83848_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);}
4、网卡和DMA结构体初始化和使能网卡:
static rt_err_t rt_stm32_eth_init(rt_device_t dev){    int i;    /* MAC address configuration */    ETH_MACAddressConfig(ETH_MAC_Address0, (u8*)&stm32_eth_device.dev_addr[0]);        /* Initialize Tx Descriptors list: Chain Mode */    ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);    /* Initialize Rx Descriptors list: Chain Mode  */    ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);     /* Enable Ethernet Rx interrrupt */    {         for(i=0; i<ETH_RXBUFNB; i++)        {          ETH_DMARxDescReceiveITConfig(&DMARxDscrTab[i], ENABLE);        }    }    #ifdef CHECKSUM_BY_HARDWARE    /* Enable the checksum insertion for the Tx frames */    {        for(i=0; i<ETH_TXBUFNB; i++)        {          ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);        }    }     #endif    {        uint16_t tmp, i=10000;        tmp = ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_CR);        ETH_WritePHYRegister(DP83848_PHY_ADDRESS, PHY_CDCTRL1, BIST_CONT_MODE );        ETH_WritePHYRegister(DP83848_PHY_ADDRESS, PHY_CR, tmp | BIST_START );//BIST_START        while(i--);        //tmp =  ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_CR);        if( ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_CR) & BIST_STATUS == BIST_STATUS )        {            rt_kprintf("BIST pass\n");        }        else        {            uint16_t ctrl;            ctrl = ETH_ReadPHYRegister(DP83848_PHY_ADDRESS, PHY_CDCTRL1);            rt_kprintf("BIST faild count =%d\n", BIST_ERROR_COUNT(ctrl) );        }        tmp &= ~BIST_START; //Stop BIST         ETH_WritePHYRegister(DP83848_PHY_ADDRESS, PHY_CR, tmp);    }     /* Enable MAC and DMA transmission and reception */    ETH_Start();  return RT_EOK;}

以上的代码都是初始化之类的,没有什么,是下面是实现网线热拔插功能主要函数;

/************************************************当网线连接状态判断是出于连接状态还是拔开状态,**若为连接状态就根据实际情况重新配置MAC和DMA。**********************************************/void Eth_Link_ITHandler(uint16_t PHYAddress){    /* Check whether the link interrupt has occurred or not */    if(((ETH_ReadPHYRegister(PHYAddress, PHY_MISR)) & PHY_LINK_STATUS) != 0)    {        uint16_t status  = ETH_ReadPHYRegister(PHYAddress, PHY_BSR);        if(status & (PHY_AutoNego_Complete | PHY_Linked_Status)){        init_dma_mac();//初始化MAC和DMA相关参数        rt_kprintf("qqx enter net_link is  connect.\n\r");        }        else{        rt_kprintf("qqx enter net_link is  out\n\r");        }    }}
//初始化MAC和DMA相关参数void init_dma_mac(void){    rt_device_t stm32_eth_device;    ETH_MACDMA_Config();    stm32_eth_device = rt_device_find("e0");    rt_stm32_eth_init(stm32_eth_device);}
/***************************************************MCU外部中断入口函数,当STM32相应管教检测到下降沿**变化则就会进入此中断函数。*************************************************/void EXTI3_IRQHandler(void){  if(EXTI_GetITStatus(ETH_LINK_EXTI_LINE) != RESET)  {    Eth_Link_ITHandler(DP83848_PHY_ADDRESS);    /* Clear interrupt pending bit */    EXTI_ClearITPendingBit(ETH_LINK_EXTI_LINE);  }}

总体的步骤是:进入中断后调用Eth_Link_ITHandler(DP83848_PHY_ADDRESS); ->

(1)ETH_MACDMA_Config();

(2)rt_stm32_eth_init(stm32_eth_device);//通过设备查找函数找到“e0(按照自己实际名称)设备并初始化这个网络设备,

这样不管网线在什么时候拔插都可以联通,完美解决热拔插网线的问题。





0 0