#include "stm32f4x7_phy.h" #include "dwt.h" #include "lwip/api.h" #include "lwip/sockets.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); us_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_CheckLinkStatus(uint16_t PHYAddress) { static uint8_t status = 0; uint32_t t = ETH_ReadPHYRegister(ETHERNET_PHY_ADDRESS, PHY_SR) & 1; /* If we have link and previous check was not yet */ if (t && !status) { /* Set link up */ netif_set_link_up(&gnetif); status = 1; } /* If we don't have link and it was on previous check */ if (!t && status) { // EthLinkStatus = 1; /* Set link down */ netif_set_link_down(&gnetif); status = 0; } } /** * @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; }