354 lines
8.3 KiB
C
354 lines
8.3 KiB
C
/* 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;
|
|
}
|