STM32F207+DP83848+RT-THREAD实现网线拔插重连试验
2015-01-19 17:46
253 查看
我在刚开始遇到这个问题的时候,上网搜了下,讲得都不是很清楚。不非是“重新初始化”、”重新初始化MAC“,但是都是在文字表面。下面直接上代码,附上的代码是自己测试通过的。
1、通过DP83848配置为link状态变化,相应管教会有电平变化(具体看手册),从而触发STM32外部中断,通知STM32网线状态。下面是配置PHY
2、代码是配置STM32的管脚为下降沿触发中断:
以上的代码都是初始化之类的,没有什么,是下面是实现网线热拔插功能主要函数;
总体的步骤是:进入中断后调用Eth_Link_ITHandler(DP83848_PHY_ADDRESS); ->
(1)ETH_MACDMA_Config();
(2)rt_stm32_eth_init(stm32_eth_device);//通过设备查找函数找到“e0(按照自己实际名称)”设备并初始化这个网络设备,
这样不管网线在什么时候拔插都可以联通,完美解决热拔插网线的问题。
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、MAC和DMA相关初始化代码(这部分的初始化我们再系统启动的时候已经初始化过了)
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(按照自己实际名称)”设备并初始化这个网络设备,
这样不管网线在什么时候拔插都可以联通,完美解决热拔插网线的问题。
相关文章推荐
- 关于ISA2004内网卡网线拔插造成ISA代理失效问题的一种解决方法(下列错误而失败:0x80072
- Java Thread实现读写同步
- 挂钩 NtResumeThread 实现全局Hook
- n皇后问题(人工智能试验java实现)
- 实现Runnable为什么比继承Thread好
- 二维反傅立叶变换试验,用VC代码实现
- Java进阶:一个简单Thread缓冲池的实现
- java Thread:利用Thread类实现多线程
- 应用SynchronizationContext来实现对thread-safe UI的同步访问的2种不同Programming Model
- 一个简单的Thread缓冲池的实现
- 用线程池(Thread Pool)实现异步执行程序
- Flex事件处理实现机制的一个试验
- JMS(Jboss Messaging)的一点使用心得(十三)拔网线后的重连----JMS Connection原理浅析及应用
- [ASP]无限级分类的简单算法实现及代码重点讲解http://bbs.blueidea.com/thread-1982151-1-1.html
- 一个简单的Thread缓冲池的实现
- 一个简单的Thread缓冲池的实现
- 用线程池(Thread Pool)实现异步执行程序
- 挂钩 NtResumeThread 实现全局Hook
- Oracle全文检索功能实现的尝试试验
- 【zt】一个用 Observer 模式实现的 Thread 线程文件搜索例子