/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : hal_stm32f4_eth.c * @brief : STM32F4 specific Ethernet interface implementation ****************************************************************************** */ /* USER CODE END Header */ #include #include "hal_stm32f4_eth.h" /** * @brief Ethernet handles */ static hal_stm32f4_eth_handle_t eth_handles[HAL_ETH_INSTANCE_MAX]; /** * @brief Configure STM32F4 Ethernet GPIO * @retval HAL status code */ hal_ret_t hal_stm32f4_eth_gpio_config(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* Enable Ethernet GPIO clocks */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); /* Configure ETH_MDIO (PA2) */ GPIO_InitStruct.Pin = GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* Configure ETH_RMII_REF_CLK (PA1) */ GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* Configure ETH_RMII_CRS_DV (PA7) */ GPIO_InitStruct.Pin = GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* Configure ETH_MDC (PC1) */ GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /* Configure ETH_RMII_RXD0 (PC4) */ GPIO_InitStruct.Pin = GPIO_PIN_4; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /* Configure ETH_RMII_RXD1 (PC5) */ GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /* Configure ETH_RMII_TX_EN (PB11) */ GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* Configure ETH_RMII_TXD0 (PB12) */ GPIO_InitStruct.Pin = GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* Configure ETH_RMII_TXD1 (PB13) */ GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); return HAL_RET_OK; } /** * @brief Initialize STM32F4 Ethernet module * @param config: Pointer to Ethernet configuration structure * @retval HAL status code */ hal_ret_t hal_stm32f4_eth_init(const hal_eth_config_t* config) { if (!config) { return HAL_RET_INVALID_PARAM; } hal_eth_instance_t instance = config->instance; if (instance >= HAL_ETH_INSTANCE_MAX) { return HAL_RET_INVALID_PARAM; } /* Configure GPIO */ if (hal_stm32f4_eth_gpio_config() != HAL_RET_OK) { return HAL_RET_INIT_ERROR; } /* Enable Ethernet clock */ __HAL_RCC_ETH_CLK_ENABLE(); /* Reset Ethernet handle */ memset(ð_handles[instance], 0, sizeof(hal_stm32f4_eth_handle_t)); /* Configure Ethernet */ eth_handles[instance].heth.Instance = ETH; eth_handles[instance].heth.Init.MACAddr = config->mac_addr.byte; eth_handles[instance].heth.Init.MediaInterface = HAL_ETH_RMII_MODE; eth_handles[instance].heth.Init.TxDesc = 0x20000000; eth_handles[instance].heth.Init.RxDesc = 0x20000800; eth_handles[instance].heth.Init.RxBuffLen = 1524; eth_handles[instance].phy_addr = config->phy_addr; /* Initialize Ethernet */ if (HAL_ETH_Init(ð_handles[instance].heth) != HAL_OK) { return HAL_RET_INIT_ERROR; } /* Configure PHY */ if (hal_stm32f4_eth_reset_phy(instance, config->phy_addr) != HAL_RET_OK) { return HAL_RET_INIT_ERROR; } /* Enable Ethernet interrupts if requested */ if (config->interrupt_enable) { HAL_NVIC_SetPriority(ETH_IRQn, 5, 0); HAL_NVIC_EnableIRQ(ETH_IRQn); } eth_handles[instance].initialized = 1; return HAL_RET_OK; } /** * @brief Deinitialize STM32F4 Ethernet module * @param instance: Ethernet instance * @retval HAL status code */ hal_ret_t hal_stm32f4_eth_deinit(hal_eth_instance_t instance) { if (instance >= HAL_ETH_INSTANCE_MAX) { return HAL_RET_INVALID_PARAM; } if (!eth_handles[instance].initialized) { return HAL_RET_OK; } /* Disable Ethernet interrupt */ HAL_NVIC_DisableIRQ(ETH_IRQn); /* Deinitialize Ethernet */ if (HAL_ETH_DeInit(ð_handles[instance].heth) != HAL_OK) { return HAL_RET_DEINIT_ERROR; } /* Disable Ethernet clock */ __HAL_RCC_ETH_CLK_DISABLE(); eth_handles[instance].initialized = 0; return HAL_RET_OK; } /** * @brief Get STM32F4 Ethernet status * @param instance: Ethernet instance * @param status: Pointer to Ethernet status structure * @retval HAL status code */ hal_ret_t hal_stm32f4_eth_get_status(hal_eth_instance_t instance, hal_eth_status_t* status) { if (instance >= HAL_ETH_INSTANCE_MAX || !status) { return HAL_RET_INVALID_PARAM; } if (!eth_handles[instance].initialized) { return HAL_RET_INIT_ERROR; } /* Check link status */ uint8_t link_up; if (hal_stm32f4_eth_check_link(instance, &link_up) != HAL_RET_OK) { return HAL_RET_ERROR; } status->link_up = link_up; status->rx_packets = eth_handles[instance].rx_packets; status->tx_packets = eth_handles[instance].tx_packets; status->rx_errors = eth_handles[instance].rx_errors; status->tx_errors = eth_handles[instance].tx_errors; /* Get speed and duplex mode */ if (link_up) { uint16_t phy_status; if (hal_stm32f4_eth_read_phy_reg(instance, eth_handles[instance].phy_addr, 0x01, &phy_status) == HAL_RET_OK) { status->duplex = (phy_status & (1 << 13)) ? 1 : 0; status->speed = (phy_status & (1 << 12)) ? 100 : 10; } else { status->duplex = 0; status->speed = 10; } } else { status->duplex = 0; status->speed = 0; } return HAL_RET_OK; } /** * @brief Set STM32F4 Ethernet MAC address * @param instance: Ethernet instance * @param mac_addr: Pointer to MAC address structure * @retval HAL status code */ hal_ret_t hal_stm32f4_eth_set_mac_addr(hal_eth_instance_t instance, const hal_eth_mac_addr_t* mac_addr) { if (instance >= HAL_ETH_INSTANCE_MAX || !mac_addr) { return HAL_RET_INVALID_PARAM; } if (!eth_handles[instance].initialized) { return HAL_RET_INIT_ERROR; } /* MAC address is set during initialization, cannot be changed at runtime */ memcpy(eth_handles[instance].heth.Init.MACAddr, mac_addr->byte, 6); return HAL_RET_OK; } /** * @brief Get STM32F4 Ethernet MAC address * @param instance: Ethernet instance * @param mac_addr: Pointer to MAC address structure * @retval HAL status code */ hal_ret_t hal_stm32f4_eth_get_mac_addr(hal_eth_instance_t instance, hal_eth_mac_addr_t* mac_addr) { if (instance >= HAL_ETH_INSTANCE_MAX || !mac_addr) { return HAL_RET_INVALID_PARAM; } if (!eth_handles[instance].initialized) { return HAL_RET_INIT_ERROR; } /* Get MAC address from initialization structure */ memcpy(mac_addr->byte, eth_handles[instance].heth.Init.MACAddr, 6); return HAL_RET_OK; } /** * @brief Check STM32F4 Ethernet link status * @param instance: Ethernet instance * @param link_up: Pointer to store link up status * @retval HAL status code */ hal_ret_t hal_stm32f4_eth_check_link(hal_eth_instance_t instance, uint8_t* link_up) { if (instance >= HAL_ETH_INSTANCE_MAX || !link_up) { return HAL_RET_INVALID_PARAM; } if (!eth_handles[instance].initialized) { return HAL_RET_INIT_ERROR; } /* Read PHY status register */ uint16_t phy_status; if (hal_stm32f4_eth_read_phy_reg(instance, eth_handles[instance].phy_addr, 0x01, &phy_status) != HAL_RET_OK) { return HAL_RET_ERROR; } /* Check link status bit */ *link_up = (phy_status & (1 << 2)) ? 1 : 0; return HAL_RET_OK; } /** * @brief Reset STM32F4 Ethernet PHY * @param instance: Ethernet instance * @param phy_addr: PHY address * @retval HAL status code */ hal_ret_t hal_stm32f4_eth_reset_phy(hal_eth_instance_t instance, hal_eth_phy_addr_t phy_addr) { if (instance >= HAL_ETH_INSTANCE_MAX) { return HAL_RET_INVALID_PARAM; } if (!eth_handles[instance].initialized) { return HAL_RET_INIT_ERROR; } eth_handles[instance].phy_addr = phy_addr; /* Reset PHY */ uint16_t value = 0x8000; if (hal_stm32f4_eth_write_phy_reg(instance, phy_addr, 0x00, value) != HAL_RET_OK) { return HAL_RET_ERROR; } /* Wait for reset to complete */ uint32_t timeout = 1000; while (timeout--) { if (hal_stm32f4_eth_read_phy_reg(instance, phy_addr, 0x00, &value) == HAL_RET_OK) { if (!(value & 0x8000)) { break; } } HAL_Delay(1); } if (timeout == 0) { return HAL_RET_TIMEOUT; } return HAL_RET_OK; } /** * @brief Read STM32F4 Ethernet PHY register * @param instance: Ethernet instance * @param phy_addr: PHY address * @param reg_addr: Register address * @param value: Pointer to store register value * @retval HAL status code */ hal_ret_t hal_stm32f4_eth_read_phy_reg(hal_eth_instance_t instance, hal_eth_phy_addr_t phy_addr, uint16_t reg_addr, uint16_t* value) { if (instance >= HAL_ETH_INSTANCE_MAX || !value) { return HAL_RET_INVALID_PARAM; } if (!eth_handles[instance].initialized) { return HAL_RET_INIT_ERROR; } uint32_t reg_value; if (HAL_ETH_ReadPHYRegister(ð_handles[instance].heth, phy_addr, reg_addr, ®_value) != HAL_OK) { return HAL_RET_ERROR; } *value = (uint16_t)reg_value; return HAL_RET_OK; } /** * @brief Write STM32F4 Ethernet PHY register * @param instance: Ethernet instance * @param phy_addr: PHY address * @param reg_addr: Register address * @param value: Register value * @retval HAL status code */ hal_ret_t hal_stm32f4_eth_write_phy_reg(hal_eth_instance_t instance, hal_eth_phy_addr_t phy_addr, uint16_t reg_addr, uint16_t value) { if (instance >= HAL_ETH_INSTANCE_MAX) { return HAL_RET_INVALID_PARAM; } if (!eth_handles[instance].initialized) { return HAL_RET_INIT_ERROR; } if (HAL_ETH_WritePHYRegister(ð_handles[instance].heth, phy_addr, reg_addr, value) != HAL_OK) { return HAL_RET_ERROR; } return HAL_RET_OK; } /** * @brief Get STM32F4 Ethernet handle * @param instance: Ethernet instance * @retval Pointer to Ethernet handle structure */ hal_stm32f4_eth_handle_t* hal_stm32f4_eth_get_handle(hal_eth_instance_t instance) { if (instance >= HAL_ETH_INSTANCE_MAX) { return NULL; } if (!eth_handles[instance].initialized) { return NULL; } return ð_handles[instance]; } /** * @brief Ethernet interrupt handler */ void ETH_IRQHandler(void) { HAL_ETH_IRQHandler(ð_handles[0].heth); } /** * @brief Ethernet RX callback * @param heth: Ethernet handle */ void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth) { /* Increment received packets count */ eth_handles[0].rx_packets++; /* Reactivate reception */ HAL_ETH_Start_IT(heth); } /** * @brief Ethernet TX callback * @param heth: Ethernet handle */ void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth) { /* Increment transmitted packets count */ eth_handles[0].tx_packets++; } /** * @brief Ethernet error callback * @param heth: Ethernet handle */ void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) { /* Increment error count */ eth_handles[0].rx_errors++; eth_handles[0].tx_errors++; }