/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : bsp_eth.c * @brief : Board support package Ethernet (LAN8720) driver implementation ****************************************************************************** */ /* USER CODE END Header */ #include "bsp_eth.h" /** * @brief Ethernet configuration */ static bsp_eth_config_t eth_config; static uint8_t eth_initialized = 0; /** * @brief Initialize Ethernet (LAN8720) module * @param config: Pointer to Ethernet configuration structure * @retval HAL status code */ hal_ret_t bsp_eth_init(const bsp_eth_config_t* config) { if (!config) { return HAL_RET_INVALID_PARAM; } if (eth_initialized) { return HAL_RET_OK; } /* Store configuration */ eth_config = *config; /* Convert to HAL configuration */ hal_eth_config_t hal_config; hal_config.enable = config->enable; hal_config.instance = config->instance; hal_config.mode = config->mode; hal_config.speed = config->speed; hal_config.phy_addr = config->phy_addr; hal_config.mac_addr = config->mac_addr; hal_config.auto_negotiation = config->auto_negotiation; hal_config.interrupt_enable = config->interrupt_enable; /* Initialize HAL Ethernet */ if (hal_eth_init(&hal_config) != HAL_RET_OK) { return HAL_RET_INIT_ERROR; } /* Detect LAN8720 PHY */ uint8_t detected; if (bsp_eth_detect_phy(&detected) != HAL_RET_OK) { return HAL_RET_INIT_ERROR; } if (!detected) { return HAL_RET_INIT_ERROR; } /* Configure PHY */ if (bsp_eth_configure_phy(config->mode, config->speed, config->auto_negotiation) != HAL_RET_OK) { return HAL_RET_INIT_ERROR; } eth_initialized = 1; return HAL_RET_OK; } /** * @brief Deinitialize Ethernet (LAN8720) module * @retval HAL status code */ hal_ret_t bsp_eth_deinit(void) { if (!eth_initialized) { return HAL_RET_OK; } if (hal_eth_deinit(eth_config.instance) != HAL_RET_OK) { return HAL_RET_DEINIT_ERROR; } eth_initialized = 0; return HAL_RET_OK; } /** * @brief Get Ethernet (LAN8720) status * @param status: Pointer to Ethernet status structure * @retval HAL status code */ hal_ret_t bsp_eth_get_status(bsp_eth_status_t* status) { if (!status) { return HAL_RET_INVALID_PARAM; } if (!eth_initialized) { return HAL_RET_INIT_ERROR; } /* Get HAL Ethernet status */ hal_eth_status_t hal_status; if (hal_eth_get_status(eth_config.instance, &hal_status) != HAL_RET_OK) { return HAL_RET_ERROR; } /* Copy status */ status->link_up = hal_status.link_up; status->duplex = hal_status.duplex; status->speed = hal_status.speed; status->rx_packets = hal_status.rx_packets; status->tx_packets = hal_status.tx_packets; status->rx_errors = hal_status.rx_errors; status->tx_errors = hal_status.tx_errors; /* Get PHY identifiers */ if (bsp_eth_read_phy_reg(LAN8720_REG_PID1, &status->phy_id1) != HAL_RET_OK) { status->phy_id1 = 0; } if (bsp_eth_read_phy_reg(LAN8720_REG_PID2, &status->phy_id2) != HAL_RET_OK) { status->phy_id2 = 0; } return HAL_RET_OK; } /** * @brief Set Ethernet MAC address * @param mac_addr: Pointer to MAC address structure * @retval HAL status code */ hal_ret_t bsp_eth_set_mac_addr(const hal_eth_mac_addr_t* mac_addr) { if (!mac_addr) { return HAL_RET_INVALID_PARAM; } if (!eth_initialized) { return HAL_RET_INIT_ERROR; } if (hal_eth_set_mac_addr(eth_config.instance, mac_addr) != HAL_RET_OK) { return HAL_RET_ERROR; } eth_config.mac_addr = *mac_addr; return HAL_RET_OK; } /** * @brief Get Ethernet MAC address * @param mac_addr: Pointer to MAC address structure * @retval HAL status code */ hal_ret_t bsp_eth_get_mac_addr(hal_eth_mac_addr_t* mac_addr) { if (!mac_addr) { return HAL_RET_INVALID_PARAM; } if (!eth_initialized) { return HAL_RET_INIT_ERROR; } if (hal_eth_get_mac_addr(eth_config.instance, mac_addr) != HAL_RET_OK) { return HAL_RET_ERROR; } return HAL_RET_OK; } /** * @brief Check Ethernet link status * @param link_up: Pointer to store link up status * @retval HAL status code */ hal_ret_t bsp_eth_check_link(uint8_t* link_up) { if (!link_up) { return HAL_RET_INVALID_PARAM; } if (!eth_initialized) { return HAL_RET_INIT_ERROR; } if (hal_eth_check_link(eth_config.instance, link_up) != HAL_RET_OK) { return HAL_RET_ERROR; } return HAL_RET_OK; } /** * @brief Reset Ethernet PHY (LAN8720) * @retval HAL status code */ hal_ret_t bsp_eth_reset_phy(void) { if (!eth_initialized) { return HAL_RET_INIT_ERROR; } if (hal_eth_reset_phy(eth_config.instance, eth_config.phy_addr) != HAL_RET_OK) { return HAL_RET_ERROR; } return HAL_RET_OK; } /** * @brief Read LAN8720 PHY register * @param reg_addr: Register address * @param value: Pointer to store register value * @retval HAL status code */ hal_ret_t bsp_eth_read_phy_reg(uint16_t reg_addr, uint16_t* value) { if (!value) { return HAL_RET_INVALID_PARAM; } if (!eth_initialized) { return HAL_RET_INIT_ERROR; } if (hal_eth_read_phy_reg(eth_config.instance, eth_config.phy_addr, reg_addr, value) != HAL_RET_OK) { return HAL_RET_ERROR; } return HAL_RET_OK; } /** * @brief Write LAN8720 PHY register * @param reg_addr: Register address * @param value: Register value * @retval HAL status code */ hal_ret_t bsp_eth_write_phy_reg(uint16_t reg_addr, uint16_t value) { if (!eth_initialized) { return HAL_RET_INIT_ERROR; } if (hal_eth_write_phy_reg(eth_config.instance, eth_config.phy_addr, reg_addr, value) != HAL_RET_OK) { return HAL_RET_ERROR; } return HAL_RET_OK; } /** * @brief Detect LAN8720 PHY presence * @param detected: Pointer to store detection result * @retval HAL status code */ hal_ret_t bsp_eth_detect_phy(uint8_t* detected) { if (!detected) { return HAL_RET_INVALID_PARAM; } if (!eth_initialized) { return HAL_RET_INIT_ERROR; } /* Read PHY identifiers */ uint16_t id1, id2; if (bsp_eth_read_phy_reg(LAN8720_REG_PID1, &id1) != HAL_RET_OK) { return HAL_RET_ERROR; } if (bsp_eth_read_phy_reg(LAN8720_REG_PID2, &id2) != HAL_RET_OK) { return HAL_RET_ERROR; } /* Check if this is a LAN8720 PHY */ if (id1 == LAN8720_PID1_VALUE && (id2 & 0xFFF0) == LAN8720_PID2_VALUE) { *detected = 1; } else { *detected = 0; } return HAL_RET_OK; } /** * @brief Configure LAN8720 PHY * @param mode: Ethernet mode * @param speed: Ethernet speed * @param auto_neg: Auto-negotiation enable * @retval HAL status code */ hal_ret_t bsp_eth_configure_phy(hal_eth_mode_t mode, hal_eth_speed_t speed, uint8_t auto_neg) { if (!eth_initialized) { return HAL_RET_INIT_ERROR; } /* Read current BCR register */ uint16_t bcr; if (bsp_eth_read_phy_reg(LAN8720_REG_BCR, &bcr) != HAL_RET_OK) { return HAL_RET_ERROR; } /* Clear relevant bits */ bcr &= ~(LAN8720_BCR_AUTO_NEG_EN | LAN8720_BCR_SPEED_SELECT | LAN8720_BCR_DUPLEX_MODE); if (auto_neg) { /* Enable auto-negotiation */ bcr |= LAN8720_BCR_AUTO_NEG_EN; bcr |= LAN8720_BCR_RESTART_AN; } else { /* Manual configuration */ if (speed == HAL_ETH_SPEED_100MBPS) { bcr |= LAN8720_BCR_SPEED_SELECT; } if (mode == HAL_ETH_MODE_FULLDUPLEX) { bcr |= LAN8720_BCR_DUPLEX_MODE; } } /* Write BCR register */ if (bsp_eth_write_phy_reg(LAN8720_REG_BCR, bcr) != HAL_RET_OK) { return HAL_RET_ERROR; } /* Wait for configuration to complete */ if (auto_neg) { uint32_t timeout = 1000; uint16_t bsr; while (timeout--) { if (bsp_eth_read_phy_reg(LAN8720_REG_BSR, &bsr) == HAL_RET_OK) { if (bsr & LAN8720_BSR_AUTO_NEG_COMPLETE) { break; } } HAL_Delay(1); } if (timeout == 0) { return HAL_RET_TIMEOUT; } } return HAL_RET_OK; }