#include "stm32f4x7_phy.h" #include "interface.h" #include "lwip/api.h" #include "lwip/sockets.h" #include "netconf.h" #include "stm32f4x7_eth.h" ETH_InitTypeDef ETH_InitStructure; __IO uint32_t EthStatus = 0; extern struct netif gnetif; static void phy_gpio_config(void); static void phy_mac_dma_config(void); static void nvic_configuration(void); /** * @brief Inserts a delay time. * @param nCount: number of 10ms periods to wait for. * @retval None */ void ETH_Delay10ms(uint32_t nCount) { // OSTimeDly(10 * nCount); USE_Delay(10 * nCount); } /*! \brief setup ethernet system(GPIOs, clocks, MAC, DMA, systick) \param[in] none \param[out] none \retval none */ void eth_init(void) { nvic_configuration(); /* configure the GPIO ports for ethernet pins */ phy_gpio_config(); /* configure the ethernet MAC/DMA */ phy_mac_dma_config(); /* Get Ethernet link status*/ if (ETH_ReadPHYRegister(ETHERNET_PHY_ADDRESS, PHY_SR) & 1) { EthStatus |= ETH_LINK_FLAG; } /* Configure the PHY to generate an interrupt on change of link status */ Eth_Link_PHYITConfig(ETHERNET_PHY_ADDRESS); ETH_DMAITConfig(ETH_DMA_IT_R | ETH_DMA_IT_NIS, ENABLE); } /*! \brief configures the ethernet interface \param[in] none \param[out] none \retval none */ static void phy_mac_dma_config(void) { /* Reset ETHERNET on AHB Bus */ ETH_DeInit(); /* Software reset */ ETH_SoftwareReset(); /* Wait for software reset */ while (ETH_GetSoftwareResetStatus() == SET) ; /* ETHERNET Configuration ------------------------------*/ /* 缺省配置ETH_InitStructure */ 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; /* 关闭自动去除PDA/CRC功能 */ 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 /* 开启ipv4和TCP/UDP/ICMP的帧校验和卸载 */ ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable; #endif /*------------------------ DMA -------------------------------*/ /*当我们使用帧校验和卸载功能的时候,一定要使能存储转发模式,存储 转发模式中要保证整个帧存储在FIFO中, 这样MAC能插入/识别出帧校验 值,当真校验正确的时候DMA就可以处理帧,否则就丢弃掉该帧*/ /* 开启丢弃TCP/IP错误帧 */ 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; /* 开启DMA传输的地址对齐功能 */ ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable; /* 开启固定突发功能 */ ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable; /* DMA发送的最大突发长度为32个节拍 */ ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat; /*DMA接收的最大突发长度为32个节拍 */ ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat; ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1; /* 配置ETH */ EthStatus = ETH_Init(Ð_InitStructure, ETHERNET_PHY_ADDRESS); } /*! \brief configures the nested vectored interrupt controller \param[in] none \param[out] none \retval none */ static void nvic_configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = ETH_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } /*! \brief configures the different GPIO ports \param[in] none \param[out] none \retval none */ static void phy_gpio_config(void) { /* Enable SYSCFG clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); #ifdef MII_MODE #ifdef PHY_CLOCK_MCO /* output HXTAL clock (25MHz) on CKOUT0 pin(PA8) to clock the PHY */ RCC_MCO1Config(RCC_MCO1Source_HSE, RCC_MCO1Div_1); #endif /* PHY_CLOCK_MCO */ SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_MII); #elif defined RMII_MODE SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII); #endif } /** * @brief This function handles Ethernet link status. * @param None * @retval None */ 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) { if ((ETH_ReadPHYRegister(PHYAddress, PHY_SR) & 1)) { netif_set_link_up(&gnetif); } else { netif_set_link_down(&gnetif); } } } /** * @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) { uint16_t tmpreg = 0; /* Read MICR register */ tmpreg = ETH_ReadPHYRegister(PHYAddress, PHY_MICR); /* Enable output interrupt events to signal via the INT pin */ tmpreg |= (uint16_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 |= (uint16_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; } /** * @brief Link callback function, this function is called on change of link status. * @param The network interface * @retval None */ void ETH_link_callback(struct netif *netif) { __IO uint32_t timeout = 0; uint32_t tmpreg; uint16_t RegValue; ip4_addr_t ipaddr; ip4_addr_t netmask; ip4_addr_t gw; if (netif_is_link_up(netif)) { /* Restart the auto-negotiation */ if (ETH_InitStructure.ETH_AutoNegotiation != ETH_AutoNegotiation_Disable) { /* Reset Timeout counter */ timeout = 0; /* Enable auto-negotiation */ ETH_WritePHYRegister(ETHERNET_PHY_ADDRESS, PHY_BCR, PHY_AutoNegotiation); /* Wait until the auto-negotiation will be completed */ do { timeout++; } while (!(ETH_ReadPHYRegister(ETHERNET_PHY_ADDRESS, PHY_BSR) & PHY_AutoNego_Complete) && (timeout < (uint32_t)PHY_READ_TO)); /* Reset Timeout counter */ timeout = 0; /* Read the result of the auto-negotiation */ RegValue = ETH_ReadPHYRegister(ETHERNET_PHY_ADDRESS, PHY_SR); /* Configure the MAC with the Duplex Mode fixed by the auto-negotiation process */ if ((RegValue & PHY_DUPLEX_STATUS) != (uint16_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; } /*------------------------ ETHERNET MACCR Re-Configuration --------------------*/ /* Get the ETHERNET MACCR value */ tmpreg = ETH->MACCR; /* Set the FES bit according to ETH_Speed value */ /* Set the DM bit according to ETH_Mode value */ tmpreg |= (uint32_t)(ETH_InitStructure.ETH_Speed | ETH_InitStructure.ETH_Mode); /* Write to ETHERNET MACCR */ ETH->MACCR = (uint32_t)tmpreg; _eth_delay_(ETH_REG_WRITE_DELAY); tmpreg = ETH->MACCR; ETH->MACCR = tmpreg; } /* Restart MAC interface */ ETH_Start(); #ifdef USE_DHCP ipaddr.addr = 0; netmask.addr = 0; gw.addr = 0; DHCP_state = DHCP_START; #else IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3); IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3); IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3); #endif /* USE_DHCP */ netif_set_addr(&gnetif, &ipaddr, &netmask, &gw); /* When the netif is fully configured this function must be called.*/ netif_set_up(&gnetif); /* 打印调试信息 */ printf("LwIP Network Cable is now connected \r\n"); #ifndef USE_DHCP /* Display static IP address */ printf("LwIP Static IP address = %d.%d.%d.%d \r\n", IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3); #endif /* USE_DHCP */ } else { ETH_Stop(); #ifdef USE_DHCP DHCP_state = DHCP_LINK_DOWN; dhcp_stop(netif); #endif /* USE_DHCP */ /* When the netif link is down this function must be called.*/ netif_set_down(&gnetif); /* 打印调试信息 */ printf("LwIP Network Cable is unplugged \r\n"); } }