Merge branch 'feat/remove_eth_drivers' into 'master'

Feat/remove eth drivers

Closes IDF-13553 and IDF-5865

See merge request espressif/esp-idf!42021
This commit is contained in:
Ondrej Kosta
2025-09-29 10:14:42 +08:00
106 changed files with 577 additions and 7436 deletions

View File

@@ -30,32 +30,12 @@ if(CONFIG_ETH_ENABLED)
list(APPEND srcs "src/mac/esp_eth_mac_esp.c" list(APPEND srcs "src/mac/esp_eth_mac_esp.c"
"src/mac/esp_eth_mac_esp_dma.c" "src/mac/esp_eth_mac_esp_dma.c"
"src/mac/esp_eth_mac_esp_gpio.c" "src/mac/esp_eth_mac_esp_gpio.c"
"src/phy/esp_eth_phy_generic.c" "src/phy/esp_eth_phy_generic.c")
"src/phy/esp_eth_phy_dp83848.c"
"src/phy/esp_eth_phy_ip101.c"
"src/phy/esp_eth_phy_ksz80xx.c"
"src/phy/esp_eth_phy_lan87xx.c"
"src/phy/esp_eth_phy_rtl8201.c")
endif()
if(CONFIG_ETH_SPI_ETHERNET_DM9051)
list(APPEND srcs "src/spi/dm9051/esp_eth_mac_dm9051.c"
"src/spi/dm9051/esp_eth_phy_dm9051.c")
endif()
if(CONFIG_ETH_SPI_ETHERNET_W5500)
list(APPEND srcs "src/spi/w5500/esp_eth_mac_w5500.c"
"src/spi/w5500/esp_eth_phy_w5500.c")
endif()
if(CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL)
list(APPEND srcs "src/spi/ksz8851snl/esp_eth_mac_ksz8851snl.c"
"src/spi/ksz8851snl/esp_eth_phy_ksz8851snl.c")
endif() endif()
if(CONFIG_ETH_USE_OPENETH) if(CONFIG_ETH_USE_OPENETH)
list(APPEND srcs "src/openeth/esp_eth_mac_openeth.c" list(APPEND srcs "src/openeth/esp_eth_mac_openeth.c"
"src/phy/esp_eth_phy_dp83848.c") "src/phy/esp_eth_phy_generic.c")
endif() endif()
endif() endif()

View File

@@ -57,38 +57,13 @@ menu "Ethernet"
If disabled, all functions are placed into FLASH. If disabled, all functions are placed into FLASH.
endif # ETH_USE_ESP32_EMAC endif # ETH_USE_ESP32_EMAC
menuconfig ETH_USE_SPI_ETHERNET menuconfig ETH_USE_SPI_ETHERNET
bool "Support SPI to Ethernet Module" bool "Support SPI to Ethernet Module"
default y default y
select ETH_ENABLED select ETH_ENABLED
help help
ESP-IDF can also support some SPI-Ethernet modules. ESP-IDF can also support SPI-Ethernet. Actual chip drivers are available as components in
Component Registry.
if ETH_USE_SPI_ETHERNET
config ETH_SPI_ETHERNET_DM9051
bool "Use DM9051"
help
DM9051 is a fast Ethernet controller with an SPI interface.
It's also integrated with a 10/100M PHY and MAC.
Select this to enable DM9051 driver.
config ETH_SPI_ETHERNET_W5500
bool "Use W5500 (MAC RAW)"
help
W5500 is a HW TCP/IP embedded Ethernet controller.
TCP/IP stack, 10/100 Ethernet MAC and PHY are embedded in a single chip.
However the driver in ESP-IDF only enables the RAW MAC mode,
making it compatible with the software TCP/IP stack.
Say yes to enable W5500 driver.
config ETH_SPI_ETHERNET_KSZ8851SNL
bool "Use KSZ8851SNL"
help
The KSZ8851SNL is a single-chip Fast Ethernet controller consisting of
a 10/100 physical layer transceiver (PHY), a MAC, and a Serial Peripheral Interface (SPI).
Select this to enable KSZ8851SNL driver.
endif # ETH_USE_SPI_ETHERNET
menuconfig ETH_USE_OPENETH menuconfig ETH_USE_OPENETH
bool "Support OpenCores Ethernet MAC (for use with QEMU)" bool "Support OpenCores Ethernet MAC (for use with QEMU)"

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -9,15 +9,14 @@
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "esp_eth_com.h" #include "esp_eth_com.h"
#include "esp_eth_mac.h" #include "esp_eth_mac.h"
#include "sdkconfig.h"
#include "driver/spi_master.h" #include "driver/spi_master.h"
#include "sdkconfig.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#if CONFIG_ETH_USE_SPI_ETHERNET #if CONFIG_ETH_USE_SPI_ETHERNET
/** /**
* @brief Custom SPI Driver Configuration. * @brief Custom SPI Driver Configuration.
* This structure declares configuration and callback functions to access Ethernet SPI module via * This structure declares configuration and callback functions to access Ethernet SPI module via
@@ -112,125 +111,8 @@ typedef struct
.read = NULL, \ .read = NULL, \
.write = NULL \ .write = NULL \
} }
#endif // CONFIG_ETH_USE_SPI_ETHERNET #endif // CONFIG_ETH_USE_SPI_ETHERNET
#if CONFIG_ETH_SPI_ETHERNET_DM9051
/**
* @brief DM9051 specific configuration
*
*/
typedef struct {
int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */
uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */
spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined) */
spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined) */
eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */
} eth_dm9051_config_t;
/**
* @brief Default DM9051 specific configuration
*
*/
#define ETH_DM9051_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \
{ \
.int_gpio_num = 4, \
.poll_period_ms = 0, \
.spi_host_id = spi_host, \
.spi_devcfg = spi_devcfg_p, \
.custom_spi_driver = ETH_DEFAULT_SPI, \
}
/**
* @brief Create DM9051 Ethernet MAC instance
*
* @param dm9051_config: DM9051 specific configuration
* @param mac_config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, const eth_mac_config_t *mac_config);
#endif // CONFIG_ETH_SPI_ETHERNET_DM9051
#if CONFIG_ETH_SPI_ETHERNET_W5500
/**
* @brief W5500 specific configuration
*
*/
typedef struct {
int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */
uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */
spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined)*/
spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined)*/
eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */
} eth_w5500_config_t;
/**
* @brief Default W5500 specific configuration
*
*/
#define ETH_W5500_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \
{ \
.int_gpio_num = 4, \
.poll_period_ms = 0, \
.spi_host_id = spi_host, \
.spi_devcfg = spi_devcfg_p, \
.custom_spi_driver = ETH_DEFAULT_SPI, \
}
/**
* @brief Create W5500 Ethernet MAC instance
*
* @param w5500_config: W5500 specific configuration
* @param mac_config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, const eth_mac_config_t *mac_config);
#endif // CONFIG_ETH_SPI_ETHERNET_W5500
#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
/**
* @brief KSZ8851SNL specific configuration
*
*/
typedef struct {
int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */
uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */
spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined) */
spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined) */
eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */
} eth_ksz8851snl_config_t;
/**
* @brief Default KSZ8851SNL specific configuration
*
*/
#define ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \
{ \
.int_gpio_num = 4, \
.poll_period_ms = 0, \
.spi_host_id = spi_host, \
.spi_devcfg = spi_devcfg_p, \
.custom_spi_driver = ETH_DEFAULT_SPI, \
}
/**
* @brief Create KSZ8851SNL Ethernet MAC instance
*
* @param ksz8851snl_config: KSZ8851SNL specific configuration
* @param mac_config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_ksz8851snl(const eth_ksz8851snl_config_t *ksz8851snl_config, const eth_mac_config_t *mac_config);
#endif // CONFIG_ETH_SPI_ETHERNET_KSZ8851
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -299,7 +299,7 @@ typedef struct {
/** /**
* @brief Create a PHY instance of generic chip which conforms with IEEE 802.3 * @brief Create a PHY instance of generic chip which conforms with IEEE 802.3
* *
* @note Default reset timing configuration is set conservatively( @c DEFAULT_PHY_RESET_ASSERTION_TIME_US ). * @note Default reset timing configuration is set conservatively(see internals of the function).
* If you need faster response and your chip supports it, configure it via @c config parameter. * If you need faster response and your chip supports it, configure it via @c config parameter.
* *
* @warning While basic functionality should always work, some specific features might be limited, * @warning While basic functionality should always work, some specific features might be limited,
@@ -313,105 +313,6 @@ typedef struct {
*/ */
esp_eth_phy_t *esp_eth_phy_new_generic(const eth_phy_config_t *config); esp_eth_phy_t *esp_eth_phy_new_generic(const eth_phy_config_t *config);
/**
* @brief Create a PHY instance of IP101
*
* @param[in] config: configuration of PHY
*
* @return
* - instance: create PHY instance successfully
* - NULL: create PHY instance failed because some error occurred
*/
esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config);
/**
* @brief Create a PHY instance of RTL8201
*
* @param[in] config: configuration of PHY
*
* @return
* - instance: create PHY instance successfully
* - NULL: create PHY instance failed because some error occurred
*/
esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config);
/**
* @brief Create a PHY instance of LAN87xx
*
* @param[in] config: configuration of PHY
*
* @return
* - instance: create PHY instance successfully
* - NULL: create PHY instance failed because some error occurred
*/
esp_eth_phy_t *esp_eth_phy_new_lan87xx(const eth_phy_config_t *config);
/**
* @brief Create a PHY instance of DP83848
*
* @param[in] config: configuration of PHY
*
* @return
* - instance: create PHY instance successfully
* - NULL: create PHY instance failed because some error occurred
*/
esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config);
/**
* @brief Create a PHY instance of KSZ80xx
*
* The phy model from the KSZ80xx series is detected automatically. If the driver
* is unable to detect a supported model, \c NULL is returned.
*
* Currently, the following models are supported:
* KSZ8001, KSZ8021, KSZ8031, KSZ8041, KSZ8051, KSZ8061, KSZ8081, KSZ8091
*
* @param[in] config: configuration of PHY
*
* @return
* - instance: create PHY instance successfully
* - NULL: create PHY instance failed because some error occurred
*/
esp_eth_phy_t *esp_eth_phy_new_ksz80xx(const eth_phy_config_t *config);
#if CONFIG_ETH_SPI_ETHERNET_DM9051
/**
* @brief Create a PHY instance of DM9051
*
* @param[in] config: configuration of PHY
*
* @return
* - instance: create PHY instance successfully
* - NULL: create PHY instance failed because some error occurred
*/
esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config);
#endif
#if CONFIG_ETH_SPI_ETHERNET_W5500
/**
* @brief Create a PHY instance of W5500
*
* @param[in] config: configuration of PHY
*
* @return
* - instance: create PHY instance successfully
* - NULL: create PHY instance failed because some error occurred
*/
esp_eth_phy_t *esp_eth_phy_new_w5500(const eth_phy_config_t *config);
#endif
#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
/**
* @brief Create a PHY instance of KSZ8851SNL
*
* @param[in] config: configuration of PHY
*
* @return
* - instance: create PHY instance successfully
* - NULL: create PHY instance failed because some error occurred
*/
esp_eth_phy_t *esp_eth_phy_new_ksz8851snl(const eth_phy_config_t *config);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -1,195 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth_phy_802_3.h"
static const char *TAG = "dp83848";
/***************Vendor Specific Register***************/
/**
* @brief PHYSTS(PHY Status Register)
*
*/
typedef union {
struct {
uint32_t link_status : 1; /* Link Status */
uint32_t speed_status : 1; /* Speed Status */
uint32_t duplex_status : 1; /* Duplex Status */
uint32_t loopback_status : 1; /* MII Loopback */
uint32_t auto_nego_complete : 1; /* Auto-Negotiation Complete */
uint32_t jabber_detect : 1; /* Jabber Detect */
uint32_t remote_fault : 1; /* Remote Fault */
uint32_t mii_interrupt : 1; /* MII Interrupt Pending */
uint32_t page_received : 1; /* Link Code Word Page Received */
uint32_t descrambler_lock : 1; /* Descrambler Lock */
uint32_t signal_detect : 1; /* Signal Detect */
uint32_t false_carrier_sense_latch : 1; /* False Carrier Sense Latch */
uint32_t polarity_status : 1; /* Polarity Status */
uint32_t receive_error_latch : 1; /* Receive Error Latch */
uint32_t mdix_mode : 1; /* MDI-X mode reported by auto-negotiation */
uint32_t reserved : 1; /* Reserved */
};
uint32_t val;
} physts_reg_t;
#define ETH_PHY_STS_REG_ADDR (0x10)
/**
* @brief PHYCR(PHY Control Register)
*
*/
typedef union {
struct {
uint32_t phy_addr : 5; /* PHY Address */
uint32_t led_cfg : 2; /* LED Configuration Modes */
uint32_t bypass_led_stretching : 1; /* Bypass LED Stretching */
uint32_t bist_start : 1; /* BIST Start */
uint32_t bist_status : 1; /* BIST Test Status */
uint32_t psr_15 : 1; /* BIST Sequence select */
uint32_t bist_force_error : 1; /* BIST Force Error */
uint32_t pause_trans_negotiate : 1; /* Pause Transmit Negotiated Status */
uint32_t pause_receive_negotiat : 1; /* Pause Receive Negotiated Status */
uint32_t force_mdix : 1; /* Force MDIX */
uint32_t en_auto_mdix : 1; /* Auto-MDIX Enable */
};
uint32_t val;
} phycr_reg_t;
#define ETH_PHY_CR_REG_ADDR (0x19)
typedef struct {
phy_802_3_t phy_802_3;
} phy_dp83848_t;
static esp_err_t dp83848_update_link_duplex_speed(phy_dp83848_t *dp83848)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = dp83848->phy_802_3.eth;
uint32_t addr = dp83848->phy_802_3.addr;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
uint32_t peer_pause_ability = false;
anlpar_reg_t anlpar;
physts_reg_t physts;
bmsr_reg_t bmsr;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (dp83848->phy_802_3.link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_STS_REG_ADDR, &(physts.val)), err, TAG, "read PHYSTS failed");
if (physts.speed_status) {
speed = ETH_SPEED_10M;
} else {
speed = ETH_SPEED_100M;
}
if (physts.duplex_status) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
/* if we're in duplex mode, and peer has the flow control ability */
if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
peer_pause_ability = 1;
} else {
peer_pause_ability = 0;
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability), err, TAG, "change pause ability failed");
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
dp83848->phy_802_3.link_status = link;
}
return ESP_OK;
err:
return ret;
}
static esp_err_t dp83848_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_dp83848_t *dp83848 = __containerof(esp_eth_phy_into_phy_802_3(phy), phy_dp83848_t, phy_802_3);
/* Update information about link, speed, duplex */
ESP_GOTO_ON_ERROR(dp83848_update_link_duplex_speed(dp83848), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t dp83848_autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
esp_eth_mediator_t *eth = phy_802_3->eth;
if (cmd == ESP_ETH_PHY_AUTONEGO_EN) {
bmcr_reg_t bmcr;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, phy_802_3->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
ESP_GOTO_ON_FALSE(bmcr.en_loopback == 0, ESP_ERR_INVALID_STATE, err, TAG, "Autonegotiation can't be enabled while in loopback operation");
}
return esp_eth_phy_802_3_autonego_ctrl(phy_802_3, cmd, autonego_en_stat);
err:
return ret;
}
static esp_err_t dp83848_loopback(esp_eth_phy_t *phy, bool enable)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
bool auto_nego_en = true;
ESP_GOTO_ON_ERROR(dp83848_autonego_ctrl(phy, ESP_ETH_PHY_AUTONEGO_G_STAT, &auto_nego_en), err, TAG, "get status of autonegotiation failed");
ESP_GOTO_ON_FALSE(!(auto_nego_en && enable), ESP_ERR_INVALID_STATE, err, TAG, "Unable to set loopback while autonegotiation is enabled. Disable it to use loopback");
return esp_eth_phy_802_3_loopback(phy_802_3, enable);
err:
return ret;
}
static esp_err_t dp83848_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
/* Basic PHY init */
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_basic_phy_init(phy_802_3), err, TAG, "failed to init PHY");
/* Check PHY ID */
uint32_t oui;
uint8_t model;
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_oui(phy_802_3, &oui), err, TAG, "read OUI failed");
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_manufac_info(phy_802_3, &model, NULL), err, TAG, "read manufacturer's info failed");
ESP_GOTO_ON_FALSE(oui == 0x80017 && model == 0x09, ESP_FAIL, err, TAG, "wrong chip ID");
return ESP_OK;
err:
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config)
{
esp_eth_phy_t *ret = NULL;
phy_dp83848_t *dp83848 = calloc(1, sizeof(phy_dp83848_t));
ESP_GOTO_ON_FALSE(dp83848, NULL, err, TAG, "calloc dp83848 failed");
ESP_GOTO_ON_FALSE(esp_eth_phy_802_3_obj_config_init(&dp83848->phy_802_3, config) == ESP_OK,
NULL, err, TAG, "configuration initialization of PHY 802.3 failed");
// redefine functions which need to be customized for sake of dp83848
dp83848->phy_802_3.parent.init = dp83848_init;
dp83848->phy_802_3.parent.get_link = dp83848_get_link;
dp83848->phy_802_3.parent.autonego_ctrl = dp83848_autonego_ctrl;
dp83848->phy_802_3.parent.loopback = dp83848_loopback;
return &dp83848->phy_802_3.parent;
err:
if (dp83848 != NULL) {
free(dp83848);
}
return ret;
}

View File

@@ -1,222 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_eth_phy_802_3.h"
static const char *TAG = "ip101";
#define IP101_PHY_RESET_ASSERTION_TIME_US 10000
#define IP101_PHY_POST_RESET_INIT_TIME_MS 10
/***************Vendor Specific Register***************/
/**
* @brief PCR(Page Control Register)
*
*/
typedef union {
struct {
uint32_t register_page_select : 5; /* Select register page, default is 16 */
uint32_t reserved : 11; /* Reserved */
};
uint32_t val;
} pcr_reg_t;
#define ETH_PHY_PCR_REG_ADDR (0x14)
/**
* @brief ISR(Interrupt Status Register), Page 16
*
*/
typedef union {
struct {
uint32_t link_changed : 1; /* Flag to indicate link status change interrupt */
uint32_t duplex_changed : 1; /* Flag to indicate duplex change interrupt */
uint32_t speed_changed : 1; /* Flag to indicate speed change interrupt */
uint32_t intr_status : 1; /* Flag to indicate interrupt status */
uint32_t reserved1 : 4; /* Reserved */
uint32_t link_mask : 1; /* Mask link change interrupt */
uint32_t duplex_mask : 1; /* Mask duplex change interrupt */
uint32_t speed_mask : 1; /* Mask speed change interrupt */
uint32_t all_mask : 1; /* Mask all interrupt */
uint32_t reserved2 : 3; /* Reserved */
uint32_t use_intr_pin : 1; /* Set high to use INTR and INTR_32 as an interrupt pin */
};
uint32_t val;
} isr_reg_t;
#define ETH_PHY_ISR_REG_ADDR (0x11)
/**
* @brief PHY MDI/MDIX Control and Specific Status Register, Page 16
*
*/
typedef union {
struct {
uint32_t op_mode : 3; /* Operation Mode Indicator */
uint32_t force_mdix : 1; /* Force the MDIX channel to be selected */
uint32_t reserved1 : 4; /* Reserved */
uint32_t link_up : 1; /* Indicate the link status is OK or FAIL */
uint32_t reserved2 : 7; /* Reserved */
};
uint32_t val;
} cssr_reg_t;
#define ETH_PHY_CSSR_REG_ADDR (0x1E)
/**
* @brief PSCR(PHY Specific Control Register), Page 1
*
*/
typedef union {
struct {
uint32_t reserved1 : 7; /* Reserved */
uint32_t force_link_100 : 1; /* Force Link 100 */
uint32_t force_link_10 : 1; /* Force Link 10 */
uint32_t reserved2 : 7; /* Reserved */
};
uint32_t val;
} pscr_reg_t;
#define ETH_PHY_PSCR_REG_ADDR (0x11)
typedef struct {
phy_802_3_t phy_802_3;
} phy_ip101_t;
static esp_err_t ip101_page_select(phy_ip101_t *ip101, uint32_t page)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = ip101->phy_802_3.eth;
pcr_reg_t pcr = {
.register_page_select = page
};
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ip101->phy_802_3.addr, ETH_PHY_PCR_REG_ADDR, pcr.val), err, TAG, "write PCR failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t ip101_update_link_duplex_speed(phy_ip101_t *ip101)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = ip101->phy_802_3.eth;
uint32_t addr = ip101->phy_802_3.addr;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
uint32_t peer_pause_ability = false;
cssr_reg_t cssr;
anlpar_reg_t anlpar;
ESP_GOTO_ON_ERROR(ip101_page_select(ip101, 16), err, TAG, "select page 16 failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_CSSR_REG_ADDR, &(cssr.val)), err, TAG, "read CSSR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
eth_link_t link = cssr.link_up ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (ip101->phy_802_3.link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
switch (cssr.op_mode) {
case 1: //10M Half
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_HALF;
break;
case 2: //100M Half
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_HALF;
break;
case 5: //10M Full
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_FULL;
break;
case 6: //100M Full
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_FULL;
break;
default:
break;
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
/* if we're in duplex mode, and peer has the flow control ability */
if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
peer_pause_ability = 1;
} else {
peer_pause_ability = 0;
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability), err, TAG, "change pause ability failed");
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
ip101->phy_802_3.link_status = link;
}
return ESP_OK;
err:
return ret;
}
static esp_err_t ip101_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_ip101_t *ip101 = __containerof(esp_eth_phy_into_phy_802_3(phy), phy_ip101_t, phy_802_3);
/* Update information about link, speed, duplex */
ESP_GOTO_ON_ERROR(ip101_update_link_duplex_speed(ip101), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t ip101_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
/* Basic PHY init */
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_basic_phy_init(phy_802_3), err, TAG, "failed to init PHY");
/* Check PHY ID */
uint32_t oui;
uint8_t model;
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_oui(phy_802_3, &oui), err, TAG, "read OUI failed");
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_manufac_info(phy_802_3, &model, NULL), err, TAG, "read manufacturer's info failed");
ESP_GOTO_ON_FALSE(oui == 0x90C3 && model == 0x5, ESP_FAIL, err, TAG, "wrong chip ID");
return ESP_OK;
err:
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config)
{
esp_eth_phy_t *ret = NULL;
phy_ip101_t *ip101 = calloc(1, sizeof(phy_ip101_t));
ESP_GOTO_ON_FALSE(ip101, NULL, err, TAG, "calloc ip101 failed");
eth_phy_config_t ip101_config = *config;
// default chip specific configuration
if (config->hw_reset_assert_time_us == 0) {
ip101_config.hw_reset_assert_time_us = IP101_PHY_RESET_ASSERTION_TIME_US;
}
if (config->post_hw_reset_delay_ms == 0) {
ip101_config.post_hw_reset_delay_ms = IP101_PHY_POST_RESET_INIT_TIME_MS;
}
ESP_GOTO_ON_FALSE(esp_eth_phy_802_3_obj_config_init(&ip101->phy_802_3, &ip101_config) == ESP_OK,
NULL, err, TAG, "configuration initialization of PHY 802.3 failed");
// redefine functions which need to be customized for sake of IP101
ip101->phy_802_3.parent.init = ip101_init;
ip101->phy_802_3.parent.get_link = ip101_get_link;
return &ip101->phy_802_3.parent;
err:
if (ip101 != NULL) {
free(ip101);
}
return ret;
}

View File

@@ -1,219 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include <inttypes.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth_phy_802_3.h"
#define KSZ80XX_PHY_ID_MSB (0x22)
#define KSZ80XX_PHY_ID_LSB (0x05)
#define KSZ80XX_PHY_OUI (KSZ80XX_PHY_ID_MSB << 6 | KSZ80XX_PHY_ID_LSB)
#define KSZ80XX_PC1R_REG_ADDR (0x1E)
#define KSZ80XX_PC2R_REG_ADDR (0x1F)
typedef enum
{
KSZ80XX_MODEL_NUMBER_11 = 0x11, // KSZ8041
KSZ80XX_MODEL_NUMBER_13 = 0x13, // KSZ8041RLNI
KSZ80XX_MODEL_NUMBER_15 = 0x15, // KSZ8021/31
KSZ80XX_MODEL_NUMBER_16 = 0x16, // KSZ8051/81/91
KSZ80XX_MODEL_NUMBER_17 = 0x17, // KSZ8061
KSZ80XX_MODEL_NUMBER_21 = 0x21, // KSZ8001
} ksz80xx_model_number_t;
typedef struct
{
phy_802_3_t phy_802_3;
uint8_t model_number;
uint32_t op_mode_reg;
uint32_t op_mode_offset;
} phy_ksz80xx_t;
static const uint8_t supported_model_numbers[] =
{
KSZ80XX_MODEL_NUMBER_11,
KSZ80XX_MODEL_NUMBER_13,
KSZ80XX_MODEL_NUMBER_15,
KSZ80XX_MODEL_NUMBER_16,
KSZ80XX_MODEL_NUMBER_17,
KSZ80XX_MODEL_NUMBER_21,
};
static const char *model_names[] = {
"41", // models with model number 0x11
"41RLNI", // models with model number 0x13
"21/31", // models with model number 0x15
"51/81/91", // models with model number 0x16
"61", // models with model number 0x17
"01", // models with model number 0x21
};
static const char *TAG = "ksz80xx";
static esp_err_t ksz80xx_update_link_duplex_speed(phy_ksz80xx_t * ksz80xx)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = ksz80xx->phy_802_3.eth;
uint32_t addr = ksz80xx->phy_802_3.addr;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
uint32_t peer_pause_ability = false;
anlpar_reg_t anlpar;
bmsr_reg_t bmsr;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (ksz80xx->phy_802_3.link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
uint32_t reg_value = 0;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ksz80xx->op_mode_reg, &reg_value), err, TAG, "read %#04" PRIx32 " failed", ksz80xx->op_mode_reg);
uint8_t op_mode = (reg_value >> ksz80xx->op_mode_offset) & 0x07;
switch (op_mode) {
case 1: //10Base-T half-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_HALF;
break;
case 2: //100Base-TX half-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_HALF;
break;
case 5: //10Base-T full-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_FULL;
break;
case 6: //100Base-TX full-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_FULL;
break;
default:
break;
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
/* if we're in duplex mode, and peer has the flow control ability */
if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
peer_pause_ability = 1;
} else {
peer_pause_ability = 0;
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability), err, TAG, "change pause ability failed");
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
ksz80xx->phy_802_3.link_status = link;
}
return ESP_OK;
err:
return ret;
}
static esp_err_t ksz80xx_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_ksz80xx_t *ksz80xx = __containerof(esp_eth_phy_into_phy_802_3(phy), phy_ksz80xx_t, phy_802_3);
/* Update information about link, speed, duplex */
ESP_GOTO_ON_ERROR(ksz80xx_update_link_duplex_speed(ksz80xx), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ret;
}
static bool ksz80xx_init_model(phy_ksz80xx_t *ksz80xx)
{
// set variables for op_mode access
switch (ksz80xx->model_number) {
case KSZ80XX_MODEL_NUMBER_21: // models KSZ8001
case KSZ80XX_MODEL_NUMBER_11: // models KSZ8041
case KSZ80XX_MODEL_NUMBER_13: // models KSZ8041RLNI
ksz80xx->op_mode_reg = KSZ80XX_PC2R_REG_ADDR;
ksz80xx->op_mode_offset = 2; // bits 4:2
break;
case KSZ80XX_MODEL_NUMBER_15: // models KSZ8021/31
case KSZ80XX_MODEL_NUMBER_16: // models KSZ8051/81/91
case KSZ80XX_MODEL_NUMBER_17: // models KSZ8061
ksz80xx->op_mode_reg = KSZ80XX_PC1R_REG_ADDR;
ksz80xx->op_mode_offset = 0; // bits 2:0
break;
default:
return false;
}
return true;
}
static esp_err_t ksz80xx_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
phy_ksz80xx_t *ksz80xx = __containerof(phy_802_3, phy_ksz80xx_t, phy_802_3);
/* Basic PHY init */
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_basic_phy_init(phy_802_3), err, TAG, "failed to init PHY");
/* Check PHY ID */
uint32_t oui;
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_oui(phy_802_3, &oui), err, TAG, "read OUI failed");
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_manufac_info(phy_802_3, &ksz80xx->model_number, NULL), err, TAG, "read manufacturer's info failed");
ESP_GOTO_ON_FALSE(oui == KSZ80XX_PHY_OUI, ESP_FAIL, err, TAG, "wrong chip ID");
const char* supported_model_name = NULL;
for (size_t i = 0; i < sizeof(supported_model_numbers); i++) {
if (ksz80xx->model_number == supported_model_numbers[i]) {
supported_model_name = model_names[i];
break;
}
}
ESP_GOTO_ON_FALSE(supported_model_name != NULL && ksz80xx_init_model(ksz80xx), ESP_FAIL, err, TAG, "unsupported model number: %#04" PRIx8, ksz80xx->model_number);
ESP_LOGI(TAG, "auto detected phy KSZ80%s", supported_model_name);
return ESP_OK;
err:
return ret;
}
static esp_err_t ksz80xx_set_speed(esp_eth_phy_t *phy, eth_speed_t speed)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
esp_eth_mediator_t *eth = phy_802_3->eth;
/* Check if loopback is enabled, and if so, can it work with proposed speed or not */
bmcr_reg_t bmcr;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, phy_802_3->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (bmcr.en_loopback) {
ESP_GOTO_ON_FALSE(speed == ETH_SPEED_100M, ESP_ERR_INVALID_STATE, err, TAG, "Speed must be 100M for loopback operation");
}
return esp_eth_phy_802_3_set_speed(phy_802_3, speed);
err:
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_ksz80xx(const eth_phy_config_t *config)
{
esp_eth_phy_t *ret = NULL;
phy_ksz80xx_t *ksz80xx = calloc(1, sizeof(phy_ksz80xx_t));
ESP_GOTO_ON_FALSE(ksz80xx, NULL, err, TAG, "calloc ksz80xx failed");
ESP_GOTO_ON_FALSE(esp_eth_phy_802_3_obj_config_init(&ksz80xx->phy_802_3, config) == ESP_OK,
NULL, err, TAG, "configuration initialization of PHY 802.3 failed");
// redefine functions which need to be customized for sake of ksz80xx
ksz80xx->phy_802_3.parent.init = ksz80xx_init;
ksz80xx->phy_802_3.parent.get_link = ksz80xx_get_link;
ksz80xx->phy_802_3.parent.set_speed = ksz80xx_set_speed;
return &ksz80xx->phy_802_3.parent;
err:
if (ksz80xx != NULL) {
free(ksz80xx);
}
return ret;
}

View File

@@ -1,390 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth_phy_802_3.h"
static const char *TAG = "lan87xx";
/* It was observed that assert nRST signal on LAN87xx needs to be a little longer than the minimum specified in datasheet */
#define LAN87XX_PHY_RESET_ASSERTION_TIME_US 150
/***************List of Supported Models***************/
// See Microchip's Application Note AN25.3 summarizing differences among below models
#define LAN8710A_MODEL_NUM 0x0F
#define LAN8720A_MODEL_NUM 0x0F
#define LAN8740A_MODEL_NUM 0x11
#define LAN8741A_MODEL_NUM 0x12
#define LAN8742A_MODEL_NUM 0x13
static const uint8_t supported_models[] = {
LAN8710A_MODEL_NUM,
#if (LAN8710A_MODEL_NUM != LAN8720A_MODEL_NUM)
LAN8720A_MODEL_NUM,
#endif
LAN8740A_MODEL_NUM,
LAN8741A_MODEL_NUM,
LAN8742A_MODEL_NUM
};
/***************Vendor Specific Register***************/
/**
* @brief MCSR(Mode Control Status Register)
*
*/
typedef union {
struct {
uint32_t reserved1 : 1; /* Reserved */
uint32_t energy_is_on : 1; /* Energy is On */
uint32_t reserved2 : 4; /* Reserved */
uint32_t en_alternate_interrupt : 1; /* Enable Alternate Interrupt Mode */
uint32_t reserved3 : 2; /* Reserved */
uint32_t en_far_loopback : 1; /* Enable Far Loopback Mode */
uint32_t reserved4 : 3; /* Reserved */
uint32_t en_energy_detect_powerdown : 1; /* Enable Energy Detect Power Down */
uint32_t reserved5 : 2; /* Reserved */
};
uint32_t val;
} mcsr_reg_t;
#define ETH_PHY_MCSR_REG_ADDR (0x11)
/**
* @brief SMR(Special Modes Register)
*
*/
typedef union {
struct {
uint32_t phy_addr : 5; /* PHY Address */
uint32_t mode : 3; /* Transceiver Mode of Operation */
uint32_t reserved_1 : 6; /* Reserved */
uint32_t mii_mode : 1; /* Mode of the digital interface (only LAN8710A/LAN8740A/LAN8741A) */
uint32_t reserved_2 : 1; /* Reserved */
};
uint32_t val;
} smr_reg_t;
#define ETH_PHY_SMR_REG_ADDR (0x12)
/**
* @brief Time Domain Reflectometry Patterns/Delay Control Register
* Only available in LAN8740A/LAN8742A
*/
typedef union {
struct {
uint32_t tdr_pattern_low : 6; /* Data pattern sent in TDR mode for the low cycle */
uint32_t tdr_pattern_high : 6; /* Data pattern sent in TDR mode for the high cycle */
uint32_t tdr_line_break_counter : 3; /* Increments of 256ms of break time */
uint32_t tdr_delay_in : 1; /* Line break counter used */
};
uint32_t val;
} tdr_pattern_reg_t;
#define EHT_PHY_TDRPD_REG_ADDR (0x18)
/**
* @brief Time Domain Reflectometry Control/Status Register)
* Only available in LAN8740A/LAN8742A
*/
typedef union {
struct {
uint32_t tdr_channel_length : 8; /* TDR channel length */
uint32_t tdr_channel_status : 1; /* TDR channel status */
uint32_t tdr_channel_cable_type : 2; /* TDR channel cable type */
uint32_t reserved : 3; /* Reserved */
uint32_t tdr_a2d_filter_enable: 1; /* Analog to Digital Filter Enabled */
uint32_t tdr_enable : 1; /* Enable TDR */
};
uint32_t val;
} tdr_control_reg_t;
#define EHT_PHY_TDRC_REG_ADDR (0x19)
/**
* @brief SECR(Symbol Error Counter Register)
*
*/
typedef union {
struct {
uint32_t symbol_err_count : 16; /* Symbol Error Counter */
};
uint32_t val;
} secr_reg_t;
#define EHT_PHY_SECR_REG_ADDR (0x1A)
/**
* @brief CSIR(Control Status Indications Register)
*
*/
typedef union {
struct {
uint32_t reserved1 : 4; /* Reserved */
uint32_t base10_t_polarity : 1; /* Polarity State of 10Base-T */
uint32_t reserved2 : 6; /* Reserved */
uint32_t dis_sqe : 1; /* Disable SQE test(Heartbeat) */
uint32_t reserved3 : 1; /* Reserved */
uint32_t select_channel : 1; /* Manual channel select:MDI(0) or MDIX(1) */
uint32_t reserved4 : 1; /* Reserved */
uint32_t auto_mdix_ctrl : 1; /* Auto-MDIX Control: EN(0) or DE(1) */
};
uint32_t val;
} scsir_reg_t;
#define ETH_PHY_CSIR_REG_ADDR (0x1B)
/**
* @brief Cable Length Register
* Only available in LAN8740A/LAN8742A
*/
typedef union {
struct {
uint32_t reserved : 12; /* Reserved */
uint32_t cable_length : 4; /* Cable length */
};
uint32_t val;
} cbln_reg_t;
#define EHT_PHY_CBLN_REG_ADDR (0x1C)
/**
* @brief ISR(Interrupt Source Register)
*
*/
typedef union {
struct {
uint32_t reserved1 : 1; /* Reserved */
uint32_t auto_nego_page_received : 1; /* Auto-Negotiation Page Received */
uint32_t parallel_detect_fault : 1; /* Parallel Detection Fault */
uint32_t auto_nego_lp_acknowledge : 1; /* Auto-Negotiation LP Acknowledge */
uint32_t link_down : 1; /* Link Down */
uint32_t remote_fault_detect : 1; /* Remote Fault Detect */
uint32_t auto_nego_complete : 1; /* Auto-Negotiation Complete */
uint32_t energy_on_generate : 1; /* ENERGY ON generated */
uint32_t wake_on_lan : 1; /* Wake on Lan (WOL) event detected (only LAN8740A/LAN8742A) */
uint32_t reserved2 : 7; /* Reserved */
};
uint32_t val;
} isfr_reg_t;
#define ETH_PHY_ISR_REG_ADDR (0x1D)
/**
* @brief IMR(Interrupt Mask Register)
*
*/
typedef union {
struct {
uint32_t reserved1 : 1; /* Reserved */
uint32_t auto_nego_page_received : 1; /* Auto-Negotiation Page Received */
uint32_t parallel_detect_fault : 1; /* Parallel Detection Fault */
uint32_t auto_nego_lp_acknowledge : 1; /* Auto-Negotiation LP Acknowledge */
uint32_t link_down : 1; /* Link Down */
uint32_t remote_fault_detect : 1; /* Remote Fault Detect */
uint32_t auto_nego_complete : 1; /* Auto-Negotiation Complete */
uint32_t energy_on_generate : 1; /* ENERGY ON generated */
uint32_t wake_on_lan : 1; /* Wake on Lan (WOL) event detected (only LAN8740A/LAN8742A) */
uint32_t reserved2 : 7; /* Reserved */
};
uint32_t val;
} imr_reg_t;
#define ETH_PHY_IMR_REG_ADDR (0x1E)
/**
* @brief PSCSR(PHY Special Control Status Register)
*
*/
typedef union {
struct {
uint32_t reserved1 : 2; /* Reserved */
uint32_t speed_indication : 3; /* Speed Indication */
uint32_t reserved2 : 1; /* Reserved */
uint32_t enable_4b5b : 1; /* Enable 4B5B encoder (only LAN8740A/LAN8741A) */
uint32_t reserved3 : 5; /* Reserved */
uint32_t auto_nego_done : 1; /* Auto Negotiation Done */
uint32_t reserved4 : 3; /* Reserved */
};
uint32_t val;
} pscsr_reg_t;
#define ETH_PHY_PSCSR_REG_ADDR (0x1F)
typedef struct {
phy_802_3_t phy_802_3;
} phy_lan87xx_t;
static esp_err_t lan87xx_update_link_duplex_speed(phy_lan87xx_t *lan87xx)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = lan87xx->phy_802_3.eth;
uint32_t addr = lan87xx->phy_802_3.addr;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
bmsr_reg_t bmsr;
bmcr_reg_t bmcr;
pscsr_reg_t pscsr;
uint32_t peer_pause_ability = false;
anlpar_reg_t anlpar;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
/* link status is forced up because LAN87xx reports link down when loopback is enabled and cable is unplugged */
eth_link_t link;
if(bmcr.en_loopback) {
link = ETH_LINK_UP;
} else {
link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
}
/* check if link status changed */
if (lan87xx->phy_802_3.link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)), err, TAG, "read PSCSR failed");
switch (pscsr.speed_indication) {
case 1: //10Base-T half-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_HALF;
break;
case 2: //100Base-TX half-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_HALF;
break;
case 5: //10Base-T full-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_FULL;
break;
case 6: //100Base-TX full-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_FULL;
break;
default:
break;
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
/* if we're in duplex mode, and peer has the flow control ability */
if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
peer_pause_ability = 1;
} else {
peer_pause_ability = 0;
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability), err, TAG, "change pause ability failed");
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
lan87xx->phy_802_3.link_status = link;
}
return ESP_OK;
err:
return ret;
}
static esp_err_t lan87xx_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_lan87xx_t *lan87xx = __containerof(esp_eth_phy_into_phy_802_3(phy), phy_lan87xx_t, phy_802_3);
/* Updata information about link, speed, duplex */
ESP_GOTO_ON_ERROR(lan87xx_update_link_duplex_speed(lan87xx), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t lan87xx_autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
esp_eth_mediator_t *eth = phy_802_3->eth;
if (cmd == ESP_ETH_PHY_AUTONEGO_EN) {
bmcr_reg_t bmcr;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, phy_802_3->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
ESP_GOTO_ON_FALSE(bmcr.en_loopback == 0, ESP_ERR_INVALID_STATE, err, TAG, "Autonegotiation can't be enabled while in loopback operation");
}
return esp_eth_phy_802_3_autonego_ctrl(phy_802_3, cmd, autonego_en_stat);
err:
return ret;
}
static esp_err_t lan87xx_loopback(esp_eth_phy_t *phy, bool enable)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
bool auto_nego_en;
ESP_GOTO_ON_ERROR(lan87xx_autonego_ctrl(phy, ESP_ETH_PHY_AUTONEGO_G_STAT, &auto_nego_en), err, TAG, "get status of autonegotiation failed");
ESP_GOTO_ON_FALSE(!(auto_nego_en && enable), ESP_ERR_INVALID_STATE, err, TAG, "Unable to set loopback while autonegotiation is enabled. Disable it to use loopback");
return esp_eth_phy_802_3_loopback(phy_802_3, enable);
err:
return ret;
}
static esp_err_t lan87xx_set_speed(esp_eth_phy_t *phy, eth_speed_t speed)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
/* It was observed that a delay needs to be introduced after setting speed and prior driver's start.
Otherwise, the very first read of PHY registers is not valid data (0xFFFF's). */
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_set_speed(phy_802_3, speed), err, TAG, "set speed failed");
vTaskDelay(pdMS_TO_TICKS(10));
err:
return ret;
}
static esp_err_t lan87xx_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
/* Basic PHY init */
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_basic_phy_init(phy_802_3), err, TAG, "failed to init PHY");
/* Check PHY ID */
uint32_t oui;
uint8_t model;
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_oui(phy_802_3, &oui), err, TAG, "read OUI failed");
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_manufac_info(phy_802_3, &model, NULL), err, TAG, "read manufacturer's info failed");
ESP_GOTO_ON_FALSE(oui == 0x1F0, ESP_FAIL, err, TAG, "wrong chip OUI");
bool supported_model = false;
for (unsigned int i = 0; i < sizeof(supported_models); i++) {
if (model == supported_models[i]) {
supported_model = true;
break;
}
}
ESP_GOTO_ON_FALSE(supported_model, ESP_FAIL, err, TAG, "unsupported chip model");
return ESP_OK;
err:
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_lan87xx(const eth_phy_config_t *config)
{
esp_eth_phy_t *ret = NULL;
phy_lan87xx_t *lan87xx = calloc(1, sizeof(phy_lan87xx_t));
ESP_GOTO_ON_FALSE(lan87xx, NULL, err, TAG, "calloc lan87xx failed");
eth_phy_config_t lan87xx_config = *config;
// default chip specific configuration
if (config->hw_reset_assert_time_us == 0) {
lan87xx_config.hw_reset_assert_time_us = LAN87XX_PHY_RESET_ASSERTION_TIME_US;
}
if (config->post_hw_reset_delay_ms == 0) {
lan87xx_config.post_hw_reset_delay_ms = ESP_ETH_NO_POST_HW_RESET_DELAY;
}
ESP_GOTO_ON_FALSE(esp_eth_phy_802_3_obj_config_init(&lan87xx->phy_802_3, &lan87xx_config) == ESP_OK,
NULL, err, TAG, "configuration initialization of PHY 802.3 failed");
// redefine functions which need to be customized for sake of LAN87xx
lan87xx->phy_802_3.parent.init = lan87xx_init;
lan87xx->phy_802_3.parent.get_link = lan87xx_get_link;
lan87xx->phy_802_3.parent.autonego_ctrl = lan87xx_autonego_ctrl;
lan87xx->phy_802_3.parent.loopback = lan87xx_loopback;
lan87xx->phy_802_3.parent.set_speed = lan87xx_set_speed;
return &lan87xx->phy_802_3.parent;
err:
if (lan87xx != NULL) {
free(lan87xx);
}
return ret;
}

View File

@@ -1,200 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_eth_phy_802_3.h"
#define RTL8201_PHY_RESET_ASSERTION_TIME_US 10000
#define RTL8201_PHY_POST_RESET_INIT_TIME_MS 150
static const char *TAG = "rtl8201";
/***************Vendor Specific Register***************/
/**
* @brief PSMR(Power Saving Mode Register)
*
*/
typedef union {
struct {
uint16_t reserved : 15; /* Reserved */
uint16_t en_pwr_save : 1; /* Enable power saving mode */
};
uint16_t val;
} psmr_reg_t;
#define ETH_PHY_PSMR_REG_ADDR (0x18)
/**
* @brief PSR(Page Select Register)
*
*/
typedef union {
struct {
uint16_t page_select : 8; /* Select register page, default is 0 */
uint16_t reserved : 8; /* Reserved */
};
uint16_t val;
} psr_reg_t;
#define ETH_PHY_PSR_REG_ADDR (0x1F)
typedef struct {
phy_802_3_t phy_802_3;
} phy_rtl8201_t;
static esp_err_t rtl8201_page_select(phy_rtl8201_t *rtl8201, uint32_t page)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = rtl8201->phy_802_3.eth;
psr_reg_t psr = {
.page_select = page
};
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, rtl8201->phy_802_3.addr, ETH_PHY_PSR_REG_ADDR, psr.val), err, TAG, "write PSR failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t rtl8201_update_link_duplex_speed(phy_rtl8201_t *rtl8201)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = rtl8201->phy_802_3.eth;
uint32_t addr = rtl8201->phy_802_3.addr;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
bmcr_reg_t bmcr;
bmsr_reg_t bmsr;
uint32_t peer_pause_ability = false;
anlpar_reg_t anlpar;
ESP_GOTO_ON_ERROR(rtl8201_page_select(rtl8201, 0), err, TAG, "select page 0 failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (rtl8201->phy_802_3.link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (bmcr.speed_select) {
speed = ETH_SPEED_100M;
} else {
speed = ETH_SPEED_10M;
}
if (bmcr.duplex_mode) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
/* if we're in duplex mode, and peer has the flow control ability */
if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
peer_pause_ability = 1;
} else {
peer_pause_ability = 0;
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability), err, TAG, "change pause ability failed");
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
rtl8201->phy_802_3.link_status = link;
}
return ESP_OK;
err:
return ret;
}
static esp_err_t rtl8201_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_rtl8201_t *rtl8201 = __containerof(esp_eth_phy_into_phy_802_3(phy), phy_rtl8201_t, phy_802_3);
/* Updata information about link, speed, duplex */
ESP_GOTO_ON_ERROR(rtl8201_update_link_duplex_speed(rtl8201), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t rtl8201_autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
esp_eth_mediator_t *eth = phy_802_3->eth;
if (cmd == ESP_ETH_PHY_AUTONEGO_EN) {
bmcr_reg_t bmcr;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, phy_802_3->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
ESP_GOTO_ON_FALSE(bmcr.en_loopback == 0, ESP_ERR_INVALID_STATE, err, TAG, "Autonegotiation can't be enabled while in loopback operation");
}
return esp_eth_phy_802_3_autonego_ctrl(phy_802_3, cmd, autonego_en_stat);
err:
return ret;
}
static esp_err_t rtl8201_loopback(esp_eth_phy_t *phy, bool enable)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
bool auto_nego_en;
ESP_GOTO_ON_ERROR(rtl8201_autonego_ctrl(phy, ESP_ETH_PHY_AUTONEGO_G_STAT, &auto_nego_en), err, TAG, "get status of autonegotiation failed");
ESP_GOTO_ON_FALSE(!(auto_nego_en && enable), ESP_ERR_INVALID_STATE, err, TAG, "Unable to set loopback while autonegotiation is enabled. Disable it to use loopback");
return esp_eth_phy_802_3_loopback(phy_802_3, enable);
err:
return ret;
}
static esp_err_t rtl8201_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
/* Basic PHY init */
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_basic_phy_init(phy_802_3), err, TAG, "failed to init PHY");
/* Check PHY ID */
uint32_t oui;
uint8_t model;
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_oui(phy_802_3, &oui), err, TAG, "read OUI failed");
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_manufac_info(phy_802_3, &model, NULL), err, TAG, "read manufacturer's info failed");
ESP_GOTO_ON_FALSE(oui == 0x732 && model == 0x1, ESP_FAIL, err, TAG, "wrong chip ID");
return ESP_OK;
err:
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config)
{
esp_eth_phy_t *ret = NULL;
phy_rtl8201_t *rtl8201 = calloc(1, sizeof(phy_rtl8201_t));
ESP_GOTO_ON_FALSE(rtl8201, NULL, err, TAG, "calloc rtl8201 failed");
eth_phy_config_t rtl8201_config = *config;
// default chip specific configuration
if (config->hw_reset_assert_time_us == 0) {
rtl8201_config.hw_reset_assert_time_us = RTL8201_PHY_RESET_ASSERTION_TIME_US;
}
if (config->post_hw_reset_delay_ms == 0) {
rtl8201_config.post_hw_reset_delay_ms = RTL8201_PHY_POST_RESET_INIT_TIME_MS;
}
ESP_GOTO_ON_FALSE(esp_eth_phy_802_3_obj_config_init(&rtl8201->phy_802_3, &rtl8201_config) == ESP_OK,
NULL, err, TAG, "configuration initialization of PHY 802.3 failed");
// redefine functions which need to be customized for sake of RTL8201
rtl8201->phy_802_3.parent.init = rtl8201_init;
rtl8201->phy_802_3.parent.get_link = rtl8201_get_link;
rtl8201->phy_802_3.parent.autonego_ctrl = rtl8201_autonego_ctrl;
rtl8201->phy_802_3.parent.loopback = rtl8201_loopback;
return &rtl8201->phy_802_3.parent;
err:
if (rtl8201 != NULL) {
free(rtl8201);
}
return ret;
}

View File

@@ -1,164 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Registers in DM9051
*
*/
#define DM9051_NCR (0x00) // Network Control Register
#define DM9051_NSR (0x01) // Network Status Register
#define DM9051_TCR (0x02) // Tx Control Register
#define DM9051_TSR1 (0x03) // Tx Status Register I
#define DM9051_TSR2 (0x04) // Tx Status Register II
#define DM9051_RCR (0x05) // Rx Control Register
#define DM9051_RSR (0x06) // Rx Status Register
#define DM9051_ROCR (0x07) // Receive Overflow Counter Register
#define DM9051_BPTR (0x08) // Back Pressure Threshold Register
#define DM9051_FCTR (0x09) // Flow Control Threshold Register
#define DM9051_FCR (0x0A) // Rx/Tx Flow Control Register
#define DM9051_EPCR (0x0B) // EEPROM & PHY Control Register
#define DM9051_EPAR (0x0C) // EEPROM & PHY Address Register
#define DM9051_EPDRL (0x0D) // EEPROM & PHY Data Register Low
#define DM9051_EPDRH (0x0E) // EEPROM & PHY Data Register High
#define DM9051_WCR (0x0F) // Wake Up Control Register
#define DM9051_PAR (0x10) // Physical Address Register
#define DM9051_MAR (0x16) // Multicast Address Hash Table Register
#define DM9051_GPCR (0x1E) // General Purpose Control Register
#define DM9051_GPR (0x1F) // General Purpose Register
#define DM9051_TRPAL (0x22) // Tx Memory Read Pointer Address Low Byte
#define DM9051_TRPAH (0x23) // Tx Memory Read Pointer Address High Byte
#define DM9051_RWPAL (0x24) // Rx Memory Read Pointer Address Low Byte
#define DM9051_RWPAH (0x25) // Rx Memory Read Pointer Address High Byte
#define DM9051_VIDL (0x28) // Vendor ID Low Byte
#define DM9051_VIDH (0x29) // Vendor ID High Byte
#define DM9051_PIDL (0x2A) // Product ID Low Byte
#define DM9051_PIDH (0x2B) // Product ID High Byte
#define DM9051_CHIPR (0x2C) // CHIP Revision
#define DM9051_TCR2 (0x2D) // Transmit Control Register 2
#define DM9051_ATCR (0x30) // Auto-Transmit Control Register
#define DM9051_TCSCR (0x31) // Transmit Check Sum Control Register
#define DM9051_RCSCSR (0x32) // Receive Check Sum Control Status Register
#define DM9051_SBCR (0x38) // SPI Bus Control Register
#define DM9051_INTCR (0x39) // INT Pin Control Register
#define DM9051_PPCSR (0x3D) // Pause Packet Control Status Register
#define DM9051_EEE_IN (0x3E) // IEEE 802.3az Enter Counter Register
#define DM9051_EEE_OUT (0x3F) // IEEE 802.3az Leave Counter Register
#define DM9051_ALNCR (0x4A) // SPI Byte Align Error Counter Register
#define DM9051_RLENCR (0x52) // Rx Packet Length Control Register
#define DM9051_BCASTCR (0x53) // RX Broadcast Control Register
#define DM9051_INTCKCR (0x54) // INT Pin Clock Output Control Register
#define DM9051_MPTRCR (0x55) // Memory Pointer Control Register
#define DM9051_MLEDCR (0x57) // More LED Control Register
#define DM9051_MEMSCR (0x59) // Memory Control Register
#define DM9051_TMEMR (0x5A) // Transmit Memory Size Register
#define DM9051_MBSR (0x5D) // Memory BIST Status Register
#define DM9051_MRCMDX (0x70) // Memory Data Pre-Fetch Read Command Without Address Increment Register
#define DM9051_MRCMDX1 (0x71) // Memory Read Command Without Pre-Fetch and Without Address Increment Register
#define DM9051_MRCMD (0x72) // Memory Data Read Command With Address Increment Register
#define DM9051_SDR_DLY (0x73) // SPI Data Read Delay Counter Register
#define DM9051_MRRL (0x74) // Memory Data Read Address Register Low Byte
#define DM9051_MRRH (0x75) // Memory Data Read Address Register High Byte
#define DM9051_MWCMDX (0x76) // Memory Data Write Command Without Address Increment Register
#define DM9051_MWCMD (0x78) // Memory Data Write Command With Address Increment Register
#define DM9051_MWRL (0x7A) // Memory Data Write Address Register Low Byte
#define DM9051_MWRH (0x7B) // Memory Data Write Address Register High Byte
#define DM9051_TXPLL (0x7C) // TX Packet Length Low Byte Register
#define DM9051_TXPLH (0x7D) // TX Packet Length High Byte Register
#define DM9051_ISR (0x7E) // Interrupt Status Register
#define DM9051_IMR (0x7F) // Interrupt Mask Register
/**
* @brief status and flag of DM9051 specific registers
*
*/
#define DM9051_SPI_RD (0) // Burst Read Command
#define DM9051_SPI_WR (1) // Burst Write Command
#define NCR_WAKEEN (1 << 6) // Enable Wakeup Function
#define NCR_FDX (1 << 3) // Duplex Mode of the Internal PHY
#define NCR_RST (1 << 0) // Software Reset and Auto-Clear after 10us
#define NSR_SPEED (1 << 7) // Speed of Internal PHY
#define NSR_LINKST (1 << 6) // Link Status of Internal PHY
#define NSR_WAKEST (1 << 5) // Wakeup Event Status
#define NSR_TX2END (1 << 3) // TX Packet Index II Complete Status
#define NSR_TX1END (1 << 2) // TX Packet Index I Complete Status
#define NSR_RXOV (1 << 1) // RX Memory Overflow Status
#define NSR_RXRDY (1 << 0) // RX Packet Ready
#define TCR_TXREQ (1 << 0) // TX Request. Auto-Clear after Sending Completely
#define RCR_WTDIS (1 << 6) // Watchdog Timer Disable
#define RCR_DIS_LONG (1 << 5) // Discard Long Packet
#define RCR_DIS_CRC (1 << 4) // Discard CRC Error Packet
#define RCR_ALL_MCAST (1 << 3) // Receive All Multicast
#define RCR_RUNT (1 << 2) // Receive Runt Packet
#define RCR_PRMSC (1 << 1) // Promiscuous Mode
#define RCR_RXEN (1 << 0) // RX Enable
#define RSR_RF (1 << 7) // Runt Frame
#define RSR_MF (1 << 6) // Multicast Frame
#define RSR_LCS (1 << 5) // Late Collision Seen
#define RSR_RWTO (1 << 4) // Receive Watchdog Time-Out
#define RSR_PLE (1 << 3) // Physical Layer Error
#define RSR_AE (1 << 2) // Alignment Error
#define RSR_CE (1 << 1) // CRC Error
#define RSR_FOE (1 << 0) // RX Memory Overflow Error
#define FCR_FLOW_ENABLE (0x39) // Enable Flow Control
#define EPCR_REEP (1 << 5) // Reload EEPROM
#define EPCR_WEP (1 << 4) // Write EEPROM Enable
#define EPCR_EPOS (1 << 3) // EEPROM or PHY Operation Select
#define EPCR_ERPRR (1 << 2) // EEPROM Read or PHY Register Read Command
#define EPCR_ERPRW (1 << 1) // EEPROM Write or PHY Register Write Command
#define EPCR_ERRE (1 << 0) // EEPROM Access Status or PHY Access Status
#define TCR2_RLCP (1 << 6) // Retry Late Collision Packet
#define ATCR_AUTO_TX (1 << 7) // Auto-Transmit Control
#define TCSCR_UDPCSE (1 << 2) // UDP CheckSum Generation
#define TCSCR_TCPCSE (1 << 1) // TCP CheckSum Generation
#define TCSCR_IPCSE (1 << 0) // IPv4 CheckSum Generation
#define MPTRCR_RST_TX (1 << 1) // Reset TX Memory Pointer
#define MPTRCR_RST_RX (1 << 0) // Reset RX Memory Pointer
#define ISR_LNKCHGS (1 << 5) // Link Status Change
#define ISR_ROO (1 << 3) // Receive Overflow Counter Overflow
#define ISR_ROS (1 << 2) // Receive Overflow
#define ISR_PT (1 << 1) // Packet Transmitted
#define ISR_PR (1 << 0) // Packet Received
#define ISR_CLR_STATUS (ISR_LNKCHGS | ISR_ROO | ISR_ROS | ISR_PT | ISR_PR)
#define IMR_PAR (1 << 7) // Pointer Auto-Return Mode
#define IMR_LNKCHGI (1 << 5) // Enable Link Status Change Interrupt
#define IMR_ROOI (1 << 3) // Enable Receive Overflow Counter Overflow Interrupt
#define IMR_ROI (1 << 2) // Enable Receive Overflow Interrupt
#define IMR_PTI (1 << 1) // Enable Packet Transmitted Interrupt
#define IMR_PRI (1 << 0) // Enable Packet Received Interrupt
#define IMR_ALL (IMR_PAR | IMR_LNKCHGI | IMR_ROOI | IMR_ROI | IMR_PTI | IMR_PRI)
#define MLEDCR_MOD3 (1 << 7) // New LED mode
#define MLEDCR_POL (1 << 2) // Reverse Polarity of LED Type
// | LED Type | LNKLED (pin 25) | SPDLED (pin 26) | FDXLED (pin 16) |
// |-----------------------------------|------------------|-----------------|-----------------|
#define MLEDCR_LED_TYPE_00 (0x00 << 0) // | Link | Traffic | Full-Duplex |
#define MLEDCR_LED_TYPE_01 (0x01 << 0) // | Link & Traffic | Speed100M | Full-Duplex |
#define MLEDCR_LED_TYPE_10 (0x02 << 0) // | Traffic | Speeed100M | Speed10M |
#define MLEDCR_LED_TYPE_11 (0x03 << 0) // | Link | Traffic100M | Traffic10M |
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,256 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth_phy_802_3.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static const char *TAG = "dm9051.phy";
/***************Vendor Specific Register***************/
/**
* @brief DSCR(DAVICOM Specified Configuration Register)
*
*/
typedef union {
struct {
uint32_t reserved1 : 1; /* Reserved */
uint32_t sleep : 1; /* Set 1 to enable PHY into sleep mode */
uint32_t mfpsc : 1; /* MII frame preamble suppression control bit */
uint32_t smrst : 1; /* Set 1 to reset all state machines of PHY */
uint32_t rpdctr_en : 1; /* Set 1 to enable automatic reduced power down */
uint32_t reserved2 : 2; /* Reserved */
uint32_t flink100 : 1; /* Force Good Link in 100Mbps */
uint32_t reserved3 : 2; /* Reserved */
uint32_t tx_fx : 1; /* 100BASE-TX or FX Mode Control */
uint32_t reserved4 : 1; /* Reserved */
uint32_t bp_adpok : 1; /* BYPASS ADPOK */
uint32_t bp_align : 1; /* Bypass Symbol Alignment Function */
uint32_t bp_scr : 1; /* Bypass Scrambler/Descrambler Function */
uint32_t bp_4b5b : 1; /* Bypass 4B5B Encoding and 5B4B Decoding */
};
uint32_t val;
} dscr_reg_t;
#define ETH_PHY_DSCR_REG_ADDR (0x10)
/**
* @brief DSCSR(DAVICOM Specified Configuration and Status Register)
*
*/
typedef union {
struct {
uint32_t anmb : 4; /* Auto-Negotiation Monitor Bits */
uint32_t phy_addr : 5; /* PHY Address */
uint32_t reserved : 3; /* Reserved */
uint32_t hdx10 : 1; /* 10M Half-Duplex Operation Mode */
uint32_t fdx10 : 1; /* 10M Full-Duplex Operation Mode */
uint32_t hdx100 : 1; /* 100M Half-Duplex Operation Mode */
uint32_t fdx100 : 1; /* 100M Full-Duplex Operation Mode */
};
uint32_t val;
} dscsr_reg_t;
#define ETH_PHY_DSCSR_REG_ADDR (0x11)
typedef union {
struct {
uint32_t pd_value : 1; /* 1 in this bit indicates power down */
uint32_t reserved1 : 1; /* Reserved */
uint32_t monsel0 : 1; /* Vendor monitor select */
uint32_t monsel1 : 1; /* Vendor monitor select */
uint32_t mdix_down : 1; /* Set 1 to disable HP Auto-MDIX */
uint32_t mdix_fix : 1; /* When mdix_down = 1, MDIX_CNTL value depend on the register value. */
uint32_t autoneg_lpbk : 1; /* Set 1 to enable autonegotiation loopback */
uint32_t mdxi_cntl : 1; /* Polarity of MDI/MDIX value */
uint32_t reserved2 : 1; /* Reserved */
uint32_t nway_pwr : 1; /* Set 1 to enable power savings during autonegotiation period */
uint32_t tx10m_pwr : 1; /* Set 1 to enable transmit power savings in 10BASE-T mode */
uint32_t preamblex : 1; /* When tx10m_pwr is set, the 10BASE-T transmit preamble count is reduced */
uint32_t force_fef : 1; /* Vendor test select control */
uint32_t force_txsd : 1; /* Set 1 to force SD signal OK in 100M */
uint32_t tstse0 : 1; /* Vendor test select control */
uint32_t tstse1 : 1; /* Vendor test select control */
};
uint32_t val;
} scr_reg_t;
#define ETH_PHY_SCR_REG_ADDR 0x14
typedef struct {
phy_802_3_t phy_802_3;
} phy_dm9051_t;
static esp_err_t dm9051_update_link_duplex_speed(phy_dm9051_t *dm9051)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = dm9051->phy_802_3.eth;
uint32_t addr = dm9051->phy_802_3.addr;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
uint32_t peer_pause_ability = false;
bmsr_reg_t bmsr;
bmcr_reg_t bmcr;
anlpar_reg_t anlpar;
// BMSR is a latch low register
// after power up, the first latched value must be 0, which means down
// to speed up power up link speed, double read this register as a workaround
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (dm9051->phy_802_3.link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
speed = bmcr.speed_select == 1 ? ETH_SPEED_100M : ETH_SPEED_10M;
duplex = bmcr.duplex_mode == 1 ? ETH_DUPLEX_FULL : ETH_DUPLEX_HALF;
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
/* if we're in duplex mode, and peer has the flow control ability */
if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
peer_pause_ability = 1;
} else {
peer_pause_ability = 0;
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability), err, TAG, "change pause ability failed");
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
dm9051->phy_802_3.link_status = link;
}
return ESP_OK;
err:
return ret;
}
static esp_err_t dm9051_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_dm9051_t *dm9051 = __containerof(esp_eth_phy_into_phy_802_3(phy), phy_dm9051_t, phy_802_3);
/* Update information about link, speed, duplex */
ESP_GOTO_ON_ERROR(dm9051_update_link_duplex_speed(dm9051), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t dm9051_reset(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_dm9051_t *dm9051 = __containerof(esp_eth_phy_into_phy_802_3(phy), phy_dm9051_t, phy_802_3);
uint32_t addr = dm9051->phy_802_3.addr;
dm9051->phy_802_3.link_status = ETH_LINK_DOWN;
esp_eth_mediator_t *eth = dm9051->phy_802_3.eth;
dscr_reg_t dscr;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)), err, TAG, "read DSCR failed");
dscr.smrst = 1;
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, addr, ETH_PHY_DSCR_REG_ADDR, dscr.val), err, TAG, "write DSCR failed");
bmcr_reg_t bmcr = {.reset = 1};
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
/* Wait for reset complete */
uint32_t to = 0;
for (to = 0; to < dm9051->phy_802_3.reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)), err, TAG, "read DSCR failed");
if (!bmcr.reset && !dscr.smrst) {
break;
}
}
ESP_GOTO_ON_FALSE(to < dm9051->phy_802_3.reset_timeout_ms / 10, ESP_FAIL, err, TAG, "PHY reset timeout");
return ESP_OK;
err:
return ret;
}
static esp_err_t dm9051_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
/* Basic PHY init */
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_basic_phy_init(phy_802_3), err, TAG, "failed to init PHY");
/* Check PHY ID */
uint32_t oui;
uint8_t model;
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_oui(phy_802_3, &oui), err, TAG, "read OUI failed");
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_manufac_info(phy_802_3, &model, NULL), err, TAG, "read manufacturer's info failed");
ESP_GOTO_ON_FALSE(oui == 0x606E && model == 0x0A, ESP_FAIL, err, TAG, "wrong chip ID");
return ESP_OK;
err:
return ret;
}
static esp_err_t dm9051_loopback(esp_eth_phy_t *phy, bool enable)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
esp_eth_mediator_t *eth = phy_802_3->eth;
/* Set Loopback function */
// Enable Auto-negotiation loopback in Specific control register
bmcr_reg_t bmcr;
scr_reg_t scr;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, phy_802_3->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, phy_802_3->addr, ETH_PHY_SCR_REG_ADDR, &(scr.val)), err, TAG, "read SCR failed");
if (enable) {
bmcr.en_loopback = 1;
scr.autoneg_lpbk = 1;
} else {
bmcr.en_loopback = 0;
scr.autoneg_lpbk = 0;
}
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, phy_802_3->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, phy_802_3->addr, ETH_PHY_SCR_REG_ADDR, scr.val), err, TAG, "write SCR failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t dm9051_set_speed(esp_eth_phy_t *phy, eth_speed_t speed)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
esp_eth_mediator_t *eth = phy_802_3->eth;
/* Check if loopback is enabled, and if so, can it work with proposed speed or not */
bmcr_reg_t bmcr;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, phy_802_3->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (bmcr.en_loopback) {
ESP_GOTO_ON_FALSE(speed == ETH_SPEED_100M, ESP_ERR_INVALID_STATE, err, TAG, "Speed must be 100M for loopback operation");
}
return esp_eth_phy_802_3_set_speed(phy_802_3, speed);
err:
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config)
{
esp_eth_phy_t *ret = NULL;
phy_dm9051_t *dm9051 = calloc(1, sizeof(phy_dm9051_t));
ESP_GOTO_ON_FALSE(dm9051, NULL, err, TAG, "calloc dm9051 failed");
ESP_GOTO_ON_FALSE(esp_eth_phy_802_3_obj_config_init(&dm9051->phy_802_3, config) == ESP_OK,
NULL, err, TAG, "configuration initialization of PHY 802.3 failed");
// redefine functions which need to be customized for sake of dm9051
dm9051->phy_802_3.parent.init = dm9051_init;
dm9051->phy_802_3.parent.reset = dm9051_reset;
dm9051->phy_802_3.parent.get_link = dm9051_get_link;
dm9051->phy_802_3.parent.loopback = dm9051_loopback;
dm9051->phy_802_3.parent.set_speed = dm9051_set_speed;
return &dm9051->phy_802_3.parent;
err:
if (dm9051 != NULL) {
free(dm9051);
}
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,392 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021 Vladimir Chistyakov
*
* SPDX-License-Identifier: MIT
*
* SPDX-FileContributor: 2021-2024 Espressif Systems (Shanghai) CO LTD
*/
#include <stdlib.h>
#include "esp_eth_phy.h"
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "esp_private/gpio.h"
#include "soc/io_mux_reg.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "ksz8851.h"
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
int32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
int reset_gpio_num;
} phy_ksz8851snl_t;
static const char *TAG = "ksz8851snl-phy";
static esp_err_t ksz8851_update_link_duplex_speed(phy_ksz8851snl_t *ksz8851)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = ksz8851->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
uint32_t status;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz8851->addr, KSZ8851_P1SR, &status), err, TAG, "P1SR read failed");
eth_link_t link = (status & P1SR_LINK_GOOD) ? ETH_LINK_UP : ETH_LINK_DOWN;
if (ksz8851->link_status != link) {
if (link == ETH_LINK_UP) {
if (status & P1SR_OPERATION_SPEED) {
speed = ETH_SPEED_100M;
ESP_LOGD(TAG, "speed 100M");
} else {
speed = ETH_SPEED_10M;
ESP_LOGD(TAG, "speed 10M");
}
if (status & P1SR_OPERATION_DUPLEX) {
duplex = ETH_DUPLEX_FULL;
ESP_LOGD(TAG, "duplex full");
} else {
duplex = ETH_DUPLEX_HALF;
ESP_LOGD(TAG, "duplex half");
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
ksz8851->link_status = link;
}
return ESP_OK;
err:
return ret;
}
static esp_err_t phy_ksz8851_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "mediator can not be null");
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
ksz8851->eth = eth;
return ESP_OK;
err:
return ret;
}
static esp_err_t phy_ksz8851_reset(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
ksz8851->link_status = ETH_LINK_DOWN;
esp_eth_mediator_t *eth = ksz8851->eth;
ESP_LOGD(TAG, "soft reset");
// NOTE(v.chistyakov): PHY_RESET bit is self-clearing
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz8851->addr, KSZ8851_PHYRR, PHYRR_PHY_RESET), err, TAG, "PHYRR write failed");
vTaskDelay(pdMS_TO_TICKS(ksz8851->reset_timeout_ms));
return ESP_OK;
err:
return ret;
}
static esp_err_t phy_ksz8851_reset_hw(esp_eth_phy_t *phy)
{
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
// NOTE(v.chistyakov): set reset_gpio_num to a negative value can skip hardware reset phy chip
if (ksz8851->reset_gpio_num >= 0) {
ESP_LOGD(TAG, "hard reset");
gpio_func_sel(ksz8851->reset_gpio_num, PIN_FUNC_GPIO);
gpio_set_level(ksz8851->reset_gpio_num, 0);
gpio_output_enable(ksz8851->reset_gpio_num);
esp_rom_delay_us(ksz8851->reset_timeout_ms * 1000);
gpio_set_level(ksz8851->reset_gpio_num, 1);
}
return ESP_OK;
}
static esp_err_t phy_ksz8851_pwrctl(esp_eth_phy_t *phy, bool enable)
{
esp_err_t ret = ESP_OK;
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
esp_eth_mediator_t *eth = ksz8851->eth;
if (enable) {
ESP_LOGD(TAG, "normal mode");
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz8851->addr, KSZ8851_PMECR, PMECR_PME_MODE_POWER_SAVING), err, TAG, "PMECR write failed");
} else {
ESP_LOGD(TAG, "power saving mode");
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz8851->addr, KSZ8851_PMECR, PMECR_PME_MODE_NORMAL), err, TAG, "PMECR write failed");
}
return ESP_OK;
err:
return ret;
}
static esp_err_t phy_ksz8851_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
ESP_LOGD(TAG, "initializing PHY");
ESP_GOTO_ON_ERROR(phy_ksz8851_pwrctl(phy, true), err, TAG, "power control failed");
ESP_GOTO_ON_ERROR(phy_ksz8851_reset(phy), err, TAG, "reset failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t phy_ksz8851_deinit(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
ESP_LOGD(TAG, "deinitializing PHY");
ESP_GOTO_ON_ERROR(phy_ksz8851_pwrctl(phy, false), err, TAG, "power control failed");
return ESP_OK;
err:
return ret;
}
/**
* @note This function is responsible for restarting a new auto-negotiation,
* the result of negotiation won't be reflected to upper layers.
* Instead, the negotiation result is fetched by linker timer, see `phy_ksz8851_get_link()`
*/
static esp_err_t phy_ksz8851_autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat)
{
esp_err_t ret = ESP_OK;
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
esp_eth_mediator_t *eth = ksz8851->eth;
uint32_t control;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz8851->addr, KSZ8851_P1CR, &control), err, TAG, "P1CR read failed");
switch (cmd) {
case ESP_ETH_PHY_AUTONEGO_RESTART:
ESP_GOTO_ON_FALSE(control & P1CR_AUTO_NEGOTIATION_ENABLE, ESP_ERR_INVALID_STATE, err, TAG, "auto negotiation is disabled");
ESP_LOGD(TAG, "restart negotiation");
/* in case any link status has changed, let's assume we're in link down status */
ksz8851->link_status = ETH_LINK_DOWN;
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz8851->addr, KSZ8851_P1CR, control | P1CR_RESTART_AN), err, TAG, "P1CR write failed");
uint32_t status;
unsigned to;
for (to = 0; to < ksz8851->autonego_timeout_ms / 100; to++) {
vTaskDelay(pdMS_TO_TICKS(100));
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz8851->addr, KSZ8851_P1SR, &status), err, TAG, "P1SR read failed");
if (status & P1SR_AN_DONE) {
break;
}
}
if ((to >= ksz8851->autonego_timeout_ms / 100) && (ksz8851->link_status == ETH_LINK_UP)) {
ESP_LOGW(TAG, "auto negotiation timeout");
}
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz8851->addr, KSZ8851_P1CR, control), err, TAG, "P1CR write failed");
ESP_LOGD(TAG, "negotiation succeeded");
break;
case ESP_ETH_PHY_AUTONEGO_DIS:
if (control & P1CR_AUTO_NEGOTIATION_ENABLE) {
control &= ~P1CR_AUTO_NEGOTIATION_ENABLE; /* Disable Auto Negotiation */
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz8851->addr, KSZ8851_P1CR, control), err, TAG, "P1CR write failed");
/* read configuration back */
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz8851->addr, KSZ8851_P1CR, &control), err, TAG, "P1CR read failed");
ESP_GOTO_ON_FALSE((control & P1CR_AUTO_NEGOTIATION_ENABLE) == 0, ESP_FAIL, err, TAG, "disable auto-negotiation failed");
}
break;
case ESP_ETH_PHY_AUTONEGO_EN:
if (!(control & P1CR_AUTO_NEGOTIATION_ENABLE)) {
control |= P1CR_AUTO_NEGOTIATION_ENABLE; /* Enable Auto Negotiation */
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz8851->addr, KSZ8851_P1CR, control), err, TAG, "P1CR write failed");
/* read configuration back */
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz8851->addr, KSZ8851_P1CR, &control), err, TAG, "P1CR read failed");
ESP_GOTO_ON_FALSE(control & P1CR_AUTO_NEGOTIATION_ENABLE, ESP_FAIL, err, TAG, "disable auto-negotiation failed");
}
break;
case ESP_ETH_PHY_AUTONEGO_G_STAT:
/* do nothing autonego_en_stat is set at the function end */
break;
default:
return ESP_ERR_INVALID_ARG;
}
*autonego_en_stat = (control & P1CR_AUTO_NEGOTIATION_ENABLE) != 0;
return ESP_OK;
err:
return ret;
}
static esp_err_t phy_ksz8851_get_link(esp_eth_phy_t *phy)
{
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
return ksz8851_update_link_duplex_speed(ksz8851);
}
static esp_err_t phy_ksz8851_set_link(esp_eth_phy_t *phy, eth_link_t link)
{
esp_err_t ret = ESP_OK;
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
esp_eth_mediator_t *eth = ksz8851->eth;
if (ksz8851->link_status != link) {
ksz8851->link_status = link;
// link status changed, inmiedately report to upper layers
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)ksz8851->link_status), err, TAG, "change link failed");
}
err:
return ret;
}
static esp_err_t phy_ksz8851_set_addr(esp_eth_phy_t *phy, uint32_t addr)
{
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
ksz8851->addr = addr;
ESP_LOGD(TAG, "setting PHY addr to %" PRIu32, addr);
return ESP_OK;
}
static esp_err_t phy_ksz8851_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "addr can not be null");
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
*addr = ksz8851->addr;
return ESP_OK;
err:
return ret;
}
static esp_err_t phy_ksz8851_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability)
{
esp_err_t ret = ESP_OK;
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
esp_eth_mediator_t *eth = ksz8851->eth;
uint32_t anar;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz8851->addr, KSZ8851_P1ANAR, &anar), err, TAG, "P1ANAR read failed");
if (ability) {
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz8851->addr, KSZ8851_P1ANAR, anar | P1ANAR_PAUSE), err, TAG, "P1ANAR write failed");
ESP_LOGD(TAG, "start advertising pause ability");
} else {
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz8851->addr, KSZ8851_P1ANAR, anar & ~P1ANAR_PAUSE), err, TAG, "P1ANAR write failed");
ESP_LOGD(TAG, "stop advertising pause ability");
}
return ESP_OK;
err:
return ret;
}
static esp_err_t phy_ksz8851_loopback(esp_eth_phy_t *phy, bool enable)
{
esp_err_t ret = ESP_OK;
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
esp_eth_mediator_t *eth = ksz8851->eth;
uint32_t mbcr;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz8851->addr, KSZ8851_P1MBCR, &mbcr), err, TAG, "P1MBCR read failed");
if (enable) {
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz8851->addr, KSZ8851_P1MBCR, mbcr | P1MBCR_LOCAL_LOOPBACK), err, TAG, "P1MBCR write failed");
ESP_LOGD(TAG, "set Local (far-end) loopback");
} else {
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz8851->addr, KSZ8851_P1MBCR, mbcr & ~P1MBCR_LOCAL_LOOPBACK), err, TAG, "P1MBCR write failed");
ESP_LOGD(TAG, "disabled Local (far-end) loopback");
}
return ESP_OK;
err:
return ret;
}
static esp_err_t phy_ksz8851_set_speed(esp_eth_phy_t *phy, eth_speed_t speed)
{
esp_err_t ret = ESP_OK;
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
esp_eth_mediator_t *eth = ksz8851->eth;
/* Since the link is going to be reconfigured, consider it down to be status updated once the driver re-started */
ksz8851->link_status = ETH_LINK_DOWN;
/* Set speed */
uint32_t control;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz8851->addr, KSZ8851_P1CR, &control), err, TAG, "P1CR read failed");
if (speed == ETH_SPEED_100M) {
control |= P1CR_FORCE_SPEED;
} else {
control &= ~P1CR_FORCE_SPEED;
}
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz8851->addr, KSZ8851_P1CR, control), err, TAG, "P1CR write failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t phy_ksz8851_set_duplex(esp_eth_phy_t *phy, eth_duplex_t duplex)
{
esp_err_t ret = ESP_OK;
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
esp_eth_mediator_t *eth = ksz8851->eth;
/* Since the link is going to be reconfigured, consider it down to be status updated once the driver re-started */
ksz8851->link_status = ETH_LINK_DOWN;
/* Set duplex mode */
uint32_t control;
uint32_t mbcr;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz8851->addr, KSZ8851_P1CR, &control), err, TAG, "P1CR read failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz8851->addr, KSZ8851_P1MBCR, &mbcr), err, TAG, "P1MBCR read failed");
if (mbcr & P1MBCR_LOCAL_LOOPBACK) {
ESP_GOTO_ON_FALSE(duplex == ETH_DUPLEX_FULL, ESP_ERR_INVALID_STATE, err, TAG, "Duplex mode must be FULL for loopback operation");
}
if (duplex == ETH_DUPLEX_FULL) {
control |= P1CR_FORCE_DUPLEX;
} else {
control &= ~P1CR_FORCE_DUPLEX;
}
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz8851->addr, KSZ8851_P1CR, control), err, TAG, "P1CR write failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t phy_ksz8851_del(esp_eth_phy_t *phy)
{
ESP_LOGD(TAG, "deleting PHY");
phy_ksz8851snl_t *ksz8851 = __containerof(phy, phy_ksz8851snl_t, parent);
free(ksz8851);
return ESP_OK;
}
esp_eth_phy_t *esp_eth_phy_new_ksz8851snl(const eth_phy_config_t *config)
{
esp_eth_phy_t *ret = NULL;
ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "config can not be null");
phy_ksz8851snl_t *ksz8851 = calloc(1, sizeof(phy_ksz8851snl_t));
ESP_GOTO_ON_FALSE(ksz8851, NULL, err, TAG, "no mem for PHY instance");
ksz8851->addr = config->phy_addr;
ksz8851->reset_timeout_ms = config->reset_timeout_ms;
ksz8851->reset_gpio_num = config->reset_gpio_num;
ksz8851->link_status = ETH_LINK_DOWN;
ksz8851->autonego_timeout_ms = config->autonego_timeout_ms;
ksz8851->parent.set_mediator = phy_ksz8851_set_mediator;
ksz8851->parent.reset = phy_ksz8851_reset;
ksz8851->parent.reset_hw = phy_ksz8851_reset_hw;
ksz8851->parent.init = phy_ksz8851_init;
ksz8851->parent.deinit = phy_ksz8851_deinit;
ksz8851->parent.autonego_ctrl = phy_ksz8851_autonego_ctrl;
ksz8851->parent.get_link = phy_ksz8851_get_link;
ksz8851->parent.set_link = phy_ksz8851_set_link;
ksz8851->parent.pwrctl = phy_ksz8851_pwrctl;
ksz8851->parent.set_addr = phy_ksz8851_set_addr;
ksz8851->parent.get_addr = phy_ksz8851_get_addr;
ksz8851->parent.advertise_pause_ability = phy_ksz8851_advertise_pause_ability;
ksz8851->parent.loopback = phy_ksz8851_loopback;
ksz8851->parent.set_speed = phy_ksz8851_set_speed;
ksz8851->parent.set_duplex = phy_ksz8851_set_duplex;
ksz8851->parent.del = phy_ksz8851_del;
return &(ksz8851->parent);
err:
return ret;
}

View File

@@ -1,351 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021 Vladimir Chistyakov
*
* SPDX-License-Identifier: MIT
*
* SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD
*/
#pragma once
typedef enum {
KSZ8851_CCR = 0x08, ///< Chip Configuration Register
KSZ8851_MARL = 0x10, ///< Host MAC Address Register Low
KSZ8851_MARM = 0x12, ///< Host MAC Address Register Middle
KSZ8851_MARH = 0x14, ///< Host MAC Address Register High
KSZ8851_OBCR = 0x20, ///< On-Chip Bus Control Register
KSZ8851_EEPCR = 0x22, ///< EEPROM Control Register
KSZ8851_MBIR = 0x24, ///< Memory Built-In Self-Test (BIST) Info Register
KSZ8851_GRR = 0x26, ///< Global Reset Register
KSZ8851_WFCR = 0x2A, ///< Wakeup Frame Control Register
KSZ8851_WF0CRC0 = 0x30, ///< Wakeup Frame 0 CRC0 Register (lower 16 bits)
KSZ8851_WF0CRC1 = 0x32, ///< Wakeup Frame 0 CRC1 Register (upper 16 bits)
KSZ8851_WF0BM0 = 0x34, ///< Wakeup Frame 0 Byte Mask 0 Register (0-15)
KSZ8851_WF0BM1 = 0x36, ///< Wakeup Frame 0 Byte Mask 1 Register (16-31)
KSZ8851_WF0BM2 = 0x38, ///< Wakeup Frame 0 Byte Mask 2 Register (32-47)
KSZ8851_WF0BM3 = 0x3A, ///< Wakeup Frame 0 Byte Mask 3 Register (48-63)
KSZ8851_WF1CRC0 = 0x40, ///< Wakeup Frame 1 CRC0 Register (lower 16 bits)
KSZ8851_WF1CRC1 = 0x42, ///< Wakeup Frame 1 CRC1 Register (upper 16 bits)
KSZ8851_WF1BM0 = 0x44, ///< Wakeup Frame 1 Byte Mask 0 Register (0-15)
KSZ8851_WF1BM1 = 0x46, ///< Wakeup Frame 1 Byte Mask 1 Register (16-31)
KSZ8851_WF1BM2 = 0x48, ///< Wakeup Frame 1 Byte Mask 2 Register (32-47)
KSZ8851_WF1BM3 = 0x4A, ///< Wakeup Frame 1 Byte Mask 3 Register (48-63)
KSZ8851_WF2CRC0 = 0x50, ///< Wakeup Frame 2 CRC0 Register (lower 16 bits)
KSZ8851_WF2CRC1 = 0x52, ///< Wakeup Frame 2 CRC1 Register (upper 16 bits)
KSZ8851_WF2BM0 = 0x54, ///< Wakeup Frame 2 Byte Mask 0 Register (0-15)
KSZ8851_WF2BM1 = 0x56, ///< Wakeup Frame 2 Byte Mask 1 Register (16-31)
KSZ8851_WF2BM2 = 0x58, ///< Wakeup Frame 2 Byte Mask 2 Register (32-47)
KSZ8851_WF2BM3 = 0x5A, ///< Wakeup Frame 2 Byte Mask 3 Register (48-63)
KSZ8851_WF3CRC0 = 0x60, ///< Wakeup Frame 3 CRC0 Register (lower 16 bits)
KSZ8851_WF3CRC1 = 0x62, ///< Wakeup Frame 3 CRC1 Register (upper 16 bits)
KSZ8851_WF3BM0 = 0x64, ///< Wakeup Frame 3 Byte Mask 0 Register (0-15)
KSZ8851_WF3BM1 = 0x66, ///< Wakeup Frame 3 Byte Mask 1 Register (16-31)
KSZ8851_WF3BM2 = 0x68, ///< Wakeup Frame 3 Byte Mask 2 Register (32-47)
KSZ8851_WF3BM3 = 0x6A, ///< Wakeup Frame 3 Byte Mask 3 Register (48-63)
KSZ8851_TXCR = 0x70, ///< Transmit Control Register
KSZ8851_TXSR = 0x72, ///< Transmit Status Register
KSZ8851_RXCR1 = 0x74, ///< Receive Control Register 1
KSZ8851_RXCR2 = 0x76, ///< Receive Control Register 2
KSZ8851_TXMIR = 0x78, ///< TXQ Memory Information Register
KSZ8851_RXFHSR = 0x7C, ///< Receive Frame Header Status Register
KSZ8851_RXFHBCR = 0x7E, ///< Receive Frame Header Byte Count Register
KSZ8851_TXQCR = 0x80, ///< TXQ Command Register
KSZ8851_RXQCR = 0x82, ///< RXQ Command Register
KSZ8851_TXFDPR = 0x84, ///< TX Frame Data Pointer Register
KSZ8851_RXFDPR = 0x86, ///< RX Frame Data Pointer Register
KSZ8851_RXDTTR = 0x8C, ///< RX Duration Timer Threshold Register
KSZ8851_RXDBCTR = 0x8E, ///< RX Data Byte Count Threshold Register
KSZ8851_IER = 0x90, ///< Interrupt Enable Register
KSZ8851_ISR = 0x92, ///< Interrupt Status Register
KSZ8851_RXFCTR = 0x9C, ///< RX Frame Count & Threshold Register
KSZ8851_TXNTFSR = 0x9E, ///< TX Next Total Frames Size Register
KSZ8851_MAHTR0 = 0xA0, ///< MAC Address Hash Table Register 0
KSZ8851_MAHTR1 = 0xA2, ///< MAC Address Hash Table Register 1
KSZ8851_MAHTR2 = 0xA4, ///< MAC Address Hash Table Register 2
KSZ8851_MAHTR3 = 0xA6, ///< MAC Address Hash Table Register 3
KSZ8851_FCLWR = 0xB0, ///< Flow Control Low Watermark Register
KSZ8851_FCHWR = 0xB2, ///< Flow Control High Watermark Register
KSZ8851_FCOWR = 0xB4, ///< Flow Control Overrun Watermark Register
KSZ8851_CIDER = 0xC0, ///< Chip ID and Enable Register
KSZ8851_CGCR = 0xC6, ///< Chip Global Control Register
KSZ8851_IACR = 0xC8, ///< Indirect Access Control Register
KSZ8851_IADLR = 0xD0, ///< Indirect Access Data Low Register
KSZ8851_IADHR = 0xD2, ///< Indirect Access Data High Register
KSZ8851_PMECR = 0xD4, ///< Power Management Event Control Register
KSZ8851_GSWUTR = 0xD6, ///< Go-Sleep & Wake-Up Time Register
KSZ8851_PHYRR = 0xD8, ///< PHY Reset Register
KSZ8851_P1MBCR = 0xE4, ///< PHY 1 MII-Register Basic Control Register
KSZ8851_P1MBSR = 0xE6, ///< PHY 1 MII-Register Basic Status Register
KSZ8851_PHY1ILR = 0xE8, ///< PHY 1 PHY ID Low Register
KSZ8851_PHY1IHR = 0xEA, ///< PHY 1 PHY ID High Register
KSZ8851_P1ANAR = 0xEC, ///< PHY 1 Auto-Negotiation Advertisement Register
KSZ8851_P1ANLPR = 0xEE, ///< PHY 1 Auto-Negotiation Link Partner Ability Register
KSZ8851_P1SCLMD = 0xF4, ///< Port 1 PHY Special Control/Status, LinkMD
KSZ8851_P1CR = 0xF6, ///< Port 1 Control Register
KSZ8851_P1SR = 0xF8, ///< Port 1 Status Register
KSZ8851_VALID_ADDRESS_MASK = 0xFE, ///< All register addresses are under this mask
} ksz8851_registers_t;
typedef enum {
CCR_EEPROM_PRESENCE = 0x0200U, ///< RO EEPROM presence
CCR_SPI_BUS_MODE = 0x0100U, ///< RO SPI bus mode
CCR_32PIN_CHIP_PACKAGE = 0x0001U, ///< RO 32-Pin Chip Package
OBCR_OUTPUT_PIN_DRIVE_STRENGTH = 0x0040U, ///< RW Output Pin Drive Strength: 8mA (0) or 16mA (1)
OBCR_ONCHIP_BUS_CLOCK_SELECTION = 0X0004U, ///< RW On-Chip Bus Clock Selection: 125MHz (0)
OBCR_ONCHIP_BUS_CLOCK_DIVIDE_BY_1 = 0x0000U, ///< RW On-Chip Bus Clock Divider Selection
OBCR_ONCHIP_BUS_CLCOK_DIVIDE_BY_2 = 0x0001U, ///< Rw On-Chip Bus Clock Divider Selection
OBCR_ONCHIP_BUS_CLCOK_DIVIDE_BY_3 = 0x0002U, ///< RW On-Chip Bus Clock Divider Selection
EEPCR_EESRWA = 0x0020U, ///< RW EEPROM Software Read (0) or Write (1) Access
EEPCR_EESA = 0x0010U, ///< RW EEPROM Software Access
EEPCR_EESB = 0x0008U, ///< RO EEPROM Data receive
EEPCR_EECB2 = 0x0004U, ///< RW EEPROM Data transmit
EEPCR_EECB1 = 0x0002U, ///< RW EEPROM Serial clock
EEPCR_EECB0 = 0x0001U, ///< RW EEPROM Chip select
MBIR_TXMBF = 0x1000U, ///< RO TX Memory BIST Test Finish
MBIR_TXMBFA = 0x0800U, ///< RO TX Memory BIST Test Fail
MBIR_TXMBFC_SHIFT = 8U, ///< RO TX Memory BIST Test Fail Count Shift
MBIR_TXMBFC_MASK = 0x7 << MBIR_TXMBFC_SHIFT, ///< RO TX Memory BIST Test Fail Count Mask
MBIR_RXMBF = 0x0010U, ///< RO RX Memory Bist Finish
MBIR_RXMBFA = 0x0008U, ///< RO RX Memory Bist Fail
MBIR_RXMBFC = 0x7U, ///< RO RX Memory BIST Test Fail Count
GRR_QMU_MODULE_SOFT_RESET = 0x0002U, ///< RW QMU Module Soft Reset
GRR_GLOBAL_SOFT_RESET = 0x0001U, ///< Rw Global Soft Reset
WFCR_MPRXE = 0x0080U, ///< RW Magic Packet RX Enable
WFCR_WF3E = 0x0008U, ///< RW Wake up Frame 3 Enable
WFCR_WF2E = 0x0004U, ///< RW Wake up Frame 2 Enable
WFCR_WF1E = 0x0002U, ///< RW Wake up Frame 1 Enable
WFCR_WF0E = 0x0001U, ///< RW Wake up Frame 0 Enable
TXCR_TCGICMP = 0x0100U, ///< RW Transmit Checksum Generation for ICMP
TXCR_TCGTCP = 0x0040U, ///< RW Transmit Checksum Generation for TCP
TXCR_TCGIP = 0x0020U, ///< RW Transmit Checksum Generation for IP
TXCR_FTXQ = 0x0010U, ///< RW Flush Transmit Queue
TXCR_TXFCE = 0x0008U, ///< RW Transmit Flow Control Enable
TXCR_TXPE = 0x0004U, ///< RW Transmit Padding Enable
TXCR_TXCE = 0x0002U, ///< RW Transmit CRC Enable
TXCR_TXE = 0x0001U, ///< RW Transmit Enable
TXSR_TXLC = 0x2000U, ///< RO Transmit Late Collision
TXSR_TXMC = 0x1000U, ///< RO Transmit Maximum Collision
TXSR_TXFID_MASK = 0x003FU, ///< RO Transmit Frame ID Mask
RXCR1_FRXQ = 0x8000U, ///< RW Flush Receive Queue
RXCR1_RXUDPFCC = 0x4000U, ///< RW Receive UDP Frame Checksum Check Enable
RXCR1_RXTCPFCC = 0x2000U, ///< RW Receive TCP Frame Checksum Check Enable
RXCR1_RXIPFCC = 0x1000U, ///< RW Receive IP Frame Checksum Check Enable
RXCR1_RXPAFMA = 0x0800U, ///< RW Receive Physical Address Filtering with MAC Address Enable
RXCR1_RXFCE = 0x0400U, ///< RW Receive Flow Control Enable
RXCR1_RXEFE = 0x0200U, ///< RW Receive Error Frame Enable
RXCR1_RXMAFMA = 0x0100U, ///< RW Receive Multicast Address Filtering with MAC Address Enable
RXCR1_RXBE = 0x0080U, ///< RW Receive Broadcast Enable
RXCR1_RXME = 0x0040U, ///< RW Receive Multicast Enable
RXCR1_RXUE = 0x0020U, ///< RW Receive Unicast Enable
RXCR1_RXAE = 0x0010U, ///< RW Receive All Enable
RXCR1_RXINVF = 0x0002U, ///< RW Receive Inverse Filtering
RXCR1_RXE = 0x0001U, ///< RW Receive Enable
RXCR2_SRDBL_SHIFT = 5U, ///< WO SPI Receive Data Burst Length: 4/8/16/32/frame (0-4)
RXCR2_IUFFP = 0x0010U, ///< RW IPv4/IPv6/UDP Fragment Frame Pass
RXCR2_RXIUFCEZ = 0x0008U, ///< RW Receive IPv4/IPv6/UDP Frame Checksum Equal Zero
RXCR2_UDPLFE = 0x0004U, ///< RW Lite Frame Enable
RXCR2_RXICMPFCC = 0x0002U, ///< RW Receive ICMP Frame Checksum Check Enable
RXCR2_RXSAF = 0x0001U, ///< RW Receive Source Address Filtering
TXMIR_TXMA_MASK = 0x1FFFU, ///< RO Transmit Memory Available Mask
RXFHSR_RXFV = 0x8000U, ///< RO Receive Frame Valid
RXFHSR_RXICMPFCS = 0x2000U, ///< RO Receive ICMP Frame Checksum Status
RXFHSR_RXIPFCS = 0x1000U, ///< RO Receive IP Frame Checksum Status
RXFHSR_RXTCPFCS = 0x0800U, ///< RO Receive TCP Frame Checksum Status
RXFHSR_RXUDPFCS = 0x0400U, ///< RO Receive UDP Frame Checksum Status
RXFHSR_RXBF = 0x0080U, ///< RO Receive Broadcast Frame
RXFHSR_RXMF = 0x0040U, ///< RO Receive Multicast Frame
RXFHSR_RXUF = 0x0020U, ///< RO Receive Unicast Frame
RXFHSR_RXMR = 0x0010U, ///< RO Receive MII Error
RXFHSR_RXFT = 0x0008U, ///< RO Receive Frame Type
RXFHSR_RXFTL = 0x0004U, ///< RO Receive Frame Too Long
RXFHSR_RXRF = 0x0002U, ///< RO Receive Runt Frame
RXFHSR_RXCE = 0x0001U, ///< RO Receive CRC Error
RXFHBCR_RXBC_MASK = 0x0FFFU, ///< RO Receive Byte Count Mask
TXQCR_AETFE = 0x0004U, ///< RW Auto-Enqueue TXQ Frame Enable
TXQCR_TXQMAM = 0x0002U, ///< RW TXQ Memory Available Monitor
TXQCR_METFE = 0x0001U, ///< RW (SC) Manual Enqueue TXQ Frame Enable
RXQCR_RXDTTS = 0x1000U, ///< RO RX Duration Timer Threshold Status
RXQCR_RXDBCTS = 0x0800U, ///< RO RX Data Byte Count Threshold Status
RXQCR_RXFCTS = 0x0400U, ///< RO RX Frame Count Threshold Status
RXQCR_RXIPHTOE = 0x0200U, ///< RW RX IP Header Two-Byte Offset Enable
RXQCR_RXDTTE = 0x0080U, ///< RW RX Duration Timer Threshold Enable
RXQCR_RXDBCTE = 0x0040U, ///< RW RX Data Byte Count Threshold Enable
RXQCR_RXFCTE = 0x0020U, ///< RW RX Frame Count Threshold Enable
RXQCR_ADRFE = 0x0010U, ///< RW Auto-Dequeue RXQ Frame Enable
RXQCR_SDA = 0x0008U, ///< WO Start DMA Access
RXQCR_RRXEF = 0x0001U, ///< RW Release RX Error Frame
TXFDPR_TXFPAI = 0x4000U, ///< RW TX Frame Data Pointer Auto Increment
TXFDPR_TXFP_MASK = 0x07FFU, ///< RO TX Frame Pointer Mask
RXFDPR_RXFPAI = 0x4000U, ///< RW RX Frame Pointer Auto Increment
RXFDPR_RXFP_MASK = 0x07FFU, ///< WO RX Frame Pointer Mask
IER_LCIE = 0x8000U, ///< RW Link Change Interrupt Enable
IER_TXIE = 0x4000U, ///< RW Transmit Interrupt Enable
IER_RXIE = 0x2000U, ///< RW Receive Interrupt Enable
IER_RXOIE = 0x0800U, ///< RW Receive Overrun Interrupt Enable
IER_TXPSIE = 0x0200U, ///< RW Transmit Process Stopped Interrupt Enable
IER_RXPSIE = 0x0100U, ///< RW Receive Process Stopped Interrupt Enable
IER_TXSAIE = 0x0040U, ///< RW Transmit Space Available Interrupt Enable
IER_RXWFDIE = 0x0020U, ///< RW Receive Wake-up Frame Detect Interrupt Enable
IER_RXMPDIE = 0x0010U, ///< RW Receive Magic Packet Detect Interrupt Enable
IER_LDIE = 0x0008U, ///< RW Linkup Detect Interrupt Enable
IER_EDIE = 0x0004U, ///< RW Energy Detect Interrupt Enable
IER_SPIBEIE = 0x0002U, ///< RW SPI Bus Error Interrupt Enable
IER_DEDIE = 0x0001U, ///< RW Delay Energy Detect Interrupt Enable
ISR_LCIS = 0x8000U, ///< RO (W1C) Link Change Interrupt Status
ISR_TXIS = 0x4000U, ///< RO (W1C) Transmit Interrupt Status
ISR_RXIS = 0x2000U, ///< RO (W1C) Receive Interrupt Status
ISR_RXOIS = 0x0800U, ///< RO (W1C) Receive Overrun Interrupt Status
ISR_TXPSIS = 0x0200U, ///< RO (W1C) Transmit Process Stopped Interrupt Status
ISR_RXPSIS = 0x0100U, ///< RO (W1C) Receive Process Stopped Interrupt Status
ISR_TXSAIS = 0x0040U, ///< RO (W1C) Transmit Space Available Interrupt Status
ISR_RXWFDIS = 0x0020U, ///< RO (W1C) Receive Wakeup Frame Detect Interrupt Status
ISR_RXMPDIS = 0x0010U, ///< RO (W1C) Receive Magic Packet Detect Interrupt Status
ISR_LDIS = 0x0008U, ///< RO (W1C) Linkup Detect Interrupt Status
ISR_EDIS = 0x0004U, ///< RO (W1C) Energy Detect Interrupt Status
ISR_SPIBEIS = 0x0002U, ///< RO (W1C) SPI Bus Error Interrupt Status
ISR_ALL = 0xFFFFU, ///< WO Clear register value
RXFCTR_RXFC_SHIFT = 8U, ///< RO RX Frame Count Shift
RXFCTR_RXFC_MASK = 0xFF << RXFCTR_RXFC_SHIFT, ///< RO RX Frame Count Mask
RXFCTR_RXFCT_MASK = 0xFFU, ///< RW Receive Frame Count Threshold
FCLWR_MASK = 0x0FFFU, ///< RW Flow Control Low Watermark Configuration Mask
FCHWR_MASK = 0x0FFFU, ///< RW Flow Control High Watermark Configuration Mask
FCOWR_MASK = 0x0FFFU, ///< RW Flow Control Overrun Watermark Configuration Mask
CIDER_KSZ8851SNL_FAMILY_ID = 0x88U, ///< KSZ8851SNL Family ID
CIDER_KSZ8851SNL_CHIP_ID = 0x7U, ///< KSZ8851SNL Chip ID
CIDER_FAMILY_ID_SHIFT = 8U, ///< RO Family ID Shift
CIDER_FAMILY_ID_MASK = 0xFF << CIDER_FAMILY_ID_SHIFT, ///< RO Family ID Mask
CIDER_CHIP_ID_SHIFT = 4U, ///< RO Chip ID Shift
CIDER_CHIP_ID_MASK = 0xF << CIDER_CHIP_ID_SHIFT, ///< RO Chip ID Mask
CIDER_REVISION_ID_SHIFT = 1U, ///< RO Revision ID Shift
CIDER_REVISION_ID_MASK = 0x7 << CIDER_REVISION_ID_SHIFT, ///< RO Revision ID Mask
CGCR_LEDSEL0 = 0x0200U, ///< RW PHY LED Mode: 0 - 100BT + LINK/ACTU, 1 - ACT + LINK
IACR_READ_ENABLE = 0x1000U, ///< RW Read Enable
IACR_MIB_COUNTER_SELECT = 0x0C00U, ///< RW Table Select
IACR_INDIRECT_ADDRESS_MASK = 0x001FU, ///< RW Indirect Address Mask
PMECR_PME_DELAY_ENABLE = 0x4000U, ///< RW PME Delay Enable
PMECR_PME_OUTPUT_POLARITY = 0x1000U, ///< RW PME Output Polarity
PMECR_WUP_FRAME_EN = 0x0800U, ///< RW Wake-on-LAN to PME Output Enable receive wake-up frame
PMECR_MAGIC_PACKET = 0x0400U, ///< RW Wake-on-LAN to PME Output Enable receive magic packet
PMECR_LINK_CHANGE_TO_UP = 0x0200U, ///< RW Wake-on-LAN to PME Output Enable link change to up
PMECR_SIGNAL_ENERGY_DETECTED = 0x0100U, ///< RW Wake-on-LAN to PME Output Enable energy detected
PMECR_AUTO_WAKEUP_ENABLE = 0x0080U, ///< RW Auto Wake-Up Enable
PMECR_WAKEUP_TO_NORMAL = 0x0040U, ///< RW Wake-Up to Normal Operation Mode
PMECR_WAKEUP_FRAME_EVENT = 0x0020U, ///< RO (W1C) Wake-Up Event Indication wakeup frame event detected
PMECR_WAKEUP_MAGIC_PACKET = 0x0010U, ///< RO (W1C) Wake-Up Event Indication magic packet event detected
PMECR_WAKEUP_LINK = 0x0008U, ///< RO (W1C) Wake-Up Event Indication link up event detected
PMECR_WAKEUP_ENERGY = 0x0004U, ///< RO (W1C) Wake-Up Event Indication energy event detected
PMECR_PME_MODE_MASK = 0x0003U, ///< RW Power Management Mode Mask
PMECR_PME_MODE_NORMAL = 0x0000U, ///< RW Normal Operation Mode
PMECR_PME_MODE_ENERGY_DETECT = 0x0001U, ///< RW Energy Detect Mode
PMECR_PME_MODE_SOFT_POWER_DOWN = 0x0002U, ///< RW Soft Power Down Mode
PMECR_PME_MODE_POWER_SAVING = 0x0003U, ///< RW Power Saving Mode
GSWUTR_WAKE_UP_TIME_SHIFT = 8U, ///< RW Wake-up Time Shift
GSWUTR_WAKE_UP_TIME_MASK = 0xFF << GSWUTR_WAKE_UP_TIME_SHIFT, ///< RW Wake-up Time Mask
GSWUTR_GO_SLEEP_TIME_MASK = 0x0003U, ///< RW Go-sleep Time Mask
PHYRR_PHY_RESET = 0x0001U, ///< WO (SC) PHY Reset Bit
P1MBCR_LOCAL_LOOPBACK = 0x4000U, ///< RW Local (far-end) loopback (llb)
P1MBCR_FORCE100 = 0x2000U, ///< RW Force 100
P1MBCR_AN_ENABLE = 0x1000U, ///< RW AN Enable
P1MBCR_RESTART_AN = 0x0200U, ///< RW Restart AN
P1MBCR_FORCE_FULL_DUPLEX = 0x0100U, ///< RW Force Full-Duplex
P1MBCR_HP_MDIX = 0x0020U, ///< RW HP Auto MDI-X mode
P1MBCR_FORCE_MDIX = 0x0010U, ///< RWForce MDI-X
P1MBCR_DISABLE_MDIX = 0x0008U, ///< RW Disable MDI-X
P1MBCR_DISABLE_TRANSMIT = 0x0002U, ///< RW Disable Transmit
P1MBCR_DISABLE_LED = 0x0001U, ///< RW Disable LED
P1MBSR_T4_CAPABLE = 0x8000U, ///< RO T4 Capable
P1MBSR_100_FULL_CAPABLE = 0x4000U, ///< RO 100 Full Capable
P1MBSR_100_HALF_CAPABLE = 0x2000U, ///< RO 100 Half Capable
P1MBSR_10_FULL_CAPABLE = 0x1000U, ///< RO 10 Full Capable
P1MBSR_10_HALF_CAPABLE = 0x0800U, ///< RO 10 Half Capable
P1MBSR_PREAMBLE_SUPPRESSED = 0x0040U, ///< RO Preamble suppressed (not supported)
P1MBSR_AN_COMPLETE = 0x0020U, ///< RO AN Complete
P1MBSR_AN_CAPABLE = 0x0008U, ///< RO AN Capable
P1MBSR_LINK_STATUS = 0x0004U, ///< RO Link Status
P1MBSR_JABBER_TEST = 0x0002U, ///< RO Jabber test (not supported)
P1MBSR_EXTENDED_CAPABLE = 0x0001U, ///< RO Extended Capable
P1ANAR_NEXT_PAGE = 0x8000U, ///< RO Next page (not supported)
P1ANAR_REMOTE_FAULT = 0x2000U, ///< RO Remote fault (not supported)
P1ANAR_PAUSE = 0x0400U, ///< RW Pause (flow control capability)
P1ANAR_ADV_100_FULL = 0x0100U, ///< RW Adv 100 Full
P1ANAR_ADV_100_HALF = 0x0080U, ///< RW Adv 100 Half
P1ANAR_ADV_10_FULL = 0x0040U, ///< RW Adv 10 Full
P1ANAR_ADV_10_HALF = 0x0020U, ///< RW Adv 10 Half
P1ANLPR_NEXT_PAGE = 0x8000U, ///< RO Next page (not supported)
P1ANLPR_LP_ACK = 0x4000U, ///< RO LP ACK (not supported)
P1ANLPR_REMOTE_FAULT = 0x2000U, ///< RO Remote fault (not supported)
P1ANLPR_PAUSE = 0x0400U, ///< RO Pause
P1ANLPR_ADV_100_FULL = 0x0100U, ///< RO Adv 100 Full
P1ANLPR_ADV_100_HALF = 0x0080U, ///< RO Adv 100 Half
P1ANLPR_ADV_10_FULL = 0x0040U, ///< RO Adv 10 Full
P1ANLPR_ADV_10_HALF = 0x0020U, ///< RO Adv 10 Half
P1SCLMD_VCT_RESULT_SHIFT = 13U, ///< RO VCT result Shift
P1SCLMD_VCT_RESULT_MASK = 0x3 << P1SCLMD_VCT_RESULT_SHIFT, ///< RO VCT result Mask
P1SCLMD_VCT_RESULT_NORMAL = 0x0U, ///< RO VCT result normal condition
P1SCLMD_VCT_RESULT_OPEN = 0x1U, ///< RO VCT result open cable condition
P1SCLMD_VCT_RESULT_SHORT = 0x2U, ///< RO VCT result short cable condition
P1SCLMD_VCT_RESULT_TEST_FAILED = 0x3U, ///< RO VCT result test failed
P1SCLMD_VCT_ENABLE = 0x1000U, ///< RW (SC) VCT Enable
P1SCLMD_FORCE_LINK = 0x0800U, ///< RW Force link
P1SCLMD_REMOTE_LOOPBACK = 0x0200U, ///< RW Remote (Near-end) loopback (rlb)
P1SCLMD_VCT_FAULT_COUNT_MASK = 0x1FU, ///< RO Distance to the fault * 0.4m
P1CR_LED_OFF = 0x8000U, ///< RW Turn off all of the port 1 LEDs
P1CR_TXIDS = 0x4000U, ///< RW Disable the ports transmitter.
P1CR_RESTART_AN = 0x2000U, ///< RW Restart AN
P1CR_DISABLE_AUTO_MDI_MDIX = 0x0400U, ///< RW Disable auto MDI/MDI-X
P1CR_FORCE_MDIX = 0x0200U, ///< RW Force MDI-X
P1CR_AUTO_NEGOTIATION_ENABLE = 0x0080U, ///< RW Auto Negotiation Enable
P1CR_FORCE_SPEED = 0x0040U, ///< RW Force Speed 100
P1CR_FORCE_DUPLEX = 0x0020U, ///< RW Force Full Duplex
P1CR_ADVERTISED_FLOW_CONTROL_CAPABILITY = 0x0010U, ///< RW Advertise flow control capability
P1CR_ADVERTISED_100BT_FULL_DUPLEX_CAPABILITY = 0x0008U, ///< RW Advertise 100BT full-duplex capability
P1CR_ADVERTISED_100BT_HALF_DUPLEX_CAPABILITY = 0x0004U, ///< RW Advertise 100BT half-duplex capability
P1CR_ADVERTISED_10BT_FULL_DUPLEX_CAPABILITY = 0x0002U, ///< RW Advertise 10BT full-duplex capability
P1CR_ADVERTISED_10BT_HALF_DUPLEX_CAPABILITY = 0x0001U, ///< RW Advertise 10BT half-duplex capability
P1SR_HP_MDIX = 0x8000U, ///< RW HP Auto MDI-X mode
P1SR_POLARITY_REVERSE = 0x2000U, ///< RO Polarity Reverse
P1SR_OPERATION_SPEED = 0x0400U, ///< RO Operation Speed 100
P1SR_OPERATION_DUPLEX = 0x0200U, ///< RO Operation Duplex Full
P1SR_MDIX_STATUS = 0x0080U, ///< RO MDI status
P1SR_AN_DONE = 0x0040U, ///< RO AN Done
P1SR_LINK_GOOD = 0x0020U, ///< RO Link Good
P1SR_PARTNER_FLOW_CONTROL_CAPABILITY = 0x0010U, ///< RO Partner flow control capability
P1SR_PARTNER_100BT_FULL_DUPLEX_CAPABILITY = 0x0008U, ///< RO Partner 100BT full-duplex capability
P1SR_PARTNER_100BT_HALF_DUPLEX_CAPABILITY = 0x0004U, ///< RO Partner 100BT half-duplex capability
P1SR_PARTNER_10BT_FULL_DUPLEX_CAPABILITY = 0x0002U, ///< RO Partner 10BT full-duplex capability
P1SR_PARTNER_10BT_HALF_DUPLEX_CAPABILITY = 0x0001U, ///< RO Partner 10BT half-duplex capability
} ksz8851_register_bits_t;

File diff suppressed because it is too large Load Diff

View File

@@ -1,393 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_eth_phy.h"
#include "esp_log.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_private/gpio.h"
#include "soc/io_mux_reg.h"
#include "esp_rom_sys.h"
#include "w5500.h"
#define W5500_WAIT_FOR_RESET_MS (10) // wait for W5500 internal PLL to be Locked after reset assert
static const char *TAG = "w5500.phy";
/***************Vendor Specific Register***************/
/**
* @brief PHYCFGR(PHY Configuration Register)
*
*/
typedef union {
struct {
uint8_t link: 1; /*!< Link status */
uint8_t speed: 1; /*!< Speed status */
uint8_t duplex: 1; /*!< Duplex status */
uint8_t opmode: 3; /*!< Operation mode */
uint8_t opsel: 1; /*!< Operation select */
uint8_t reset: 1; /*!< Reset, when this bit is '0', PHY will get reset */
};
uint8_t val;
} phycfg_reg_t;
typedef enum {
W5500_OP_MODE_10BT_HALF_AUTO_DIS,
W5500_OP_MODE_10BT_FULL_AUTO_DIS,
W5500_OP_MODE_100BT_HALF_AUTO_DIS,
W5500_OP_MODE_100BT_FULL_AUTO_DIS,
W5500_OP_MODE_100BT_HALF_AUTO_EN,
W5500_OP_MODE_NOT_USED,
W5500_OP_MODE_PWR_DOWN,
W5500_OP_MODE_ALL_CAPABLE,
} phy_w5500_op_mode_e;
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
int addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
int reset_gpio_num;
} phy_w5500_t;
static esp_err_t w5500_update_link_duplex_speed(phy_w5500_t *w5500)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = w5500->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
phycfg_reg_t phycfg;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)), err, TAG, "read PHYCFG failed");
eth_link_t link = phycfg.link ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (w5500->link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
if (phycfg.speed) {
speed = ETH_SPEED_100M;
} else {
speed = ETH_SPEED_10M;
}
if (phycfg.duplex) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
}
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
w5500->link_status = link;
}
return ESP_OK;
err:
return ret;
}
static esp_err_t w5500_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "mediator can't be null");
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
w5500->eth = eth;
return ESP_OK;
err:
return ret;
}
static esp_err_t w5500_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
/* Updata information about link, speed, duplex */
ESP_GOTO_ON_ERROR(w5500_update_link_duplex_speed(w5500), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t w5500_set_link(esp_eth_phy_t *phy, eth_link_t link)
{
esp_err_t ret = ESP_OK;
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
esp_eth_mediator_t *eth = w5500->eth;
if (w5500->link_status != link) {
w5500->link_status = link;
// link status changed, inmiedately report to upper layers
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)w5500->link_status), err, TAG, "change link failed");
}
err:
return ret;
}
static esp_err_t w5500_reset(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
w5500->link_status = ETH_LINK_DOWN;
esp_eth_mediator_t *eth = w5500->eth;
phycfg_reg_t phycfg;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)), err, TAG, "read PHYCFG failed");
phycfg.reset = 0; // set to '0' will reset internal PHY
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val), err, TAG, "write PHYCFG failed");
vTaskDelay(pdMS_TO_TICKS(W5500_WAIT_FOR_RESET_MS));
phycfg.reset = 1; // set to '1' after reset
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val), err, TAG, "write PHYCFG failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t w5500_reset_hw(esp_eth_phy_t *phy)
{
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
// set reset_gpio_num to a negative value can skip hardware reset phy chip
if (w5500->reset_gpio_num >= 0) {
gpio_func_sel(w5500->reset_gpio_num, PIN_FUNC_GPIO);
gpio_set_level(w5500->reset_gpio_num, 0);
gpio_output_enable(w5500->reset_gpio_num);
esp_rom_delay_us(100); // insert min input assert time
gpio_set_level(w5500->reset_gpio_num, 1);
}
return ESP_OK;
}
static esp_err_t w5500_autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat)
{
esp_err_t ret = ESP_OK;
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
esp_eth_mediator_t *eth = w5500->eth;
phycfg_reg_t phycfg;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)), err, TAG, "read PHYCFG failed");
switch (cmd) {
case ESP_ETH_PHY_AUTONEGO_RESTART:
ESP_GOTO_ON_FALSE(phycfg.opmode == W5500_OP_MODE_ALL_CAPABLE || phycfg.opmode == W5500_OP_MODE_100BT_HALF_AUTO_EN,
ESP_ERR_INVALID_STATE, err, TAG, "auto negotiation is disabled");
/* in case any link status has changed, let's assume we're in link down status */
w5500->link_status = ETH_LINK_DOWN;
phycfg.opsel = 1; // Configure PHY Operation Mode based on registry setting
phycfg.reset = 0; // PHY needs to be reset after configuring opsel and opmode
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val), err, TAG, "write PHYCFG failed");
vTaskDelay(pdMS_TO_TICKS(W5500_WAIT_FOR_RESET_MS));
phycfg.reset = 1; // reset flag needs to be put back to 1
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val), err, TAG, "write PHYCFG failed");
*autonego_en_stat = phycfg.opmode == W5500_OP_MODE_ALL_CAPABLE || phycfg.opmode == W5500_OP_MODE_100BT_HALF_AUTO_EN;
break;
case ESP_ETH_PHY_AUTONEGO_DIS:
/* W5500 autonegotiation cannot be separately disabled, only specific speed/duplex mode needs to be configured. Hence set the
last used configuration */
if (phycfg.duplex) { // Full duplex
if (phycfg.speed) { // 100 Mbps speed
phycfg.opmode = W5500_OP_MODE_100BT_FULL_AUTO_DIS;
} else {
phycfg.opmode = W5500_OP_MODE_10BT_FULL_AUTO_DIS;
}
} else {
if (phycfg.speed) { // 100 Mbps speed
phycfg.opmode = W5500_OP_MODE_100BT_HALF_AUTO_DIS;
} else {
phycfg.opmode = W5500_OP_MODE_10BT_HALF_AUTO_DIS;
}
}
phycfg.opsel = 1;
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val), err, TAG, "write PHYCFG failed");
*autonego_en_stat = false;
break;
case ESP_ETH_PHY_AUTONEGO_EN:
phycfg.opsel = 1; // PHY working mode configured by register
phycfg.opmode = W5500_OP_MODE_ALL_CAPABLE; // all capable, auto-negotiation enabled
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val), err, TAG, "write PHYCFG failed");
*autonego_en_stat = true;
break;
case ESP_ETH_PHY_AUTONEGO_G_STAT:
*autonego_en_stat = phycfg.opmode == W5500_OP_MODE_ALL_CAPABLE || phycfg.opmode == W5500_OP_MODE_100BT_HALF_AUTO_EN;
break;
default:
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
err:
return ret;
}
static esp_err_t w5500_pwrctl(esp_eth_phy_t *phy, bool enable)
{
// power control is not supported for W5500 internal PHY
return ESP_OK;
}
static esp_err_t w5500_set_addr(esp_eth_phy_t *phy, uint32_t addr)
{
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
w5500->addr = addr;
return ESP_OK;
}
static esp_err_t w5500_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "addr can't be null");
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
*addr = w5500->addr;
return ESP_OK;
err:
return ret;
}
static esp_err_t w5500_del(esp_eth_phy_t *phy)
{
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
free(w5500);
return ESP_OK;
}
static esp_err_t w5500_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability)
{
// pause ability advertisement is not supported for W5500 internal PHY
return ESP_OK;
}
static esp_err_t w5500_loopback(esp_eth_phy_t *phy, bool enable)
{
// Loopback is not supported for W5500 internal PHY
return ESP_ERR_NOT_SUPPORTED;
}
static esp_err_t w5500_set_speed(esp_eth_phy_t *phy, eth_speed_t speed)
{
esp_err_t ret = ESP_OK;
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
esp_eth_mediator_t *eth = w5500->eth;
/* Since the link is going to be reconfigured, consider it down to be status updated once the driver re-started */
w5500->link_status = ETH_LINK_DOWN;
phycfg_reg_t phycfg;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)), err, TAG, "read PHYCFG failed");
if (phycfg.duplex) { // Full duplex
if (speed == ETH_SPEED_100M) {
phycfg.opmode = W5500_OP_MODE_100BT_FULL_AUTO_DIS;
} else {
phycfg.opmode = W5500_OP_MODE_10BT_FULL_AUTO_DIS;
}
} else {
if (speed == ETH_SPEED_100M) {
phycfg.opmode = W5500_OP_MODE_100BT_HALF_AUTO_DIS;
} else {
phycfg.opmode = W5500_OP_MODE_10BT_HALF_AUTO_DIS;
}
}
phycfg.opsel = 1; // PHY working mode configured by register
phycfg.reset = 0; // PHY needs to be reset after configuring opsel and opmode
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val), err, TAG, "write PHYCFG failed");
vTaskDelay(pdMS_TO_TICKS(W5500_WAIT_FOR_RESET_MS));
phycfg.reset = 1; // reset flag needs to be put back to 1
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val), err, TAG, "write PHYCFG failed");
err:
return ret;
}
static esp_err_t w5500_set_duplex(esp_eth_phy_t *phy, eth_duplex_t duplex)
{
esp_err_t ret = ESP_OK;
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
esp_eth_mediator_t *eth = w5500->eth;
/* Since the link is going to be reconfigured, consider it down to be status updated once the driver re-started */
w5500->link_status = ETH_LINK_DOWN;
phycfg_reg_t phycfg;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)), err, TAG, "read PHYCFG failed");
if (phycfg.speed) { // 100Mbps
if (duplex == ETH_DUPLEX_FULL) {
phycfg.opmode = W5500_OP_MODE_100BT_FULL_AUTO_DIS;
} else {
phycfg.opmode = W5500_OP_MODE_100BT_HALF_AUTO_DIS;
}
} else {
if (duplex == ETH_DUPLEX_FULL) {
phycfg.opmode = W5500_OP_MODE_10BT_FULL_AUTO_DIS;
} else {
phycfg.opmode = W5500_OP_MODE_10BT_HALF_AUTO_DIS;
}
}
phycfg.opsel = 1; // PHY working mode configured by register
phycfg.reset = 0; // PHY needs to be reset after configuring opsel and opmode
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val), err, TAG, "write PHYCFG failed");
vTaskDelay(pdMS_TO_TICKS(W5500_WAIT_FOR_RESET_MS));
phycfg.reset = 1; // reset flag needs to be put back to 1
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val), err, TAG, "write PHYCFG failed");
err:
return ret;
}
static esp_err_t w5500_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
/* Power on Ethernet PHY */
ESP_GOTO_ON_ERROR(w5500_pwrctl(phy, true), err, TAG, "power control failed");
/* Reset Ethernet PHY */
ESP_GOTO_ON_ERROR(w5500_reset(phy), err, TAG, "reset failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t w5500_deinit(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
/* Power off Ethernet PHY */
ESP_GOTO_ON_ERROR(w5500_pwrctl(phy, false), err, TAG, "power control failed");
return ESP_OK;
err:
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_w5500(const eth_phy_config_t *config)
{
esp_eth_phy_t *ret = NULL;
ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "invalid arguments");
phy_w5500_t *w5500 = calloc(1, sizeof(phy_w5500_t));
ESP_GOTO_ON_FALSE(w5500, NULL, err, TAG, "no mem for PHY instance");
w5500->addr = config->phy_addr;
w5500->reset_timeout_ms = config->reset_timeout_ms;
w5500->reset_gpio_num = config->reset_gpio_num;
w5500->link_status = ETH_LINK_DOWN;
w5500->autonego_timeout_ms = config->autonego_timeout_ms;
w5500->parent.reset = w5500_reset;
w5500->parent.reset_hw = w5500_reset_hw;
w5500->parent.init = w5500_init;
w5500->parent.deinit = w5500_deinit;
w5500->parent.set_mediator = w5500_set_mediator;
w5500->parent.autonego_ctrl = w5500_autonego_ctrl;
w5500->parent.get_link = w5500_get_link;
w5500->parent.set_link = w5500_set_link;
w5500->parent.pwrctl = w5500_pwrctl;
w5500->parent.get_addr = w5500_get_addr;
w5500->parent.set_addr = w5500_set_addr;
w5500->parent.advertise_pause_ability = w5500_advertise_pause_ability;
w5500->parent.loopback = w5500_loopback;
w5500->parent.set_speed = w5500_set_speed;
w5500->parent.set_duplex = w5500_set_duplex;
w5500->parent.del = w5500_del;
return &(w5500->parent);
err:
return ret;
}

View File

@@ -1,72 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#define W5500_ADDR_OFFSET (16) // Address length
#define W5500_BSB_OFFSET (3) // Block Select Bits offset
#define W5500_RWB_OFFSET (2) // Read Write Bits offset
#define W5500_CHIP_VERSION (0x4) // Chip version that VERSIONR returns
#define W5500_BSB_COM_REG (0x00) // Common Register
#define W5500_BSB_SOCK_REG(s) ((s)*4+1) // Socket Register
#define W5500_BSB_SOCK_TX_BUF(s) ((s)*4+2) // Socket TX Buffer
#define W5500_BSB_SOCK_RX_BUF(s) ((s)*4+3) // Socket RX Buffer
#define W5500_ACCESS_MODE_READ (0) // Read Mode
#define W5500_ACCESS_MODE_WRITE (1) // Write Mode
#define W5500_SPI_OP_MODE_VDM (0x00) // Variable Data Length Mode (SPI frame is controlled by CS line)
#define W5500_SPI_OP_MODE_FDM_1 (0x01) // Fixed Data Length Mode, 1 Byte Length
#define W5500_SPI_OP_MODE_FDM_2 (0x02) // Fixed Data Length Mode, 2 Bytes Length
#define W5500_SPI_OP_MODE_FDM_4 (0x03) // Fixed Data Length Mode, 4 Bytes Length
#define W5500_MAKE_MAP(offset, bsb) ((offset) << W5500_ADDR_OFFSET | (bsb) << W5500_BSB_OFFSET)
#define W5500_REG_MR W5500_MAKE_MAP(0x0000, W5500_BSB_COM_REG) // Mode
#define W5500_REG_MAC W5500_MAKE_MAP(0x0009, W5500_BSB_COM_REG) // MAC Address
#define W5500_REG_INTLEVEL W5500_MAKE_MAP(0x0013, W5500_BSB_COM_REG) // Interrupt Level Timeout
#define W5500_REG_IR W5500_MAKE_MAP(0x0015, W5500_BSB_COM_REG) // Interrupt
#define W5500_REG_IMR W5500_MAKE_MAP(0x0016, W5500_BSB_COM_REG) // Interrupt Mask
#define W5500_REG_SIR W5500_MAKE_MAP(0x0017, W5500_BSB_COM_REG) // Socket Interrupt
#define W5500_REG_SIMR W5500_MAKE_MAP(0x0018, W5500_BSB_COM_REG) // Socket Interrupt Mask
#define W5500_REG_RTR W5500_MAKE_MAP(0x0019, W5500_BSB_COM_REG) // Retry Time
#define W5500_REG_RCR W5500_MAKE_MAP(0x001B, W5500_BSB_COM_REG) // Retry Count
#define W5500_REG_PHYCFGR W5500_MAKE_MAP(0x002E, W5500_BSB_COM_REG) // PHY Configuration
#define W5500_REG_VERSIONR W5500_MAKE_MAP(0x0039, W5500_BSB_COM_REG) // Chip version
#define W5500_REG_SOCK_MR(s) W5500_MAKE_MAP(0x0000, W5500_BSB_SOCK_REG(s)) // Socket Mode
#define W5500_REG_SOCK_CR(s) W5500_MAKE_MAP(0x0001, W5500_BSB_SOCK_REG(s)) // Socket Command
#define W5500_REG_SOCK_IR(s) W5500_MAKE_MAP(0x0002, W5500_BSB_SOCK_REG(s)) // Socket Interrupt
#define W5500_REG_SOCK_SR(s) W5500_MAKE_MAP(0x0004, W5500_BSB_SOCK_REG(s)) // Socket Status
#define W5500_REG_SOCK_RXBUF_SIZE(s) W5500_MAKE_MAP(0x001E, W5500_BSB_SOCK_REG(s)) // Socket Receive Buffer Size
#define W5500_REG_SOCK_TXBUF_SIZE(s) W5500_MAKE_MAP(0x001F, W5500_BSB_SOCK_REG(s)) // Socket Transmit Buffer Size
#define W5500_REG_SOCK_TX_FSR(s) W5500_MAKE_MAP(0x0020, W5500_BSB_SOCK_REG(s)) // Socket TX Free Size
#define W5500_REG_SOCK_TX_RD(s) W5500_MAKE_MAP(0x0022, W5500_BSB_SOCK_REG(s)) // Socket TX Read Pointer
#define W5500_REG_SOCK_TX_WR(s) W5500_MAKE_MAP(0x0024, W5500_BSB_SOCK_REG(s)) // Socket TX Write Pointer
#define W5500_REG_SOCK_RX_RSR(s) W5500_MAKE_MAP(0x0026, W5500_BSB_SOCK_REG(s)) // Socket RX Received Size
#define W5500_REG_SOCK_RX_RD(s) W5500_MAKE_MAP(0x0028, W5500_BSB_SOCK_REG(s)) // Socket RX Read Pointer
#define W5500_REG_SOCK_RX_WR(s) W5500_MAKE_MAP(0x002A, W5500_BSB_SOCK_REG(s)) // Socket RX Write Pointer
#define W5500_REG_SOCK_IMR(s) W5500_MAKE_MAP(0x002C, W5500_BSB_SOCK_REG(s)) // Socket Interrupt Mask
#define W5500_MEM_SOCK_TX(s,addr) W5500_MAKE_MAP(addr, W5500_BSB_SOCK_TX_BUF(s)) // Socket TX buffer address
#define W5500_MEM_SOCK_RX(s,addr) W5500_MAKE_MAP(addr, W5500_BSB_SOCK_RX_BUF(s)) // Socket RX buffer address
#define W5500_MR_RST (1<<7) // Software reset
#define W5500_MR_PB (1<<4) // Ping block (block the response to a ping request)
#define W5500_SIMR_SOCK0 (1<<0) // Socket 0 interrupt
#define W5500_SMR_MAC_RAW (1<<2) // MAC RAW mode
#define W5500_SMR_MAC_FILTER (1<<7) // MAC filter
#define W5500_SMR_MAC_BLOCK_MCAST (1<<5) // Block multicast
#define W5500_SCR_OPEN (0x01) // Open command
#define W5500_SCR_CLOSE (0x10) // Close command
#define W5500_SCR_SEND (0x20) // Send command
#define W5500_SCR_RECV (0x40) // Recv command
#define W5500_SIR_RECV (1<<2) // Receive done
#define W5500_SIR_SEND (1<<4) // Send done

View File

@@ -24,10 +24,12 @@ menu "esp_eth TEST_APPS Configuration"
if TARGET_USE_INTERNAL_ETHERNET if TARGET_USE_INTERNAL_ETHERNET
choice TARGET_ETH_PHY_DEVICE choice TARGET_ETH_PHY_DEVICE
prompt "Ethernet PHY" prompt "Ethernet PHY"
default TARGET_ETH_PHY_DEVICE_IP101 default TARGET_ETH_PHY_DEVICE_GENERIC
help help
Select one of the devices listed here Select one of the devices listed here
config TARGET_ETH_PHY_DEVICE_GENERIC
bool "Generic IEEE802.3"
config TARGET_ETH_PHY_DEVICE_IP101 config TARGET_ETH_PHY_DEVICE_IP101
bool "IP101" bool "IP101"
config TARGET_ETH_PHY_DEVICE_LAN8720 config TARGET_ETH_PHY_DEVICE_LAN8720

View File

@@ -114,7 +114,10 @@ esp_eth_phy_t *phy_init(eth_phy_config_t *phy_config)
} }
#if CONFIG_TARGET_USE_INTERNAL_ETHERNET #if CONFIG_TARGET_USE_INTERNAL_ETHERNET
phy_config->phy_addr = ESP_ETH_PHY_ADDR_AUTO; phy_config->phy_addr = ESP_ETH_PHY_ADDR_AUTO;
#if CONFIG_TARGET_ETH_PHY_DEVICE_IP101 #if CONFIG_TARGET_ETH_PHY_DEVICE_GENERIC
phy = esp_eth_phy_new_generic(phy_config);
ESP_LOGI(TAG, "DUT PHY: Generic");
#elif CONFIG_TARGET_ETH_PHY_DEVICE_IP101
phy = esp_eth_phy_new_ip101(phy_config); phy = esp_eth_phy_new_ip101(phy_config);
ESP_LOGI(TAG, "DUT PHY: IP101"); ESP_LOGI(TAG, "DUT PHY: IP101");
#elif CONFIG_TARGET_ETH_PHY_DEVICE_LAN8720 #elif CONFIG_TARGET_ETH_PHY_DEVICE_LAN8720

View File

@@ -251,7 +251,7 @@ def ethernet_heap_alloc_test(dut: IdfDut) -> None:
# ----------- IP101 ----------- # ----------- IP101 -----------
@pytest.mark.ethernet @pytest.mark.ethernet
@pytest.mark.parametrize('config', ['default_ip101', 'release_ip101', 'single_core_ip101'], indirect=True) @pytest.mark.parametrize('config', ['default_generic', 'release_generic', 'single_core_generic'], indirect=True)
@pytest.mark.flaky(reruns=3, reruns_delay=5) @pytest.mark.flaky(reruns=3, reruns_delay=5)
@idf_parametrize('target', ['esp32'], indirect=['target']) @idf_parametrize('target', ['esp32'], indirect=['target'])
def test_esp_ethernet(dut: IdfDut) -> None: def test_esp_ethernet(dut: IdfDut) -> None:
@@ -262,7 +262,7 @@ def test_esp_ethernet(dut: IdfDut) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
[ [
'default_ip101', 'default_generic',
], ],
indirect=True, indirect=True,
) )
@@ -277,7 +277,7 @@ def test_esp_emac(dut: IdfDut) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
[ [
'default_ip101', 'default_generic',
], ],
indirect=True, indirect=True,
) )
@@ -291,7 +291,7 @@ def test_esp_eth_ip101(dut: IdfDut) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
[ [
'default_ip101_esp32p4', 'default_generic_esp32p4',
], ],
indirect=True, indirect=True,
) )
@@ -306,7 +306,7 @@ def test_esp32p4_ethernet(dut: IdfDut) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
[ [
'default_ip101_esp32p4', 'default_generic_esp32p4',
], ],
indirect=True, indirect=True,
) )
@@ -331,6 +331,7 @@ def test_esp32p4_emac_clko(dut: IdfDut) -> None:
# ----------- LAN8720 ----------- # ----------- LAN8720 -----------
@pytest.mark.temp_skip_ci(targets=['esp32'], reason='IDF-14124')
@pytest.mark.eth_lan8720 @pytest.mark.eth_lan8720
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
@@ -347,6 +348,7 @@ def test_esp_eth_lan8720(dut: IdfDut) -> None:
# ----------- RTL8201 ----------- # ----------- RTL8201 -----------
@pytest.mark.temp_skip_ci(targets=['esp32'], reason='IDF-14124')
@pytest.mark.eth_rtl8201 @pytest.mark.eth_rtl8201
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
@@ -363,6 +365,7 @@ def test_esp_eth_rtl8201(dut: IdfDut) -> None:
# ----------- KSZ8041 ----------- # ----------- KSZ8041 -----------
@pytest.mark.temp_skip_ci(targets=['esp32'], reason='IDF-14124')
@pytest.mark.eth_ksz8041 @pytest.mark.eth_ksz8041
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
@@ -379,6 +382,7 @@ def test_esp_eth_ksz8041(dut: IdfDut) -> None:
# ----------- DP83848 ----------- # ----------- DP83848 -----------
@pytest.mark.temp_skip_ci(targets=['esp32'], reason='IDF-14124')
@pytest.mark.eth_dp83848 @pytest.mark.eth_dp83848
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
@@ -395,6 +399,7 @@ def test_esp_eth_dp83848(dut: IdfDut) -> None:
# ----------- W5500 ----------- # ----------- W5500 -----------
@pytest.mark.temp_skip_ci(targets=['esp32'], reason='IDF-14124')
@pytest.mark.eth_w5500 @pytest.mark.eth_w5500
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
@@ -414,6 +419,7 @@ def test_esp_eth_w5500(dut: IdfDut) -> None:
# ----------- KSZ8851SNL ----------- # ----------- KSZ8851SNL -----------
@pytest.mark.temp_skip_ci(targets=['esp32'], reason='IDF-14124')
@pytest.mark.eth_ksz8851snl @pytest.mark.eth_ksz8851snl
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',
@@ -433,6 +439,7 @@ def test_esp_eth_ksz8851snl(dut: IdfDut) -> None:
# ----------- DM9051 ----------- # ----------- DM9051 -----------
@pytest.mark.temp_skip_ci(targets=['esp32'], reason='IDF-14124')
@pytest.mark.eth_dm9051 @pytest.mark.eth_dm9051
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config',

View File

@@ -1,8 +0,0 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_SPI_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_DM9051=y

View File

@@ -1,11 +0,0 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_DP83848=y
CONFIG_TARGET_RMII_CLK_OUT=y
CONFIG_TARGET_RMII_CLK_OUT_GPIO=17

View File

@@ -6,4 +6,4 @@ CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT_EN=n CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_KSZ8041=y CONFIG_TARGET_ETH_PHY_DEVICE_GENERIC=y

View File

@@ -6,6 +6,6 @@ CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT_EN=n CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_IP101=y CONFIG_TARGET_ETH_PHY_DEVICE_GENERIC=y
CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG=y CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG=y

View File

@@ -1,9 +0,0 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_IP101=y

View File

@@ -1,8 +0,0 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_SPI_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_KSZ8851SNL=y

View File

@@ -1,11 +0,0 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_LAN8720=y
CONFIG_TARGET_RMII_CLK_OUT=y
CONFIG_TARGET_RMII_CLK_OUT_GPIO=17

View File

@@ -1,13 +0,0 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_RTL8201=y
CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG=n
CONFIG_TARGET_IO_MDC=16
CONFIG_TARGET_IO_MDIO=17

View File

@@ -1,8 +0,0 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_SPI_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_W5500=y

View File

@@ -4,7 +4,7 @@ CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG=y CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG=y
CONFIG_TARGET_ETH_PHY_DEVICE_IP101=y CONFIG_TARGET_ETH_PHY_DEVICE_GENERIC=y
CONFIG_ESP_SLEEP_DEBUG=y CONFIG_ESP_SLEEP_DEBUG=y

View File

@@ -1,10 +0,0 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_SPI_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_DM9051=y
CONFIG_TARGET_ETH_SPI_POLL_MS=10

View File

@@ -1,10 +0,0 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_SPI_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_KSZ8851SNL=y
CONFIG_TARGET_ETH_SPI_POLL_MS=10

View File

@@ -1,10 +0,0 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_SPI_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_W5500=y
CONFIG_TARGET_ETH_SPI_POLL_MS=10

View File

@@ -9,4 +9,4 @@ CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT_EN=n CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_IP101=y CONFIG_TARGET_ETH_PHY_DEVICE_GENERIC=y

View File

@@ -6,7 +6,7 @@ CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT_EN=n CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_IP101=y CONFIG_TARGET_ETH_PHY_DEVICE_GENERIC=y
CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG=y CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG=y

View File

@@ -9,4 +9,4 @@ CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT_EN=n CONFIG_ESP_TASK_WDT_EN=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_IP101=y CONFIG_TARGET_ETH_PHY_DEVICE_GENERIC=y

View File

@@ -195,7 +195,7 @@ static void ethernet_init(test_vfs_eth_network_t *network_hndls)
#ifdef CONFIG_IDF_TARGET_ESP32P4 #ifdef CONFIG_IDF_TARGET_ESP32P4
phy_config.reset_gpio_num = 51; phy_config.reset_gpio_num = 51;
#endif // CONFIG_IDF_TARGET_ESP32P4 #endif // CONFIG_IDF_TARGET_ESP32P4
network_hndls->phy = esp_eth_phy_new_ip101(&phy_config); network_hndls->phy = esp_eth_phy_new_generic(&phy_config);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(network_hndls->mac, network_hndls->phy); esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(network_hndls->mac, network_hndls->phy);
network_hndls->eth_handle = NULL; network_hndls->eth_handle = NULL;
// install Ethernet driver // install Ethernet driver

View File

@@ -104,7 +104,7 @@ void connect_test_fixture_setup(void)
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
s_mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); s_mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
s_phy = esp_eth_phy_new_ip101(&phy_config); s_phy = esp_eth_phy_new_generic(&phy_config);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(s_mac, s_phy); esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(s_mac, s_phy);
// install Ethernet driver // install Ethernet driver

View File

@@ -305,15 +305,13 @@ The Ethernet driver is implemented in an Object-Oriented style. Any operation on
phy_config.phy_addr = CONFIG_ETHERNET_PHY_ADDR; // alter the PHY address according to your board design phy_config.phy_addr = CONFIG_ETHERNET_PHY_ADDR; // alter the PHY address according to your board design
phy_config.reset_gpio_num = CONFIG_ETHERNET_PHY_RST_GPIO; // alter the GPIO used for PHY reset phy_config.reset_gpio_num = CONFIG_ETHERNET_PHY_RST_GPIO; // alter the GPIO used for PHY reset
esp_eth_phy_t *phy = esp_eth_phy_new_generic(&phy_config); // create generic PHY instance esp_eth_phy_t *phy = esp_eth_phy_new_generic(&phy_config); // create generic PHY instance
// ESP-IDF officially supports several different specific Ethernet PHY chip driver
// esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
// esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config);
// esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&phy_config);
// esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
.. note:: .. note::
Any Ethernet PHY chip compliant with IEEE 802.3 can be used when creating new PHY instance with :cpp:func:`esp_eth_phy_new_generic`. However, while basic functionality should always work, some specific features might be limited, even if the PHY meets IEEE 802.3 standard. A typical example is loopback functionality, where certain PHYs may require setting a specific speed mode to operate correctly. If this is the concern and you need PHY driver specifically tailored to your chip needs, use drivers for PHY chips the ESP-IDF already officially supports or consult with :ref:`Custom PHY Driver <custom-phy-driver>` section to create a new custom driver. Any Ethernet PHY chip compliant with IEEE 802.3 can be used when creating new PHY instance with :cpp:func:`esp_eth_phy_new_generic`. However, while basic functionality should always work, some specific features might be limited, even if the PHY meets IEEE 802.3 standard. A typical example is loopback functionality, where certain PHYs may require setting a specific speed mode to operate correctly. If this is the concern and you need PHY driver specifically tailored to your chip needs, use drivers for PHY chips the ESP-IDF already officially supports or consult with :ref:`Custom PHY Driver <custom-phy-driver>` section to create a new custom driver.
.. tip::
Espressif provides drivers for several specific Ethernet PHY chips in the `esp-eth-drivers <https://github.com/espressif/esp-eth-drivers>`_ repository. Drivers are distributed as components and are available in the `ESP Component Registry <https://components.espressif.com/>`_.
Optional Runtime MAC Clock Configuration Optional Runtime MAC Clock Configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -329,7 +327,7 @@ The Ethernet driver is implemented in an Object-Oriented style. Any operation on
esp32_emac_config.interface = EMAC_DATA_INTERFACE_RMII; // alter EMAC Data Interface esp32_emac_config.interface = EMAC_DATA_INTERFACE_RMII; // alter EMAC Data Interface
esp32_emac_config.clock_config.rmii.clock_mode = EMAC_CLK_OUT; // select EMAC REF_CLK mode esp32_emac_config.clock_config.rmii.clock_mode = EMAC_CLK_OUT; // select EMAC REF_CLK mode
esp32_emac_config.clock_config.rmii.clock_gpio = EMAC_CLK_OUT_GPIO; // select GPIO number used to input/output EMAC REF_CLK esp32_emac_config.clock_config.rmii.clock_gpio = 17; // select GPIO number used to input/output EMAC REF_CLK
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); // create MAC instance esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); // create MAC instance
@@ -375,6 +373,8 @@ SPI-Ethernet Module
* The SPI device configuration (i.e., `spi_device_interface_config_t`) may slightly differ for other Ethernet modules or to meet SPI timing on specific PCB. Please check out your module's specs and the examples in ESP-IDF. * The SPI device configuration (i.e., `spi_device_interface_config_t`) may slightly differ for other Ethernet modules or to meet SPI timing on specific PCB. Please check out your module's specs and the examples in ESP-IDF.
.. tip::
Espressif provides drivers for various SPI-Ethernet modules in the `esp-eth-drivers <https://github.com/espressif/esp-eth-drivers>`_ repository. Drivers are distributed as components and are available in the `ESP Component Registry <https://components.espressif.com/>`_.
Install Driver Install Driver
-------------- --------------
@@ -383,7 +383,7 @@ To install the Ethernet driver, we need to combine the instance of MAC and PHY a
* :cpp:member:`esp_eth_config_t::mac`: instance that created from MAC generator (e.g., :cpp:func:`esp_eth_mac_new_esp32`). * :cpp:member:`esp_eth_config_t::mac`: instance that created from MAC generator (e.g., :cpp:func:`esp_eth_mac_new_esp32`).
* :cpp:member:`esp_eth_config_t::phy`: instance that created from PHY generator (e.g., :cpp:func:`esp_eth_phy_new_ip101`). * :cpp:member:`esp_eth_config_t::phy`: instance that created from PHY generator (e.g., :cpp:func:`esp_eth_phy_new_generic`).
* :cpp:member:`esp_eth_config_t::check_link_period_ms`: Ethernet driver starts an OS timer to check the link status periodically, this field is used to set the interval, in milliseconds. * :cpp:member:`esp_eth_config_t::check_link_period_ms`: Ethernet driver starts an OS timer to check the link status periodically, this field is used to set the interval, in milliseconds.
@@ -644,11 +644,11 @@ The majority of PHY management functionality required by the ESP-IDF Ethernet dr
**Steps to create a custom PHY driver:** **Steps to create a custom PHY driver:**
1. Define vendor-specific registry layout based on the PHY datasheet. See :component_file:`esp_eth/src/phy/esp_eth_phy_ip101.c` as an example. 1. Define vendor-specific registry layout based on the PHY datasheet.
2. Prepare derived PHY management object info structure which: 2. Prepare derived PHY management object info structure which:
* must contain at least parent IEEE 802.3 :cpp:class:`phy_802_3_t` object * must contain at least parent IEEE 802.3 :cpp:class:`phy_802_3_t` object
* optionally contain additional variables needed to support non-IEEE 802.3 or customized functionality. See :component_file:`esp_eth/src/phy/esp_eth_phy_ksz80xx.c` as an example. * optionally contain additional variables needed to support non-IEEE 802.3 or customized functionality.
3. Define chip-specific management call-back functions. 3. Define chip-specific management call-back functions.
4. Initialize parent IEEE 802.3 object and re-assign chip-specific management call-back functions. 4. Initialize parent IEEE 802.3 object and re-assign chip-specific management call-back functions.

View File

@@ -43,6 +43,32 @@ Removed the following RMII clock Kconfig options from `components/esp_eth`. Cloc
**Impact**: Applications using ``ETH_ESP32_EMAC_DEFAULT_CONFIG()`` continue to work. Custom clock configurations must be set explicitly in the EMAC config structure or use the `Ethernet Init component <https://components.espressif.com/components/espressif/ethernet_init>`_. **Impact**: Applications using ``ETH_ESP32_EMAC_DEFAULT_CONFIG()`` continue to work. Custom clock configurations must be set explicitly in the EMAC config structure or use the `Ethernet Init component <https://components.espressif.com/components/espressif/ethernet_init>`_.
Ethernet PHY and Ethernet SPI Module drivers are moved from ESP-IDF to external repo
------------------------------------------------------------------------------------
The Ethernet PHY and Ethernet SPI Module drivers have been removed from ESP-IDF and have been migrated to `esp-eth-drivers <https://github.com/espressif/esp-eth-drivers>`_ repository. If you are using these drivers, you need to use the drivers as component in your project. The drivers are now available in the `ESP Component Registry <https://components.espressif.com/>`_.
**Removed APIs**:
- :cpp:func:`esp_eth_phy_new_ip101`
- :cpp:func:`esp_eth_phy_new_lan87xx`
- :cpp:func:`esp_eth_phy_new_rtl8201`
- :cpp:func:`esp_eth_phy_new_dp83848`
- :cpp:func:`esp_eth_phy_new_ksz80xx`
- :cpp:func:`esp_eth_mac_new_dm9051`
- :cpp:func:`esp_eth_phy_new_dm9051`
- :cpp:func:`esp_eth_mac_new_ksz8851snl`
- :cpp:func:`esp_eth_phy_new_ksz8851snl`
- :cpp:func:`esp_eth_mac_new_w5500`
- :cpp:func:`esp_eth_phy_new_w5500`
**Impact**: Applications using Ethernet PHY and Ethernet SPI Module drivers that used to be part of ESP-IDF will no longer work.
**Migration**:
Add driver component from `IDF Component Manager <https://components.espressif.com/>`_ to your project using `idf.py add-dependency` and include `esp_eth_phy_xxxx.h` and `esp_eth_mac_xxxx.h` or use the `Ethernet Init component <https://components.espressif.com/components/espressif/ethernet_init>`_.
ESP-NETIF ESP-NETIF
********* *********

View File

@@ -305,15 +305,13 @@ ESP-IDF 在宏 :c:macro:`ETH_MAC_DEFAULT_CONFIG` 和 :c:macro:`ETH_PHY_DEFAULT_C
phy_config.phy_addr = CONFIG_ETHERNET_PHY_ADDR; // 根据开发板设计更改 PHY 地址 phy_config.phy_addr = CONFIG_ETHERNET_PHY_ADDR; // 根据开发板设计更改 PHY 地址
phy_config.reset_gpio_num = CONFIG_ETHERNET_PHY_RST_GPIO; // 更改用于 PHY 复位的 GPIO phy_config.reset_gpio_num = CONFIG_ETHERNET_PHY_RST_GPIO; // 更改用于 PHY 复位的 GPIO
esp_eth_phy_t *phy = esp_eth_phy_new_generic(&phy_config); // 创建通用 PHY 实例 esp_eth_phy_t *phy = esp_eth_phy_new_generic(&phy_config); // 创建通用 PHY 实例
// ESP-IDF 为数种特定以太网 PHY 芯片驱动提供官方支持
// esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
// esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config);
// esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&phy_config);
// esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
.. note:: .. note::
使用 :cpp:func:`esp_eth_phy_new_generic` 创建新的 PHY 实例时,可以使用任何符合 IEEE 802.3 标准的以太网 PHY 芯片。然而,尽管 PHY 芯片符合 IEEE 802.3 标准,能提供基本功能,但某些特定的功能可能无法完全实现。例如,某些以太网 PHY 芯片可能需要配置特定的速度模式才能启用环回功能。遇到这种情况,需要配置 PHY 驱动程序以满足特定芯片需求,请使用 ESP-IDF 官方支持的 PHY 芯片驱动程序,或参阅 :ref:`Custom PHY Driver <custom-phy-driver>` 小节以创建新的自定义驱动程序。 使用 :cpp:func:`esp_eth_phy_new_generic` 创建新的 PHY 实例时,可以使用任何符合 IEEE 802.3 标准的以太网 PHY 芯片。然而,尽管 PHY 芯片符合 IEEE 802.3 标准,能提供基本功能,但某些特定的功能可能无法完全实现。例如,某些以太网 PHY 芯片可能需要配置特定的速度模式才能启用环回功能。遇到这种情况,需要配置 PHY 驱动程序以满足特定芯片需求,请使用 ESP-IDF 官方支持的 PHY 芯片驱动程序,或参阅 :ref:`Custom PHY Driver <custom-phy-driver>` 小节以创建新的自定义驱动程序。
.. tip::
乐鑫为多种特定的以太网 PHY 芯片提供了驱动程序,这些驱动程序可在 `esp-eth-drivers <https://github.com/espressif/esp-eth-drivers>`_ 仓库中获取。驱动以组件形式分发,并可在 `ESP 组件库 <https://components.espressif.com/>`_ 上获取。
可选的运行时 MAC 时钟配置 可选的运行时 MAC 时钟配置
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -329,7 +327,7 @@ ESP-IDF 在宏 :c:macro:`ETH_MAC_DEFAULT_CONFIG` 和 :c:macro:`ETH_PHY_DEFAULT_C
esp32_emac_config.interface = EMAC_DATA_INTERFACE_RMII; // 更改 EMAC 数据接口 esp32_emac_config.interface = EMAC_DATA_INTERFACE_RMII; // 更改 EMAC 数据接口
esp32_emac_config.clock_config.rmii.clock_mode = EMAC_CLK_OUT; // 配置 EMAC REF_CLK 模式 esp32_emac_config.clock_config.rmii.clock_mode = EMAC_CLK_OUT; // 配置 EMAC REF_CLK 模式
esp32_emac_config.clock_config.rmii.clock_gpio = EMAC_CLK_OUT_GPIO; // 配置用于输入/输出 EMAC REF_CLK 的 GPIO 编号 esp32_emac_config.clock_config.rmii.clock_gpio = 17; // 配置用于输入/输出 EMAC REF_CLK 的 GPIO 编号
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); // 创建 MAC 实例 esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); // 创建 MAC 实例
@@ -375,6 +373,8 @@ SPI-Ethernet 模块
* 针对不同的以太网模块,或是为了满足特定 PCB 上的 SPI 时序SPI 从机设备配置(即 `spi_device_interface_config_t`)可能略有不同。具体配置请查看模块规格以及 ESP-IDF 中的示例。 * 针对不同的以太网模块,或是为了满足特定 PCB 上的 SPI 时序SPI 从机设备配置(即 `spi_device_interface_config_t`)可能略有不同。具体配置请查看模块规格以及 ESP-IDF 中的示例。
.. tip::
乐鑫为多种 SPI-Ethernet 模块提供了驱动程序,这些驱动程序可在 `esp-eth-drivers <https://github.com/espressif/esp-eth-drivers>`_ 仓库中获取。驱动以组件形式分发,并可在 `ESP 组件库 <https://components.espressif.com/>`_ 上获取。
安装驱动程序 安装驱动程序
-------------- --------------
@@ -383,7 +383,7 @@ SPI-Ethernet 模块
* :cpp:member:`esp_eth_config_t::mac`:由 MAC 生成器创建的实例(例如 :cpp:func:`esp_eth_mac_new_esp32`)。 * :cpp:member:`esp_eth_config_t::mac`:由 MAC 生成器创建的实例(例如 :cpp:func:`esp_eth_mac_new_esp32`)。
* :cpp:member:`esp_eth_config_t::phy`:由 PHY 生成器创建的实例(例如 :cpp:func:`esp_eth_phy_new_ip101`)。 * :cpp:member:`esp_eth_config_t::phy`:由 PHY 生成器创建的实例(例如 :cpp:func:`esp_eth_phy_new_generic`)。
* :cpp:member:`esp_eth_config_t::check_link_period_ms`:以太网驱动程序会启用操作系统定时器来定期检查链接状态。该字段用于设置间隔时间,单位为毫秒。 * :cpp:member:`esp_eth_config_t::check_link_period_ms`:以太网驱动程序会启用操作系统定时器来定期检查链接状态。该字段用于设置间隔时间,单位为毫秒。
@@ -644,11 +644,11 @@ ESP-IDF 以太网驱动程序所需的大部分 PHY 管理功能都已涵盖在
**创建自定义 PHY 驱动程序的步骤:** **创建自定义 PHY 驱动程序的步骤:**
1. 请根据 PHY 数据手册,定义针对供应商的特定注册表布局。示例请参见 :component_file:`esp_eth/src/phy/esp_eth_phy_ip101.c` 1. 请根据 PHY 数据手册,定义厂家私有的寄存器
2. 准备衍生的 PHY 管理对象信息结构,该结构: 2. 准备衍生的 PHY 管理对象信息结构,该结构:
* 必须至少包含 IEEE 802.3 :cpp:class:`phy_802_3_t` 父对象 * 必须至少包含 IEEE 802.3 :cpp:class:`phy_802_3_t` 父对象
* 可选择包含额外的变量,以支持非 IEEE 802.3 或定制功能。示例请参见 :component_file:`esp_eth/src/phy/esp_eth_phy_ksz80xx.c` * 可选择包含额外的变量,以支持非 IEEE 802.3 或定制功能。
3. 定义针对芯片的特定管理回调功能。 3. 定义针对芯片的特定管理回调功能。
4. 初始化 IEEE 802.3 父对象并重新分配针对芯片的特定管理回调功能。 4. 初始化 IEEE 802.3 父对象并重新分配针对芯片的特定管理回调功能。

View File

@@ -43,6 +43,32 @@
**影响**:使用 ``ETH_ESP32_EMAC_DEFAULT_CONFIG()`` 的应用程序可继续正常工作。自定义时钟配置需在 EMAC 配置结构体中显式设置,或使用 `Ethernet Init 组件 <https://components.espressif.com/components/espressif/ethernet_init>`_ **影响**:使用 ``ETH_ESP32_EMAC_DEFAULT_CONFIG()`` 的应用程序可继续正常工作。自定义时钟配置需在 EMAC 配置结构体中显式设置,或使用 `Ethernet Init 组件 <https://components.espressif.com/components/espressif/ethernet_init>`_
以太网 PHY 和以太网 SPI 模块驱动已从 ESP-IDF 移至外部仓库
-------------------------------------------------------------
以太网 PHY 和以太网 SPI 模块驱动已从 ESP-IDF 中移除,并迁移至 `esp-eth-drivers <https://github.com/espressif/esp-eth-drivers>`_ 仓库。如果你在项目中使用这些驱动,需要将其作为组件集成。相关驱动现已在 `ESP 组件库 <https://components.espressif.com/>`_ 上提供。
**移除的 API**
- :cpp:func:`esp_eth_phy_new_ip101`
- :cpp:func:`esp_eth_phy_new_lan87xx`
- :cpp:func:`esp_eth_phy_new_rtl8201`
- :cpp:func:`esp_eth_phy_new_dp83848`
- :cpp:func:`esp_eth_phy_new_ksz80xx`
- :cpp:func:`esp_eth_mac_new_dm9051`
- :cpp:func:`esp_eth_phy_new_dm9051`
- :cpp:func:`esp_eth_mac_new_ksz8851snl`
- :cpp:func:`esp_eth_phy_new_ksz8851snl`
- :cpp:func:`esp_eth_mac_new_w5500`
- :cpp:func:`esp_eth_phy_new_w5500`
**影响**:原本依赖 ESP-IDF 内置以太网 PHY 和以太网 SPI 模块驱动的应用将无法继续工作。
**迁移方式**
请通过 `idf.py add-dependency` 命令,从 `IDF 组件管理器 <https://components.espressif.com/>`_ 添加驱动组件到你的项目,并包含相应的 `esp_eth_phy_xxxx.h` 和 `esp_eth_mac_xxxx.h` 头文件,或使用 `Ethernet Init 组件 <https://components.espressif.com/components/espressif/ethernet_init>`_
ESP-NETIF ESP-NETIF
********* *********

View File

@@ -137,7 +137,7 @@ menu "Example Connection Configuration"
choice EXAMPLE_ETHERNET_TYPE choice EXAMPLE_ETHERNET_TYPE
prompt "Ethernet Type" prompt "Ethernet Type"
default EXAMPLE_USE_INTERNAL_ETHERNET if SOC_EMAC_SUPPORTED default EXAMPLE_USE_INTERNAL_ETHERNET if SOC_EMAC_SUPPORTED
default EXAMPLE_USE_W5500 default EXAMPLE_USE_DUMMY
help help
Select which kind of Ethernet will be used in the example. Select which kind of Ethernet will be used in the example.
@@ -148,21 +148,11 @@ menu "Example Connection Configuration"
help help
Select internal Ethernet MAC controller. Select internal Ethernet MAC controller.
config EXAMPLE_USE_DM9051 config EXAMPLE_USE_DUMMY
bool "DM9051 Module" bool "DUMMY Module"
select EXAMPLE_USE_SPI_ETHERNET
select ETH_USE_SPI_ETHERNET select ETH_USE_SPI_ETHERNET
select ETH_SPI_ETHERNET_DM9051
help help
Select external SPI-Ethernet module. Dummy option to just to pass builds, will be fixed by IDF-14059
config EXAMPLE_USE_W5500
bool "W5500 Module"
select EXAMPLE_USE_SPI_ETHERNET
select ETH_USE_SPI_ETHERNET
select ETH_SPI_ETHERNET_W5500
help
Select external SPI-Ethernet module (W5500).
config EXAMPLE_USE_OPENETH config EXAMPLE_USE_OPENETH
bool "OpenCores Ethernet MAC (EXPERIMENTAL)" bool "OpenCores Ethernet MAC (EXPERIMENTAL)"
@@ -179,7 +169,7 @@ menu "Example Connection Configuration"
if EXAMPLE_USE_INTERNAL_ETHERNET if EXAMPLE_USE_INTERNAL_ETHERNET
choice EXAMPLE_ETH_PHY_MODEL choice EXAMPLE_ETH_PHY_MODEL
prompt "Ethernet PHY Device" prompt "Ethernet PHY Device"
default EXAMPLE_ETH_PHY_IP101 default EXAMPLE_ETH_PHY_GENERIC
help help
Select the Ethernet PHY device to use in the example. Select the Ethernet PHY device to use in the example.
@@ -191,46 +181,6 @@ menu "Example Connection Configuration"
even if the PHY meets IEEE 802.3 standard. A typical example is loopback even if the PHY meets IEEE 802.3 standard. A typical example is loopback
functionality, where certain PHYs may require setting a specific speed mode to functionality, where certain PHYs may require setting a specific speed mode to
operate correctly. operate correctly.
config EXAMPLE_ETH_PHY_IP101
bool "IP101"
help
IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
config EXAMPLE_ETH_PHY_RTL8201
bool "RTL8201/SR8201"
help
RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
config EXAMPLE_ETH_PHY_LAN87XX
bool "LAN87xx"
help
Below chips are supported:
LAN8710A is a small footprint MII/RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and
flexPWR® Technology.
LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
LAN8740A/LAN8741A is a small footprint MII/RMII 10/100 Energy Efficient Ethernet Transceiver
with HP Auto-MDIX and flexPWR® Technology.
LAN8742A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and
flexPWR® Technology.
Goto https://www.microchip.com for more information about them.
config EXAMPLE_ETH_PHY_DP83848
bool "DP83848"
help
DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
Goto http://www.ti.com/product/DP83848J for more information about it.
config EXAMPLE_ETH_PHY_KSZ80XX
bool "KSZ80xx"
help
With the KSZ80xx series, Microchip offers single-chip 10BASE-T/100BASE-TX
Ethernet Physical Layer Transceivers (PHY).
The following chips are supported: KSZ8001, KSZ8021, KSZ8031, KSZ8041,
KSZ8051, KSZ8061, KSZ8081, KSZ8091
Goto https://www.microchip.com for more information about them.
endchoice endchoice
config EXAMPLE_ETH_MDC_GPIO config EXAMPLE_ETH_MDC_GPIO
@@ -250,65 +200,6 @@ menu "Example Connection Configuration"
Set the GPIO number used by SMI MDIO. Set the GPIO number used by SMI MDIO.
endif endif
if EXAMPLE_USE_SPI_ETHERNET
config EXAMPLE_ETH_SPI_HOST
int "SPI Host Number"
range 0 2
default 1
help
Set the SPI host used to communicate with the SPI Ethernet Controller.
config EXAMPLE_ETH_SPI_SCLK_GPIO
int "SPI SCLK GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 14
help
Set the GPIO number used by SPI SCLK.
config EXAMPLE_ETH_SPI_MOSI_GPIO
int "SPI MOSI GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 13
help
Set the GPIO number used by SPI MOSI.
config EXAMPLE_ETH_SPI_MISO_GPIO
int "SPI MISO GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
default 12
help
Set the GPIO number used by SPI MISO.
config EXAMPLE_ETH_SPI_CS_GPIO
int "SPI CS GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 15
help
Set the GPIO number used by SPI CS.
config EXAMPLE_ETH_SPI_CLOCK_MHZ
int "SPI clock speed (MHz)"
range 5 80
default 36
help
Set the clock speed (MHz) of SPI interface.
config EXAMPLE_ETH_SPI_INT_GPIO
int "Interrupt GPIO number"
range -1 ENV_GPIO_IN_RANGE_MAX
default 4
help
Set the GPIO number used by the SPI Ethernet module interrupt line.
Set -1 to use SPI Ethernet module in polling mode.
config EXAMPLE_ETH_SPI_POLLING_MS_VAL
depends on EXAMPLE_ETH_SPI_INT_GPIO < 0
int "Polling period in msec of SPI Ethernet Module"
default 10
help
Set SPI Ethernet module polling period.
endif # EXAMPLE_USE_SPI_ETHERNET
config EXAMPLE_ETH_PHY_RST_GPIO config EXAMPLE_ETH_PHY_RST_GPIO
int "PHY Reset GPIO number" int "PHY Reset GPIO number"
range -1 ENV_GPIO_OUT_RANGE_MAX range -1 ENV_GPIO_OUT_RANGE_MAX

View File

@@ -9,9 +9,6 @@
#include "example_common_private.h" #include "example_common_private.h"
#include "esp_event.h" #include "esp_event.h"
#include "esp_eth.h" #include "esp_eth.h"
#if CONFIG_ETH_USE_SPI_ETHERNET
#include "driver/spi_master.h"
#endif // CONFIG_ETH_USE_SPI_ETHERNET
#include "esp_log.h" #include "esp_log.h"
#include "esp_mac.h" #include "esp_mac.h"
#include "driver/gpio.h" #include "driver/gpio.h"
@@ -82,6 +79,10 @@ static esp_eth_netif_glue_handle_t s_eth_glue = NULL;
static esp_netif_t *eth_start(void) static esp_netif_t *eth_start(void)
{ {
// TODO just to pass builds, will be fixed by IDF-14059
#if CONFIG_EXAMPLE_USE_DUMMY
return NULL;
#else
esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH(); esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();
// Warning: the interface desc is used in tests to capture actual connection details (IP, gw, mask) // Warning: the interface desc is used in tests to capture actual connection details (IP, gw, mask)
esp_netif_config.if_desc = EXAMPLE_NETIF_DESC_ETH; esp_netif_config.if_desc = EXAMPLE_NETIF_DESC_ETH;
@@ -105,72 +106,17 @@ static esp_netif_t *eth_start(void)
s_mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); s_mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
#if CONFIG_EXAMPLE_ETH_PHY_GENERIC #if CONFIG_EXAMPLE_ETH_PHY_GENERIC
s_phy = esp_eth_phy_new_generic(&phy_config); s_phy = esp_eth_phy_new_generic(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_IP101
s_phy = esp_eth_phy_new_ip101(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
s_phy = esp_eth_phy_new_rtl8201(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_LAN87XX
s_phy = esp_eth_phy_new_lan87xx(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_DP83848
s_phy = esp_eth_phy_new_dp83848(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_KSZ80XX
s_phy = esp_eth_phy_new_ksz80xx(&phy_config);
#endif // CONFIG_EXAMPLE_ETH_PHY_GENERIC #endif // CONFIG_EXAMPLE_ETH_PHY_GENERIC
#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
gpio_install_isr_service(0);
spi_bus_config_t buscfg = {
.miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO,
.mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO,
.sclk_io_num = CONFIG_EXAMPLE_ETH_SPI_SCLK_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
};
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
spi_device_interface_config_t spi_devcfg = {
.mode = 0,
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
.queue_size = 20
};
#if CONFIG_EXAMPLE_USE_DM9051
/* dm9051 ethernet driver is based on spi driver */
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(CONFIG_EXAMPLE_ETH_SPI_HOST, &spi_devcfg);
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
#if CONFIG_EXAMPLE_ETH_SPI_INT_GPIO < 0
dm9051_config.poll_period_ms = CONFIG_EXAMPLE_ETH_SPI_POLLING_MS_VAL;
#endif // CONFIG_EXAMPLE_ETH_SPI_INT_GPIO
s_mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
s_phy = esp_eth_phy_new_dm9051(&phy_config);
#elif CONFIG_EXAMPLE_USE_W5500
/* w5500 ethernet driver is based on spi driver */
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(CONFIG_EXAMPLE_ETH_SPI_HOST, &spi_devcfg);
w5500_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
#if CONFIG_EXAMPLE_ETH_SPI_INT_GPIO < 0
w5500_config.poll_period_ms = CONFIG_EXAMPLE_ETH_SPI_POLLING_MS_VAL;
#endif // CONFIG_EXAMPLE_ETH_SPI_INT_GPIO
s_mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
s_phy = esp_eth_phy_new_w5500(&phy_config);
#endif // CONFIG_EXAMPLE_USE_DM9051
#elif CONFIG_EXAMPLE_USE_OPENETH #elif CONFIG_EXAMPLE_USE_OPENETH
phy_config.autonego_timeout_ms = 100; phy_config.autonego_timeout_ms = 100;
s_mac = esp_eth_mac_new_openeth(&mac_config); s_mac = esp_eth_mac_new_openeth(&mac_config);
s_phy = esp_eth_phy_new_dp83848(&phy_config); s_phy = esp_eth_phy_new_generic(&phy_config);
#endif // CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET #endif // CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
// Install Ethernet driver // Install Ethernet driver
esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy); esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy);
ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle)); ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
#if CONFIG_EXAMPLE_USE_SPI_ETHERNET
/* The SPI Ethernet module might doesn't have a burned factory MAC address, we cat to set it manually.
We set the ESP_MAC_ETH mac address as the default, if you want to use ESP_MAC_EFUSE_CUSTOM mac address, please enable the
configuration: `ESP_MAC_USE_CUSTOM_MAC_AS_BASE_MAC`
*/
uint8_t eth_mac[6] = {0};
ESP_ERROR_CHECK(esp_read_mac(eth_mac, ESP_MAC_ETH));
ESP_ERROR_CHECK(esp_eth_ioctl(s_eth_handle, ETH_CMD_S_MAC_ADDR, eth_mac));
#endif // CONFIG_EXAMPLE_USE_SPI_ETHERNET
// combine driver with netif // combine driver with netif
s_eth_glue = esp_eth_new_netif_glue(s_eth_handle); s_eth_glue = esp_eth_new_netif_glue(s_eth_handle);
esp_netif_attach(netif, s_eth_glue); esp_netif_attach(netif, s_eth_glue);
@@ -184,6 +130,7 @@ static esp_netif_t *eth_start(void)
esp_eth_start(s_eth_handle); esp_eth_start(s_eth_handle);
return netif; return netif;
#endif // CONFIG_EXAMPLE_USE_DUMMY
} }
static void eth_stop(void) static void eth_stop(void)

View File

@@ -4,20 +4,13 @@ examples/ethernet/basic:
enable: enable:
- if: INCLUDE_DEFAULT == 1 - if: INCLUDE_DEFAULT == 1
disable: disable:
- if: IDF_TARGET in ["esp32h21", "esp32h4"] - if: IDF_TARGET not in ["esp32", "esp32p4"]
temporary: true
reason: not supported yet # TODO: [ESP32H21] IDF-11581 [ESP32H4] IDF-12360
disable_test:
- if: IDF_TARGET not in ["esp32"]
temporary: true
reason: lack of runners
depends_components: depends_components:
- esp_eth - esp_eth
- esp_netif - esp_netif
- lwip - lwip
- esp_event - esp_event
- esp_driver_gpio - esp_driver_gpio
- esp_driver_spi
examples/ethernet/iperf: examples/ethernet/iperf:
disable: disable:

View File

@@ -5,86 +5,32 @@
See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples. See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples.
## Common Pin Assignments Ethernet examples demonstrate basic features related to Ethernet layer, such as:
### Using ESP32 internal MAC * basic Ethernet initialization and binding to IP stack via ESP-NETIF
* RMII PHY wiring is fixed and can not be changed through either IOMUX or GPIO Matrix. By default, they're connected as follows: * tools for performance measurement, i.e. `iperf`
| GPIO | RMII Signal | Notes | * hardware time synchronization
| ------ | ----------- | ------------ |
| GPIO21 | TX_EN | EMAC_TX_EN |
| GPIO19 | TX0 | EMAC_TXD0 |
| GPIO22 | TX1 | EMAC_TXD1 |
| GPIO25 | RX0 | EMAC_RXD0 |
| GPIO26 | RX1 | EMAC_RXD1 |
| GPIO27 | CRS_DV | EMAC_RX_DRV |
* One of the following GPIO pins can be used as RMII REF_CLK input/output: ## ESP-IDF Ethernet Driver
| GPIO | Function | Notes | By default, ESP-IDF offers drivers for its internal Ethernet MAC (see Espressif documentation for supported chips) and for Generic IEEE 802.3 compliant PHYs. However, it does not limit users to use just those options. It is possible to create specific MAC and PHY layer drivers tailored for specific chip needs, including SPI Ethernet modules. Espressif maintains additional Ethernet drivers at [esp-eth-drivers repository](https://github.com/espressif/esp-eth-drivers) and the drivers are accessible via [The ESP Component Registry](https://components.espressif.com/) from users' projects.
| ------ | -------------------- | ------------ |
| GPIO0 | EMAC_TX_CLK/CLK_OUT1 | input/output |
| GPIO16 | EMAC_CLK_OUT | output |
| GPIO17 | EMAC_CLK_180 | output |
* SMI (Serial Management Interface) wiring is not fixed. You may need to changed it according to your board schematic. By default they're connected as follows: ## Component for Ethernet Initialization
| GPIO | SMI Signal | Notes | The `Component for Ethernet Initialization` is a component intended for simple initialization of a wide range of Ethernet PHY chips, including SPI Ethernet modules and for advanced Ethernet configuration options, see [its homepage](https://components.espressif.com/components/espressif/ethernet_init/) for more information.
| ------ | ----------- | ------------- |
| GPIO23 | MDC | Output to PHY |
| GPIO18 | MDIO | Bidirectional |
* PHY chip has a reset pin, if want to do a hardware reset during initialization, then you have to connect it with one GPIO on ESP32. See more information from [here](#configure-the-project). The default GPIO used for resetting PHY chip is GPIO5.
### Using SPI ethernet modules
* SPI Ethernet modules (DM9051, W5500, ...) typically consume one SPI interface plus an interrupt and reset GPIO. They can be connected as follows for ESP32 as an example. However, they can be remapped to any pin using the GPIO Matrix.
| GPIO | DM9051 |
| ------ | ----------- |
| GPIO14 | SPI_CLK |
| GPIO13 | SPI_MOSI |
| GPIO12 | SPI_MISO |
| GPIO15 | SPI_CS |
| GPIO4 | Interrupt |
| NC | Reset |
---
**Warning:**
Please consult Espressif Technical reference manual along with datasheet for specific ESP Module you use when assigning any other pins, especially when choosing from system configuration menu for the ethernet examples, some pins cannot be used (they may already be utilized for different purpose like SPI Flash/RAM, some pins might be inputs only, etc.).
---
## Common Configurations
1. In the `Example Ethernet Configuration` menu:
* Choose the kind of Ethernet.
* If `Internal EMAC` is selected:
* Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board.
* Set GPIO number used by SMI signal under `SMI MDC GPIO number` and `SMI MDIO GPIO number` respectively.
* If `SPI Ethernet` is selected:
* Set SPI specific configuration, including SPI host number, GPIO numbers and clock rate.
* Multiple Ethernet SPI modules of the same type can be connected to single SPI interface at a time. The modules then share data and CLK signals. The CS, interrupt and reset pins need to be specifically configured for each module separately.
* Set GPIO number used by PHY chip reset under `PHY Reset GPIO number`, you may have to change the default value according to your board schematic. **PHY hardware reset can be disabled by set this value to -1**.
* Set PHY address under `PHY Address`, you may have to change the default value according to your board schematic.
2. In the `Component config > Ethernet` menu:
* Under `Support ESP32 internal EMAC controller` sub-menu:
* In the `PHY interface`, select `Reduced Media Independent Interface (RMII)`, ESP-IDF currently only support RMII mode.
* In the `RMII clock mode`, select one of the source that RMII clock (50MHz) comes from: `Input RMII clock from external` or `Output RMII clock from internal`.
* If `Output RMII clock from internal` is enabled, you also have to set the GPIO number that used to output the RMII clock, under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17.
* If `Output RMII clock from GPIO0 (Experimental!)` is also enabled, then you have no choice but GPIO0 to output the RMII clock.
* In `Amount of Ethernet DMA Rx buffers` and `Amount of Ethernet DMA Tx buffers`, you can set the amount of DMA buffers used for Tx and Rx.
* Under `Support SPI to Ethernet Module` sub-menu, select the SPI module that you used for this example. Currently ESP-IDF only supports `DM9051`, `W5500` and `KSZ8851SNL`.
## Common Troubleshooting ## Common Troubleshooting
* The data panel between ESP32's MAC and PHY needs a fixed 50MHz clock to do synchronization, which also called RMII clock. It can either be provided by an external oscillator or generated from internal APLL. The signal integrity of RMII clock is strict, so keep the trace as short as possible! * The data path between ESP32's MAC and PHY needs a fixed 50MHz clock for synchronization, which is also called RMII REF clock. It can either be provided by an external oscillator or generated from internal PLL. The signal integrity of RMII clock is strict, so keep the trace as short as possible!
* If the RMII clock is generated from internal APLL, then APLL can't be used for other purpose (e.g. I2S). * If you observe undefined behavior (e.g. LCD glitches) of any **SPI device** which works normally when Ethernet is not connected over internal EMAC, you need to adjust EMAC DMA burst length (the DMA is a shared resource between EMAC and the SPI). The same applies when you observe Ethernet frame corruption at the output of SPI Ethernet module and you use a combination of internal EMAC and SPI Ethernet module as network interfaces. To configure the EMAC DMA burst length, modify internal Ethernet initialization as follows:
* If you observe undefined behavior (e.g. LCD glitches) of any **SPI device** which works normally when Ethernet is not connected over internal EMAC, you need to adjust EMAC DMA burst length (the DMA is shared resource between EMAC and the SPI). The same applies when you observe Ethernet frames corruption at the output of SPI Ethernet module and you use combination of internal EMAC and SPI Ethernet module as network interfaces. To configure the EMAC DMA burst length, modify internal Ethernet initialization as follows:
```c ```c
esp32_emac_config.dma_burst_len = ETH_DMA_BURST_LEN_4; // or other appropriate value esp32_emac_config.dma_burst_len = ETH_DMA_BURST_LEN_4; // or other appropriate value
``` ```
* ESP32 limitations:
* If the RMII clock is generated from internal APLL, then APLL can't be used for other purposes (e.g. I2S).
* If Wi-Fi or Bluetooth are used simultaneously with Ethernet, the RMII clock cannot be generated by the internal APLL clock, as it would result in clock instability. See [ESP32 errata](https://docs.espressif.com/projects/esp-chip-errata/en/latest/esp32/03-errata-description/index.html#clock-esp32-cannot-be-used-as-the-phy-clock-source-if-wi-fi-and-ethernet-are-used-at-the-same-time) for more information.

View File

@@ -1,38 +1,35 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | | Supported Targets | ESP32 | ESP32-P4 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | | ----------------- | ----- | -------- |
# Ethernet Example # Basic Ethernet Example
(See the README.md file in the upper level 'examples' directory for more information about examples.) (See the README.md file in the upper level 'examples' directory for more information about examples.)
## Overview ## Overview
This example demonstrates basic usage of `Ethernet driver` together with `esp_netif`. Initialization of the `Ethernet driver` is wrapped in separate [sub-component](./components/ethernet_init/ethernet_init.c) of this project to clearly distinguish between the driver's and `esp_netif` initializations. The work flow of the example could be as follows: This example demonstrates basic usage of internal EMAC and `Ethernet driver` together with `esp_netif`. The workflow of the example is as follows:
1. Install Ethernet driver 1. Install Ethernet driver
2. Attach the driver to `esp_netif` 2. Attach the driver to `esp_netif`
3. Send DHCP requests and wait for a DHCP lease 3. Send DHCP requests and wait for a DHCP lease
4. If get IP address successfully, then you will be able to ping the device 4. If get IP address successfully, then you will be able to ping the device
If you have a new Ethernet application to go (for example, connect to IoT cloud via Ethernet), try this as a basic template, then add your own code. If you have a new simple Ethernet application to go (for example, connect to IoT cloud via Ethernet), try this as a basic template, then add your own code.
>[!TIP]
> For initialization of a wider range of Ethernet PHY chips, including SPI Ethernet modules and for advanced Ethernet configuration options, please use [Component for Ethernet Initialization](https://components.espressif.com/components/espressif/ethernet_init/).
## How to use example ## How to use example
### Hardware Required ### Hardware Required
To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves. To run this example, it's recommended that you have an official Espressif Ethernet capable development board - either [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32/esp32-ethernet-kit/index.html) or [ESP32-P4-Function-EV-Board](https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32p4/esp32-p4-function-ev-board/index.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a IEEE 802.3 compliant Ethernet PHY chip and with the default RMII dataplane GPIO configuration.
Besides that, `esp_eth` component can drive third-party Ethernet module which integrates MAC and PHY and provides common communication interface (e.g. SPI, USB, etc). This example will take the `DM9051`, `W5500` or `KSZ8851SNL` SPI modules as an example, illustrating how to install the Ethernet driver in the same manner. > [!NOTE]
> `Generic 802.3 PHY` basic functionality should always work for PHY compliant with IEEE 802.3. However, some specific features might be limited. A typical example is loopback functionality, where certain PHYs may require setting a specific speed mode to operate correctly. If this is a case, use driver tailored to that specific chip.
The ESP-IDF supports the usage of multiple Ethernet interfaces at a time when external modules are utilized which is also demonstrated by this example. There are several options you can combine:
* Internal EMAC and one SPI Ethernet module.
* Two SPI Ethernet modules of the same type connected to single SPI interface and accessed by switching appropriate CS.
* Internal EMAC and two SPI Ethernet modules of the same type.
#### Pin Assignment #### Pin Assignment
See common pin assignments for Ethernet examples from [upper level](../README.md#common-pin-assignments). This example uses the default RMII GPIO configuration as defined by `ETH_ESP32_EMAC_DEFAULT_CONFIG` for the specific ESP32 chip (ESP32, ESP32P4, etc.).
When using two Ethernet SPI modules at a time, they are to be connected to single SPI interface. Both modules then share data (MOSI/MISO) and CLK signals. However, the CS, interrupt and reset pins need to be connected to separate GPIO for each Ethernet SPI module.
### Configure the project ### Configure the project

View File

@@ -1,3 +0,0 @@
idf_component_register(SRCS "ethernet_init.c"
PRIV_REQUIRES esp_driver_gpio esp_eth
INCLUDE_DIRS ".")

View File

@@ -1,308 +0,0 @@
menu "Example Ethernet Configuration"
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
config EXAMPLE_USE_INTERNAL_ETHERNET
depends on SOC_EMAC_SUPPORTED
select ETH_USE_ESP32_EMAC
default y
bool "Internal EMAC"
help
Use internal Ethernet MAC controller.
if EXAMPLE_USE_INTERNAL_ETHERNET
choice EXAMPLE_ETH_PHY_MODEL
prompt "Ethernet PHY Device"
default EXAMPLE_ETH_PHY_IP101
help
Select the Ethernet PHY device to use in the example.
config EXAMPLE_ETH_PHY_GENERIC
bool "Generic 802.3 PHY"
help
Any Ethernet PHY chip compliant with IEEE 802.3 can be used. However, while
basic functionality should always work, some specific features might be limited,
even if the PHY meets IEEE 802.3 standard. A typical example is loopback
functionality, where certain PHYs may require setting a specific speed mode to
operate correctly.
config EXAMPLE_ETH_PHY_IP101
bool "IP101"
help
IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
config EXAMPLE_ETH_PHY_RTL8201
bool "RTL8201/SR8201"
help
RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
config EXAMPLE_ETH_PHY_LAN87XX
bool "LAN87xx"
help
Below chips are supported:
LAN8710A is a small footprint MII/RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and
flexPWR® Technology.
LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
LAN8740A/LAN8741A is a small footprint MII/RMII 10/100 Energy Efficient Ethernet Transceiver
with HP Auto-MDIX and flexPWR® Technology.
LAN8742A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and
flexPWR® Technology.
Goto https://www.microchip.com for more information about them.
config EXAMPLE_ETH_PHY_DP83848
bool "DP83848"
help
DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
Goto http://www.ti.com/product/DP83848J for more information about it.
config EXAMPLE_ETH_PHY_KSZ80XX
bool "KSZ80xx"
help
With the KSZ80xx series, Microchip offers single-chip 10BASE-T/100BASE-TX
Ethernet Physical Layer Transceivers (PHY).
The following chips are supported: KSZ8001, KSZ8021, KSZ8031, KSZ8041,
KSZ8051, KSZ8061, KSZ8081, KSZ8091
Goto https://www.microchip.com for more information about them.
endchoice # EXAMPLE_ETH_PHY_MODEL
config EXAMPLE_ETH_MDC_GPIO
int "SMI MDC GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 23 if IDF_TARGET_ESP32
default 31 if IDF_TARGET_ESP32P4
help
Set the GPIO number used by SMI MDC.
config EXAMPLE_ETH_MDIO_GPIO
int "SMI MDIO GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 18 if IDF_TARGET_ESP32
default 52 if IDF_TARGET_ESP32P4
help
Set the GPIO number used by SMI MDIO.
config EXAMPLE_ETH_PHY_RST_GPIO
int "PHY Reset GPIO number"
range -1 ENV_GPIO_OUT_RANGE_MAX
default 5 if IDF_TARGET_ESP32
default 51 if IDF_TARGET_ESP32P4
help
Set the GPIO number used to reset PHY chip.
Set to -1 to disable PHY chip hardware reset.
config EXAMPLE_ETH_PHY_ADDR
int "PHY Address"
range -1 31
default 1
help
Set PHY address according your board schematic.
Set to -1 to driver find the PHY address automatically.
endif # EXAMPLE_USE_INTERNAL_ETHERNET
config EXAMPLE_USE_SPI_ETHERNET
bool "SPI Ethernet"
default n
select ETH_USE_SPI_ETHERNET
help
Use external SPI-Ethernet module(s).
if EXAMPLE_USE_SPI_ETHERNET
config EXAMPLE_SPI_ETHERNETS_NUM
int "Number of SPI Ethernet modules to use at a time"
range 1 2
default 1
help
Set the number of SPI Ethernet modules you want to use at a time. Multiple SPI modules can be connected
to one SPI interface and can be separately accessed based on state of associated Chip Select (CS).
choice EXAMPLE_ETHERNET_TYPE_SPI
prompt "Ethernet SPI"
default EXAMPLE_USE_W5500
help
Select which kind of Ethernet will be used in the example.
config EXAMPLE_USE_DM9051
bool "DM9051 Module"
select ETH_SPI_ETHERNET_DM9051
help
Select external SPI-Ethernet module (DM9051).
config EXAMPLE_USE_KSZ8851SNL
bool "KSZ8851SNL Module"
select ETH_SPI_ETHERNET_KSZ8851SNL
help
Select external SPI-Ethernet module (KSZ8851SNL).
config EXAMPLE_USE_W5500
bool "W5500 Module"
select ETH_SPI_ETHERNET_W5500
help
Select external SPI-Ethernet module (W5500).
endchoice
config EXAMPLE_ETH_SPI_HOST
int "SPI Host Number"
range 0 2
default 1
help
Set the SPI host used to communicate with the SPI Ethernet Controller.
config EXAMPLE_ETH_SPI_SCLK_GPIO
int "SPI SCLK GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 14 if IDF_TARGET_ESP32
default 12 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 6 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C61
default 4 if IDF_TARGET_ESP32H2
default 33 if IDF_TARGET_ESP32P4
default 8 if IDF_TARGET_ESP32C5
help
Set the GPIO number used by SPI SCLK.
config EXAMPLE_ETH_SPI_MOSI_GPIO
int "SPI MOSI GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 13 if IDF_TARGET_ESP32
default 11 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 7 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C61
default 5 if IDF_TARGET_ESP32H2
default 32 if IDF_TARGET_ESP32P4
default 10 if IDF_TARGET_ESP32C5
help
Set the GPIO number used by SPI MOSI.
config EXAMPLE_ETH_SPI_MISO_GPIO
int "SPI MISO GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
default 12 if IDF_TARGET_ESP32
default 13 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 2 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C61
default 0 if IDF_TARGET_ESP32H2
default 24 if IDF_TARGET_ESP32P4
default 9 if IDF_TARGET_ESP32C5
help
Set the GPIO number used by SPI MISO.
config EXAMPLE_ETH_SPI_CLOCK_MHZ
int "SPI clock speed (MHz)"
range 5 80
default 16
help
Set the clock speed (MHz) of SPI interface.
config EXAMPLE_ETH_SPI_CS0_GPIO
int "SPI CS0 GPIO number for SPI Ethernet module #1"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 15 if IDF_TARGET_ESP32
default 10 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C2
default 3 if IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C61
default 1 if IDF_TARGET_ESP32H2
default 21 if IDF_TARGET_ESP32P4
help
Set the GPIO number used by SPI CS0, i.e. Chip Select associated with the first SPI Eth module).
config EXAMPLE_ETH_SPI_CS1_GPIO
depends on EXAMPLE_SPI_ETHERNETS_NUM > 1
int "SPI CS1 GPIO number for SPI Ethernet module #2"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 32 if IDF_TARGET_ESP32
default 7 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 8 if IDF_TARGET_ESP32C3
default 21 if IDF_TARGET_ESP32C6
default 3 if IDF_TARGET_ESP32C2
default 11 if IDF_TARGET_ESP32H2
default 23 if IDF_TARGET_ESP32P4 || IDF_TARGET_ESP32C61
default 1 if IDF_TARGET_ESP32C5
help
Set the GPIO number used by SPI CS1, i.e. Chip Select associated with the second SPI Eth module.
config EXAMPLE_ETH_SPI_INT0_GPIO
int "Interrupt GPIO number SPI Ethernet module #1"
range -1 ENV_GPIO_IN_RANGE_MAX
default 4 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
default 4 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C5
default 10 if IDF_TARGET_ESP32H2
default 48 if IDF_TARGET_ESP32P4
default 0 if IDF_TARGET_ESP32C61
help
Set the GPIO number used by the first SPI Ethernet module interrupt line.
Set -1 to use SPI Ethernet module in polling mode.
config EXAMPLE_ETH_SPI_INT1_GPIO
depends on EXAMPLE_SPI_ETHERNETS_NUM > 1
int "Interrupt GPIO number SPI Ethernet module #2"
range -1 ENV_GPIO_IN_RANGE_MAX
default 33 if IDF_TARGET_ESP32
default 5 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C2
default 5 if IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C5
default 9 if IDF_TARGET_ESP32H2
default 47 if IDF_TARGET_ESP32P4
default 1 if IDF_TARGET_ESP32C61
help
Set the GPIO number used by the second SPI Ethernet module interrupt line.
Set -1 to use SPI Ethernet module in polling mode.
config EXAMPLE_ETH_SPI_POLLING0_MS_VAL
depends on EXAMPLE_ETH_SPI_INT0_GPIO < 0
int "Polling period in msec of SPI Ethernet Module #1"
default 10
help
Set SPI Ethernet module polling period.
config EXAMPLE_ETH_SPI_POLLING1_MS_VAL
depends on EXAMPLE_SPI_ETHERNETS_NUM > 1 && EXAMPLE_ETH_SPI_INT1_GPIO < 0
int "Polling period in msec of SPI Ethernet Module #2"
default 10
help
Set SPI Ethernet module polling period.
# Hidden variable to ensure that polling period option is visible only when interrupt is set disabled and
# it is set to known value (0) when interrupt is enabled at the same time.
config EXAMPLE_ETH_SPI_POLLING0_MS
int
default EXAMPLE_ETH_SPI_POLLING0_MS_VAL if EXAMPLE_ETH_SPI_POLLING0_MS_VAL > 0
default 0
# Hidden variable to ensure that polling period option is visible only when interrupt is set disabled and
# it is set to known value (0) when interrupt is enabled at the same time.
config EXAMPLE_ETH_SPI_POLLING1_MS
depends on EXAMPLE_SPI_ETHERNETS_NUM > 1
int
default EXAMPLE_ETH_SPI_POLLING1_MS_VAL if EXAMPLE_ETH_SPI_POLLING1_MS_VAL > 0
default 0
config EXAMPLE_ETH_SPI_PHY_RST0_GPIO
int "PHY Reset GPIO number of SPI Ethernet Module #1"
range -1 ENV_GPIO_OUT_RANGE_MAX
default -1
help
Set the GPIO number used to reset PHY chip on the first SPI Ethernet module.
Set to -1 to disable PHY chip hardware reset.
config EXAMPLE_ETH_SPI_PHY_RST1_GPIO
depends on EXAMPLE_SPI_ETHERNETS_NUM > 1
int "PHY Reset GPIO number of SPI Ethernet Module #2"
range -1 ENV_GPIO_OUT_RANGE_MAX
default -1
help
Set the GPIO number used to reset PHY chip on the second SPI Ethernet module.
Set to -1 to disable PHY chip hardware reset.
config EXAMPLE_ETH_SPI_PHY_ADDR0
int "PHY Address of SPI Ethernet Module #1"
range 0 31
default 1
help
Set the first SPI Ethernet module PHY address according your board schematic.
config EXAMPLE_ETH_SPI_PHY_ADDR1
depends on EXAMPLE_SPI_ETHERNETS_NUM > 1
int "PHY Address of SPI Ethernet Module #2"
range 0 31
default 1
help
Set the second SPI Ethernet module PHY address according your board schematic.
endif # EXAMPLE_USE_SPI_ETHERNET
endmenu

View File

@@ -1,340 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "ethernet_init.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_mac.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#if CONFIG_EXAMPLE_USE_SPI_ETHERNET
#include "driver/spi_master.h"
#endif // CONFIG_EXAMPLE_USE_SPI_ETHERNET
#if CONFIG_EXAMPLE_SPI_ETHERNETS_NUM
#define SPI_ETHERNETS_NUM CONFIG_EXAMPLE_SPI_ETHERNETS_NUM
#else
#define SPI_ETHERNETS_NUM 0
#endif
#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
#define INTERNAL_ETHERNETS_NUM 1
#else
#define INTERNAL_ETHERNETS_NUM 0
#endif
#define INIT_SPI_ETH_MODULE_CONFIG(eth_module_config, num) \
do { \
eth_module_config[num].spi_cs_gpio = CONFIG_EXAMPLE_ETH_SPI_CS ##num## _GPIO; \
eth_module_config[num].int_gpio = CONFIG_EXAMPLE_ETH_SPI_INT ##num## _GPIO; \
eth_module_config[num].polling_ms = CONFIG_EXAMPLE_ETH_SPI_POLLING ##num## _MS; \
eth_module_config[num].phy_reset_gpio = CONFIG_EXAMPLE_ETH_SPI_PHY_RST ##num## _GPIO; \
eth_module_config[num].phy_addr = CONFIG_EXAMPLE_ETH_SPI_PHY_ADDR ##num; \
} while(0)
typedef struct {
uint8_t spi_cs_gpio;
int8_t int_gpio;
uint32_t polling_ms;
int8_t phy_reset_gpio;
uint8_t phy_addr;
uint8_t *mac_addr;
}spi_eth_module_config_t;
static const char *TAG = "example_eth_init";
#if CONFIG_EXAMPLE_USE_SPI_ETHERNET
static bool gpio_isr_svc_init_by_eth = false; // indicates that we initialized the GPIO ISR service
#endif // CONFIG_EXAMPLE_USE_SPI_ETHERNET
#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
/**
* @brief Internal ESP32 Ethernet initialization
*
* @param[out] mac_out optionally returns Ethernet MAC object
* @param[out] phy_out optionally returns Ethernet PHY object
* @return
* - esp_eth_handle_t if init succeeded
* - NULL if init failed
*/
static esp_eth_handle_t eth_init_internal(esp_eth_mac_t **mac_out, esp_eth_phy_t **phy_out)
{
esp_eth_handle_t ret = NULL;
// Init common MAC and PHY configs to default
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
// Update PHY config based on board specific configuration
phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR;
phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO;
// Init vendor specific MAC config to default
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
// Update vendor specific MAC config based on board configuration
esp32_emac_config.smi_gpio.mdc_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;
esp32_emac_config.smi_gpio.mdio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;
#if CONFIG_EXAMPLE_USE_SPI_ETHERNET
// The DMA is shared resource between EMAC and the SPI. Therefore, adjust
// EMAC DMA burst length when SPI Ethernet is used along with EMAC.
esp32_emac_config.dma_burst_len = ETH_DMA_BURST_LEN_4;
#endif // CONFIG_EXAMPLE_USE_SPI_ETHERNET
// Create new ESP32 Ethernet MAC instance
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
// Create new PHY instance based on board configuration
#if CONFIG_EXAMPLE_ETH_PHY_GENERIC
esp_eth_phy_t *phy = esp_eth_phy_new_generic(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_IP101
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_LAN87XX
esp_eth_phy_t *phy = esp_eth_phy_new_lan87xx(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_DP83848
esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_KSZ80XX
esp_eth_phy_t *phy = esp_eth_phy_new_ksz80xx(&phy_config);
#endif
// Init Ethernet driver to default and install it
esp_eth_handle_t eth_handle = NULL;
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
ESP_GOTO_ON_FALSE(esp_eth_driver_install(&config, &eth_handle) == ESP_OK, NULL,
err, TAG, "Ethernet driver install failed");
if (mac_out != NULL) {
*mac_out = mac;
}
if (phy_out != NULL) {
*phy_out = phy;
}
return eth_handle;
err:
if (eth_handle != NULL) {
esp_eth_driver_uninstall(eth_handle);
}
if (mac != NULL) {
mac->del(mac);
}
if (phy != NULL) {
phy->del(phy);
}
return ret;
}
#endif // CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
#if CONFIG_EXAMPLE_USE_SPI_ETHERNET
/**
* @brief SPI bus initialization (to be used by Ethernet SPI modules)
*
* @return
* - ESP_OK on success
*/
static esp_err_t spi_bus_init(void)
{
esp_err_t ret = ESP_OK;
#if (CONFIG_EXAMPLE_ETH_SPI_INT0_GPIO >= 0) || (CONFIG_EXAMPLE_ETH_SPI_INT1_GPIO > 0)
// Install GPIO ISR handler to be able to service SPI Eth modules interrupts
ret = gpio_install_isr_service(0);
if (ret == ESP_OK) {
gpio_isr_svc_init_by_eth = true;
} else if (ret == ESP_ERR_INVALID_STATE) {
ESP_LOGW(TAG, "GPIO ISR handler has been already installed");
ret = ESP_OK; // ISR handler has been already installed so no issues
} else {
ESP_LOGE(TAG, "GPIO ISR handler install failed");
goto err;
}
#endif
// Init SPI bus
spi_bus_config_t buscfg = {
.miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO,
.mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO,
.sclk_io_num = CONFIG_EXAMPLE_ETH_SPI_SCLK_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
};
ESP_GOTO_ON_ERROR(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO),
err, TAG, "SPI host #%d init failed", CONFIG_EXAMPLE_ETH_SPI_HOST);
err:
return ret;
}
/**
* @brief Ethernet SPI modules initialization
*
* @param[in] spi_eth_module_config specific SPI Ethernet module configuration
* @param[out] mac_out optionally returns Ethernet MAC object
* @param[out] phy_out optionally returns Ethernet PHY object
* @return
* - esp_eth_handle_t if init succeeded
* - NULL if init failed
*/
static esp_eth_handle_t eth_init_spi(spi_eth_module_config_t *spi_eth_module_config, esp_eth_mac_t **mac_out, esp_eth_phy_t **phy_out)
{
esp_eth_handle_t ret = NULL;
// Init common MAC and PHY configs to default
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
// Update PHY config based on board specific configuration
phy_config.phy_addr = spi_eth_module_config->phy_addr;
phy_config.reset_gpio_num = spi_eth_module_config->phy_reset_gpio;
// Configure SPI interface for specific SPI module
spi_device_interface_config_t spi_devcfg = {
.mode = 0,
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
.queue_size = 20,
.spics_io_num = spi_eth_module_config->spi_cs_gpio
};
// Init vendor specific MAC config to default, and create new SPI Ethernet MAC instance
// and new PHY instance based on board configuration
#if CONFIG_EXAMPLE_USE_KSZ8851SNL
eth_ksz8851snl_config_t ksz8851snl_config = ETH_KSZ8851SNL_DEFAULT_CONFIG(CONFIG_EXAMPLE_ETH_SPI_HOST, &spi_devcfg);
ksz8851snl_config.int_gpio_num = spi_eth_module_config->int_gpio;
ksz8851snl_config.poll_period_ms = spi_eth_module_config->polling_ms;
esp_eth_mac_t *mac = esp_eth_mac_new_ksz8851snl(&ksz8851snl_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_ksz8851snl(&phy_config);
#elif CONFIG_EXAMPLE_USE_DM9051
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(CONFIG_EXAMPLE_ETH_SPI_HOST, &spi_devcfg);
dm9051_config.int_gpio_num = spi_eth_module_config->int_gpio;
dm9051_config.poll_period_ms = spi_eth_module_config->polling_ms;
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
#elif CONFIG_EXAMPLE_USE_W5500
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(CONFIG_EXAMPLE_ETH_SPI_HOST, &spi_devcfg);
w5500_config.int_gpio_num = spi_eth_module_config->int_gpio;
w5500_config.poll_period_ms = spi_eth_module_config->polling_ms;
esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);
#endif //CONFIG_EXAMPLE_USE_W5500
// Init Ethernet driver to default and install it
esp_eth_handle_t eth_handle = NULL;
esp_eth_config_t eth_config_spi = ETH_DEFAULT_CONFIG(mac, phy);
ESP_GOTO_ON_FALSE(esp_eth_driver_install(&eth_config_spi, &eth_handle) == ESP_OK, NULL, err, TAG, "SPI Ethernet driver install failed");
// The SPI Ethernet module might not have a burned factory MAC address, we can set it manually.
if (spi_eth_module_config->mac_addr != NULL) {
ESP_GOTO_ON_FALSE(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, spi_eth_module_config->mac_addr) == ESP_OK,
NULL, err, TAG, "SPI Ethernet MAC address config failed");
}
if (mac_out != NULL) {
*mac_out = mac;
}
if (phy_out != NULL) {
*phy_out = phy;
}
return eth_handle;
err:
if (eth_handle != NULL) {
esp_eth_driver_uninstall(eth_handle);
}
if (mac != NULL) {
mac->del(mac);
}
if (phy != NULL) {
phy->del(phy);
}
return ret;
}
#endif // CONFIG_EXAMPLE_USE_SPI_ETHERNET
esp_err_t example_eth_init(esp_eth_handle_t *eth_handles_out[], uint8_t *eth_cnt_out)
{
esp_err_t ret = ESP_OK;
esp_eth_handle_t *eth_handles = NULL;
uint8_t eth_cnt = 0;
#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET || CONFIG_EXAMPLE_USE_SPI_ETHERNET
ESP_GOTO_ON_FALSE(eth_handles_out != NULL && eth_cnt_out != NULL, ESP_ERR_INVALID_ARG,
err, TAG, "invalid arguments: initialized handles array or number of interfaces");
eth_handles = calloc(SPI_ETHERNETS_NUM + INTERNAL_ETHERNETS_NUM, sizeof(esp_eth_handle_t));
ESP_GOTO_ON_FALSE(eth_handles != NULL, ESP_ERR_NO_MEM, err, TAG, "no memory");
#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
eth_handles[eth_cnt] = eth_init_internal(NULL, NULL);
ESP_GOTO_ON_FALSE(eth_handles[eth_cnt], ESP_FAIL, err, TAG, "internal Ethernet init failed");
eth_cnt++;
#endif //CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
#if CONFIG_EXAMPLE_USE_SPI_ETHERNET
ESP_GOTO_ON_ERROR(spi_bus_init(), err, TAG, "SPI bus init failed");
// Init specific SPI Ethernet module configuration from Kconfig (CS GPIO, Interrupt GPIO, etc.)
spi_eth_module_config_t spi_eth_module_config[CONFIG_EXAMPLE_SPI_ETHERNETS_NUM] = { 0 };
INIT_SPI_ETH_MODULE_CONFIG(spi_eth_module_config, 0);
// The SPI Ethernet module(s) might not have a burned factory MAC address, hence use manually configured address(es).
// In this example, Locally Administered MAC address derived from ESP32x base MAC address is used.
// Note that Locally Administered OUI range should be used only when testing on a LAN under your control!
uint8_t base_mac_addr[ETH_ADDR_LEN];
ESP_GOTO_ON_ERROR(esp_efuse_mac_get_default(base_mac_addr), err, TAG, "get EFUSE MAC failed");
uint8_t local_mac_1[ETH_ADDR_LEN];
esp_derive_local_mac(local_mac_1, base_mac_addr);
spi_eth_module_config[0].mac_addr = local_mac_1;
#if CONFIG_EXAMPLE_SPI_ETHERNETS_NUM > 1
INIT_SPI_ETH_MODULE_CONFIG(spi_eth_module_config, 1);
uint8_t local_mac_2[ETH_ADDR_LEN];
base_mac_addr[ETH_ADDR_LEN - 1] += 1;
esp_derive_local_mac(local_mac_2, base_mac_addr);
spi_eth_module_config[1].mac_addr = local_mac_2;
#endif
#if CONFIG_EXAMPLE_SPI_ETHERNETS_NUM > 2
#error Maximum number of supported SPI Ethernet devices is currently limited to 2 by this example.
#endif
for (int i = 0; i < CONFIG_EXAMPLE_SPI_ETHERNETS_NUM; i++) {
eth_handles[eth_cnt] = eth_init_spi(&spi_eth_module_config[i], NULL, NULL);
ESP_GOTO_ON_FALSE(eth_handles[eth_cnt], ESP_FAIL, err, TAG, "SPI Ethernet init failed");
eth_cnt++;
}
#endif // CONFIG_EXAMPLE_USE_SPI_ETHERNET
#else
ESP_LOGD(TAG, "no Ethernet device selected to init");
#endif // CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET || CONFIG_EXAMPLE_USE_SPI_ETHERNET
*eth_handles_out = eth_handles;
*eth_cnt_out = eth_cnt;
return ret;
#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET || CONFIG_EXAMPLE_USE_SPI_ETHERNET
err:
free(eth_handles);
return ret;
#endif
}
esp_err_t example_eth_deinit(esp_eth_handle_t *eth_handles, uint8_t eth_cnt)
{
ESP_RETURN_ON_FALSE(eth_handles != NULL, ESP_ERR_INVALID_ARG, TAG, "array of Ethernet handles cannot be NULL");
for (int i = 0; i < eth_cnt; i++) {
esp_eth_mac_t *mac = NULL;
esp_eth_phy_t *phy = NULL;
if (eth_handles[i] != NULL) {
esp_eth_get_mac_instance(eth_handles[i], &mac);
esp_eth_get_phy_instance(eth_handles[i], &phy);
ESP_RETURN_ON_ERROR(esp_eth_driver_uninstall(eth_handles[i]), TAG, "Ethernet %p uninstall failed", eth_handles[i]);
}
if (mac != NULL) {
mac->del(mac);
}
if (phy != NULL) {
phy->del(phy);
}
}
#if CONFIG_EXAMPLE_USE_SPI_ETHERNET
spi_bus_free(CONFIG_EXAMPLE_ETH_SPI_HOST);
#if (CONFIG_EXAMPLE_ETH_SPI_INT0_GPIO >= 0) || (CONFIG_EXAMPLE_ETH_SPI_INT1_GPIO > 0)
// We installed the GPIO ISR service so let's uninstall it too.
// BE CAREFUL HERE though since the service might be used by other functionality!
if (gpio_isr_svc_init_by_eth) {
ESP_LOGW(TAG, "uninstalling GPIO ISR service!");
gpio_uninstall_isr_service();
}
#endif
#endif //CONFIG_EXAMPLE_USE_SPI_ETHERNET
free(eth_handles);
return ESP_OK;
}

View File

@@ -1,41 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#pragma once
#include "esp_eth_driver.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize Ethernet driver based on Espressif IoT Development Framework Configuration
*
* @param[out] eth_handles_out array of initialized Ethernet driver handles
* @param[out] eth_cnt_out number of initialized Ethernets
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG when passed invalid pointers
* - ESP_ERR_NO_MEM when there is no memory to allocate for Ethernet driver handles array
* - ESP_FAIL on any other failure
*/
esp_err_t example_eth_init(esp_eth_handle_t *eth_handles_out[], uint8_t *eth_cnt_out);
/**
* @brief De-initialize array of Ethernet drivers
* @note All Ethernet drivers in the array must be stopped prior calling this function.
*
* @param[in] eth_handles array of Ethernet drivers to be de-initialized
* @param[in] eth_cnt number of Ethernets drivers to be de-initialized
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG when passed invalid pointers
*/
esp_err_t example_eth_deinit(esp_eth_handle_t *eth_handles, uint8_t eth_cnt);
#ifdef __cplusplus
}
#endif

View File

@@ -1,3 +1,3 @@
idf_component_register(SRCS "ethernet_example_main.c" idf_component_register(SRCS "ethernet_example_main.c"
PRIV_REQUIRES esp_netif esp_eth ethernet_init PRIV_REQUIRES esp_netif esp_eth
INCLUDE_DIRS ".") INCLUDE_DIRS ".")

View File

@@ -1,9 +1,194 @@
menu "Example Configuration" menu "Example Ethernet Configuration"
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
choice EXAMPLE_ETH_PHY_INTERFACE
prompt "PHY interface"
default EXAMPLE_ETH_PHY_INTERFACE_DEFAULT
help
Select the communication interface between MAC and PHY chip.
config EXAMPLE_ETH_PHY_INTERFACE_DEFAULT
bool "Default EMAC interface configuration"
help
Will use default hardcoded ESP Ethernet MAC driver configuration
config EXAMPLE_ETH_PHY_INTERFACE_RMII
bool "Reduced Media Independent Interface (RMII)"
endchoice
if EXAMPLE_ETH_PHY_INTERFACE_RMII
choice EXAMPLE_ETH_RMII_CLK_MODE
prompt "RMII CLK mode"
default EXAMPLE_ETH_RMII_CLK_INPUT
help
Select external or internal RMII CLK.
config EXAMPLE_ETH_RMII_CLK_INPUT
bool "Input RMII CLK from external"
help
MAC will get RMII CLK from outside.
config EXAMPLE_ETH_RMII_CLK_OUTPUT
bool "Output RMII CLK from internal"
help
Generate RMII CLK by internal PLL.
This clock can be routed to the external PHY device.
!! WARNING !!
ESP32 Errata: If you want the Ethernet to work with WiFi or BT, dont select ESP32
as RMII CLK output as it would result in clock instability! Applicable only to ESP32,
other ESP32 SoCs (like ESP32P4) are not affected.
endchoice
config EXAMPLE_ETH_RMII_CLK_GPIO
int "RMII CLK GPIO"
range ENV_GPIO_RANGE_MIN ENV_GPIO_RANGE_MAX
default 50 if IDF_TARGET_ESP32P4
default 0
help
RMII CLK input or output GPIO. See datasheet for available GPIOs.
config EXAMPLE_ETH_RMII_CLK_EXT_LOOPBACK_EN
depends on !SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK && EXAMPLE_ETH_RMII_CLK_OUTPUT
bool "Enable external RMII CLK loopback input"
default y
help
RMII CLK output signal must be looped back to the EMAC externally on certain chips.
config EXAMPLE_ETH_RMII_CLK_EXT_LOOPBACK_IN_GPIO
depends on EXAMPLE_ETH_RMII_CLK_EXT_LOOPBACK_EN
int "RMII CLK loopback input GPIO"
range ENV_GPIO_RANGE_MIN ENV_GPIO_RANGE_MAX
default 32 if IDF_TARGET_ESP32P4
default 0
help
Set GPIO number used by RMII REF CLK input to loopback internally generated RMII CLK output.
See datasheet for available GPIOs.
if SOC_EMAC_USE_MULTI_IO_MUX
config EXAMPLE_ETH_RMII_TX_EN_GPIO
int "RMII TX_EN GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 49 if IDF_TARGET_ESP32P4
default 0
help
Set the GPIO number used by RMII TX_EN signal.
See datasheet for available GPIOs.
config EXAMPLE_ETH_RMII_TXD0_GPIO
int "RMII TXD0 GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 34 if IDF_TARGET_ESP32P4
default 0
help
Set the GPIO number used by RMII TXD0 signal.
See datasheet for available GPIOs.
config EXAMPLE_ETH_RMII_TXD1_GPIO
int "RMII TXD1 GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 35 if IDF_TARGET_ESP32P4
default 0
help
Set the GPIO number used by RMII TXD1 signal.
See datasheet for available GPIOs.
config EXAMPLE_ETH_RMII_CRS_DV_GPIO
int "RMII CRS_DV GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
default 28 if IDF_TARGET_ESP32P4
default 0
help
Set the GPIO number used by RMII CRS_DV signal.
See datasheet for available GPIOs.
config EXAMPLE_ETH_RMII_RXD0_GPIO
int "RMII RXD0 GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
default 29 if IDF_TARGET_ESP32P4
default 0
help
Set the GPIO number used by RMII RXD0 signal.
See datasheet for available GPIOs.
config EXAMPLE_ETH_RMII_RXD1_GPIO
int "RMII RXD1 GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
default 30 if IDF_TARGET_ESP32P4
default 0
help
Set the GPIO number used by RMII RXD1 signal.
See datasheet for available GPIOs.
endif # SOC_EMAC_USE_MULTI_IO_MUX
endif # EXAMPLE_ETH_PHY_INTERFACE_RMII
config EXAMPLE_ETH_MDC_GPIO
int "SMI MDC GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 23 if IDF_TARGET_ESP32
default 31 if IDF_TARGET_ESP32P4
help
Set the GPIO number used by SMI MDC.
config EXAMPLE_ETH_MDIO_GPIO
int "SMI MDIO GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 18 if IDF_TARGET_ESP32
default 52 if IDF_TARGET_ESP32P4
help
Set the GPIO number used by SMI MDIO.
config EXAMPLE_ETH_PHY_ADDR
int "PHY Address"
range -1 31
default 1
help
Set PHY address according your board schematic.
Set to -1 to driver find the PHY address automatically.
config EXAMPLE_ETH_PHY_RST_GPIO
int "PHY Reset GPIO number"
range -1 ENV_GPIO_OUT_RANGE_MAX
default 5 if IDF_TARGET_ESP32
default 51 if IDF_TARGET_ESP32P4
help
Set the GPIO number used to reset PHY chip.
Set to -1 to disable PHY chip hardware reset.
menuconfig EXAMPLE_ETH_PHY_RST_TIMING_EN
bool "PHY Reset Timing configuration"
default n
help
Default reset timing configuration is set conservatively. If you need faster response and
your chip supports it, enable and configure it. See PHY datasheet "AC Specification" section.
config EXAMPLE_ETH_PHY_RST_ASSERT_TIME_US
int "PHY Reset Assert Time (microseconds)"
depends on EXAMPLE_ETH_PHY_RST_TIMING_EN
range 0 100000
default 10000
help
Time in microseconds to assert the PHY reset signal.
This should be long enough to ensure the PHY chip is properly reset.
config EXAMPLE_ETH_PHY_RST_DELAY_MS
int "PHY Post-Reset Delay (milliseconds)"
depends on EXAMPLE_ETH_PHY_RST_TIMING_EN
range -1 4000
default 10
help
Delay in milliseconds after releasing the PHY reset signal.
This allows the PHY chip to stabilize before communication begins.
When no delay required, set -1.
config EXAMPLE_ETH_DEINIT_AFTER_S config EXAMPLE_ETH_DEINIT_AFTER_S
int "Stop and deinit Ethernet after elapsing number of secs" int "Deinitialize Ethernet after (seconds)"
range -1 300 range -1 3600
default -1 default -1
help help
This option is for demonstration purposes only to demonstrate deinitialization of the Ethernet driver. This option is for demonstration purposes only to demonstrate deinitialization of the Ethernet driver.
Set to -1 to not deinitialize. Set to -1 to not deinitialize.
endmenu endmenu

View File

@@ -1,23 +1,145 @@
/* Ethernet Basic Example /*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
This example code is in the Public Domain (or CC0 licensed, at your option.) *
* SPDX-License-Identifier: Apache-2.0
Unless required by applicable law or agreed to in writing, this *
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/ */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_netif.h" #include "esp_netif.h"
#include "esp_eth.h" #include "esp_eth.h"
#include "esp_event.h" #include "esp_event.h"
#include "esp_log.h" #include "esp_log.h"
#include "ethernet_init.h" #include "esp_check.h"
#include "sdkconfig.h" #include "sdkconfig.h"
static const char *TAG = "eth_example"; static const char *TAG = "eth_basic_example";
/**
* @brief Initialize Ethernet driver with generic PHY (all IEEE 802.3 compliant PHYs)
*
*
* @param[out] eth_handle_out initialized Ethernet driver handle
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG when passed invalid pointer
* - ESP_FAIL on any other failure
*/
static esp_err_t eth_init(esp_eth_handle_t *eth_handle_out)
{
if (eth_handle_out == NULL) {
ESP_LOGE(TAG, "invalid argument: eth_handle_out cannot be NULL");
return ESP_ERR_INVALID_ARG;
}
// Init common MAC and PHY configs to default
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
// Update PHY config based on board specific configuration
phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR;
phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO;
#if CONFIG_EXAMPLE_ETH_PHY_RST_TIMING_EN
phy_config.hw_reset_assert_time_us = CONFIG_EXAMPLE_ETH_PHY_RST_ASSERT_TIME_US;
phy_config.post_hw_reset_delay_ms = CONFIG_EXAMPLE_ETH_PHY_RST_DELAY_MS;
#endif // CONFIG_EXAMPLE_ETH_PHY_RST_TIMING_EN
// Init vendor specific MAC config to default
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
// Update vendor specific MAC config based on board configuration
esp32_emac_config.smi_gpio.mdc_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;
esp32_emac_config.smi_gpio.mdio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;
#if CONFIG_EXAMPLE_ETH_PHY_INTERFACE_RMII
// Configure RMII based on Kconfig when non-default configuration selected
esp32_emac_config.interface = EMAC_DATA_INTERFACE_RMII;
// Configure RMII clock mode and GPIO
#if CONFIG_EXAMPLE_ETH_RMII_CLK_INPUT
esp32_emac_config.clock_config.rmii.clock_mode = EMAC_CLK_EXT_IN;
#else // CONFIG_EXAMPLE_ETH_RMII_CLK_OUTPUT
esp32_emac_config.clock_config.rmii.clock_mode = EMAC_CLK_OUT;
#endif
esp32_emac_config.clock_config.rmii.clock_gpio = CONFIG_EXAMPLE_ETH_RMII_CLK_GPIO;
#if CONFIG_EXAMPLE_ETH_RMII_CLK_EXT_LOOPBACK_EN
esp32_emac_config.clock_config.rmii.clock_loopback_gpio = CONFIG_EXAMPLE_ETH_RMII_CLK_EXT_LOOPBACK_IN_GPIO;
#endif
#if SOC_EMAC_USE_MULTI_IO_MUX
// Configure RMII datapane GPIOs
esp32_emac_config.emac_dataif_gpio.rmii.tx_en_num = CONFIG_EXAMPLE_ETH_RMII_TX_EN_GPIO;
esp32_emac_config.emac_dataif_gpio.rmii.txd0_num = CONFIG_EXAMPLE_ETH_RMII_TXD0_GPIO;
esp32_emac_config.emac_dataif_gpio.rmii.txd1_num = CONFIG_EXAMPLE_ETH_RMII_TXD1_GPIO;
esp32_emac_config.emac_dataif_gpio.rmii.crs_dv_num = CONFIG_EXAMPLE_ETH_RMII_CRS_DV_GPIO;
esp32_emac_config.emac_dataif_gpio.rmii.rxd0_num = CONFIG_EXAMPLE_ETH_RMII_RXD0_GPIO;
esp32_emac_config.emac_dataif_gpio.rmii.rxd1_num = CONFIG_EXAMPLE_ETH_RMII_RXD1_GPIO;
#endif // SOC_EMAC_USE_MULTI_IO_MUX
#endif // CONFIG_EXAMPLE_ETH_PHY_INTERFACE_RMII
// Create new ESP32 Ethernet MAC instance
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
if (mac == NULL) {
ESP_LOGE(TAG, "create MAC instance failed");
return ESP_FAIL;
}
// Create new generic PHY instance
esp_eth_phy_t *phy = esp_eth_phy_new_generic(&phy_config);
if (phy == NULL) {
ESP_LOGE(TAG, "create PHY instance failed");
mac->del(mac);
return ESP_FAIL;
}
// Init Ethernet driver to default and install it
esp_eth_handle_t eth_handle = NULL;
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
if (esp_eth_driver_install(&config, &eth_handle) != ESP_OK) {
ESP_LOGE(TAG, "Ethernet driver install failed");
mac->del(mac);
phy->del(phy);
return ESP_FAIL;
}
*eth_handle_out = eth_handle;
return ESP_OK;
}
#if CONFIG_EXAMPLE_ETH_DEINIT_AFTER_S >= 0
/**
* @brief De-initialize Ethernet driver
* @note Ethernet driver must be stopped prior calling this function.
*
* @param[in] eth_handle Ethernet driver to be de-initialized
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG when passed invalid pointer
*/
static esp_err_t eth_deinit(esp_eth_handle_t eth_handle)
{
ESP_RETURN_ON_FALSE(eth_handle != NULL, ESP_ERR_INVALID_ARG, TAG, "Ethernet handle cannot be NULL");
esp_eth_mac_t *mac = NULL;
esp_eth_phy_t *phy = NULL;
esp_eth_get_mac_instance(eth_handle, &mac);
esp_eth_get_phy_instance(eth_handle, &phy);
ESP_RETURN_ON_ERROR(esp_eth_driver_uninstall(eth_handle), TAG, "Ethernet %p uninstall failed", eth_handle);
if (mac != NULL) {
mac->del(mac);
}
if (phy != NULL) {
phy->del(phy);
}
return ESP_OK;
}
#endif // CONFIG_EXAMPLE_ETH_DEINIT_AFTER_S >= 0
/** Event handler for Ethernet events */ /** Event handler for Ethernet events */
static void eth_event_handler(void *arg, esp_event_base_t event_base, static void eth_event_handler(void *arg, esp_event_base_t event_base,
@@ -66,73 +188,40 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
void app_main(void) void app_main(void)
{ {
// Initialize Ethernet driver // Initialize Ethernet driver
uint8_t eth_port_cnt = 0; esp_eth_handle_t eth_handle;
esp_eth_handle_t *eth_handles; ESP_ERROR_CHECK(eth_init(&eth_handle));
ESP_ERROR_CHECK(example_eth_init(&eth_handles, &eth_port_cnt));
// Initialize TCP/IP network interface aka the esp-netif (should be called only once in application) // Initialize TCP/IP network interface aka the esp-netif (should be called only once in application)
ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_netif_init());
// Create default event loop that running in background // Create default event loop that running in background
ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_t *eth_netifs[eth_port_cnt]; // Create instance of esp-netif for Ethernet
esp_eth_netif_glue_handle_t eth_netif_glues[eth_port_cnt];
// Create instance(s) of esp-netif for Ethernet(s)
if (eth_port_cnt == 1) {
// Use ESP_NETIF_DEFAULT_ETH when just one Ethernet interface is used and you don't need to modify // Use ESP_NETIF_DEFAULT_ETH when just one Ethernet interface is used and you don't need to modify
// default esp-netif configuration parameters. // default esp-netif configuration parameters.
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
eth_netifs[0] = esp_netif_new(&cfg); esp_netif_t *eth_netif = esp_netif_new(&cfg);
eth_netif_glues[0] = esp_eth_new_netif_glue(eth_handles[0]); esp_eth_netif_glue_handle_t eth_netif_glue = esp_eth_new_netif_glue(eth_handle);
// Attach Ethernet driver to TCP/IP stack // Attach Ethernet driver to TCP/IP stack
ESP_ERROR_CHECK(esp_netif_attach(eth_netifs[0], eth_netif_glues[0])); ESP_ERROR_CHECK(esp_netif_attach(eth_netif, eth_netif_glue));
} else {
// Use ESP_NETIF_INHERENT_DEFAULT_ETH when multiple Ethernet interfaces are used and so you need to modify
// esp-netif configuration parameters for each interface (name, priority, etc.).
esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();
esp_netif_config_t cfg_spi = {
.base = &esp_netif_config,
.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH
};
char if_key_str[10];
char if_desc_str[10];
char num_str[3];
for (int i = 0; i < eth_port_cnt; i++) {
itoa(i, num_str, 10);
strcat(strcpy(if_key_str, "ETH_"), num_str);
strcat(strcpy(if_desc_str, "eth"), num_str);
esp_netif_config.if_key = if_key_str;
esp_netif_config.if_desc = if_desc_str;
esp_netif_config.route_prio -= i*5;
eth_netifs[i] = esp_netif_new(&cfg_spi);
eth_netif_glues[i] = esp_eth_new_netif_glue(eth_handles[i]);
// Attach Ethernet driver to TCP/IP stack
ESP_ERROR_CHECK(esp_netif_attach(eth_netifs[i], eth_netif_glues[i]));
}
}
// Register user defined event handlers // Register user defined event handlers
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));
// Start Ethernet driver state machine // Start Ethernet driver state machine
for (int i = 0; i < eth_port_cnt; i++) { ESP_ERROR_CHECK(esp_eth_start(eth_handle));
ESP_ERROR_CHECK(esp_eth_start(eth_handles[i]));
}
#if CONFIG_EXAMPLE_ETH_DEINIT_AFTER_S >= 0 #if CONFIG_EXAMPLE_ETH_DEINIT_AFTER_S >= 0
// For demonstration purposes, wait and then deinit Ethernet network // For demonstration purposes, wait and then deinit Ethernet network
vTaskDelay(pdMS_TO_TICKS(CONFIG_EXAMPLE_ETH_DEINIT_AFTER_S * 1000)); vTaskDelay(pdMS_TO_TICKS(CONFIG_EXAMPLE_ETH_DEINIT_AFTER_S * 1000));
ESP_LOGI(TAG, "stop and deinitialize Ethernet network..."); ESP_LOGI(TAG, "stop and deinitialize Ethernet network...");
// Stop Ethernet driver state machine and destroy netif // Stop Ethernet driver state machine and destroy netif
for (int i = 0; i < eth_port_cnt; i++) { ESP_ERROR_CHECK(esp_eth_stop(eth_handle));
ESP_ERROR_CHECK(esp_eth_stop(eth_handles[i])); ESP_ERROR_CHECK(esp_eth_del_netif_glue(eth_netif_glue));
ESP_ERROR_CHECK(esp_eth_del_netif_glue(eth_netif_glues[i])); esp_netif_destroy(eth_netif);
esp_netif_destroy(eth_netifs[i]);
}
esp_netif_deinit(); esp_netif_deinit();
ESP_ERROR_CHECK(example_eth_deinit(eth_handles, eth_port_cnt)); ESP_ERROR_CHECK(eth_deinit(eth_handle));
ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler)); ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler));
ESP_ERROR_CHECK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler)); ESP_ERROR_CHECK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
ESP_ERROR_CHECK(esp_event_loop_delete_default()); ESP_ERROR_CHECK(esp_event_loop_delete_default());

View File

@@ -5,19 +5,17 @@ import subprocess
import pytest import pytest
from pytest_embedded import Dut from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.parametrize( @pytest.mark.parametrize(
'config', 'config, target',
[ [
pytest.param('default_ip101', marks=[pytest.mark.eth_ip101]), pytest.param('defaults', 'esp32', marks=[pytest.mark.eth_ip101]),
pytest.param('default_generic', marks=[pytest.mark.eth_ip101]), pytest.param('lan8720_esp32', 'esp32', marks=[pytest.mark.eth_lan8720]),
pytest.param('default_dm9051', marks=[pytest.mark.eth_dm9051]), pytest.param('defaults', 'esp32p4', marks=[pytest.mark.eth_ip101]),
], ],
indirect=True, indirect=['target'],
) )
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_esp_eth_basic(dut: Dut) -> None: def test_esp_eth_basic(dut: Dut) -> None:
# wait for ip received # wait for ip received
dut_ip = dut.expect(r'esp_netif_handlers: .+ ip: (\d+\.\d+\.\d+\.\d+),').group(1) dut_ip = dut.expect(r'esp_netif_handlers: .+ ip: (\d+\.\d+\.\d+\.\d+),').group(1)
@@ -25,4 +23,5 @@ def test_esp_eth_basic(dut: Dut) -> None:
param = '-n' if platform.system().lower() == 'windows' else '-c' param = '-n' if platform.system().lower() == 'windows' else '-c'
command = ['ping', param, '1', dut_ip] command = ['ping', param, '1', dut_ip]
output = subprocess.run(command, capture_output=True) output = subprocess.run(command, capture_output=True)
assert 'unreachable' not in str(output.stdout) if 'unreachable' in str(output.stdout):
raise RuntimeError('Host unreachable')

View File

@@ -1,5 +0,0 @@
CONFIG_EXAMPLE_USE_SPI_ETHERNET=y
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=n
CONFIG_EXAMPLE_SPI_ETHERNETS_NUM=1
CONFIG_EXAMPLE_USE_DM9051=y
CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ=20

View File

@@ -1,9 +0,0 @@
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
CONFIG_ETH_ENABLED=y
CONFIG_ETH_USE_ESP32_EMAC=y

View File

@@ -1,9 +0,0 @@
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
CONFIG_ETH_ENABLED=y
CONFIG_ETH_USE_ESP32_EMAC=y

View File

@@ -0,0 +1,2 @@
CONFIG_ETH_ENABLED=y
CONFIG_ETH_USE_ESP32_EMAC=y

View File

@@ -0,0 +1,8 @@
# RMII GPIO Configuration to align with LAN8720 test board
CONFIG_IDF_TARGET="esp32"
CONFIG_EXAMPLE_ETH_PHY_INTERFACE_RMII=y
CONFIG_EXAMPLE_ETH_RMII_CLK_OUTPUT=y
CONFIG_EXAMPLE_ETH_RMII_CLK_GPIO=17
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
CONFIG_EXAMPLE_ETH_PHY_ADDR=0

View File

@@ -0,0 +1,2 @@
CONFIG_ETH_ENABLED=y
CONFIG_ETH_USE_ESP32_EMAC=y

View File

@@ -15,9 +15,12 @@ The cli environment in the example is based on the [console component](https://d
### Hardware Required ### Hardware Required
To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves. To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Espressif supports multiple Ethernet PHYs. The full list of supported PHYs is available at [esp-eth-drivers](https://github.com/espressif/esp-eth-drivers) repository. If your PHY is IEEE 802.3 compliant, you can use `Generic PHY` driver for most use cases.
Besides that, `esp_eth` component can drive third-party Ethernet module which integrates MAC and PHY and provides common communication interface (e.g. SPI, USB, etc). This example will take the **DM9051** as an example, illustrating how to install the Ethernet driver in the same manner. Besides that, `esp_eth` component can drive third-party Ethernet module which integrates MAC and PHY and provides common communication interface (e.g. SPI, USB, etc). The full list of supported SPI Ethernet modules is also available at [esp-eth-drivers](https://github.com/espressif/esp-eth-drivers) repository.
> [!NOTE]
> `Generic 802.3 PHY` basic functionality should always work for PHY compliant with IEEE 802.3. However, some specific features might be limited. A typical example is loopback functionality, where certain PHYs may require setting a specific speed mode to operate correctly. If this is a case, use driver tailored to that specific chip.
#### Pin Assignment #### Pin Assignment

View File

@@ -2,6 +2,6 @@ dependencies:
cmd_system: cmd_system:
path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system
espressif/ethernet_init: espressif/ethernet_init:
version: "0.7.0" version: "*"
espressif/iperf-cmd: espressif/iperf-cmd:
version: "~0.1.1" version: "~0.1.1"

View File

@@ -1,6 +1,6 @@
dependencies: dependencies:
espressif/ethernet_init: espressif/ethernet_init:
version: "0.7.0" version: "*"
esp_eth_time: esp_eth_time:
path: ${IDF_PATH}/examples/ethernet/ptp/components/esp_eth_time path: ${IDF_PATH}/examples/ethernet/ptp/components/esp_eth_time
ptpd: ptpd:

View File

@@ -1,3 +1,3 @@
dependencies: dependencies:
espressif/ethernet_init: espressif/ethernet_init:
version: "0.7.0" version: "*"

View File

@@ -17,13 +17,12 @@ The similarities on MAC layer between Ethernet and Wi-Fi make it easy to forward
### Hardware Required ### Hardware Required
To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves. To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Espressif supports multiple Ethernet PHYs. The full list of supported PHYs is available at [esp-eth-drivers](https://github.com/espressif/esp-eth-drivers) repository. If your PHY is IEEE 802.3 compliant, you can use `Generic PHY` driver for most use cases.
Besides that, `esp_eth` component can drive third-party Ethernet module which integrates MAC and PHY and provides common communication interface (e.g. SPI, USB, etc). This example will take the **DM9051** as an example, illustrating how to install the Ethernet driver in the same manner. Besides that, `esp_eth` component can drive third-party Ethernet module which integrates MAC and PHY and provides common communication interface (e.g. SPI, USB, etc). The full list of supported SPI Ethernet modules is also available at [esp-eth-drivers](https://github.com/espressif/esp-eth-drivers) repository.
#### Pin Assignment > [!NOTE]
> `Generic 802.3 PHY` basic functionality should always work for PHY compliant with IEEE 802.3. However, some specific features might be limited. A typical example is loopback functionality, where certain PHYs may require setting a specific speed mode to operate correctly. If this is a case, use driver tailored to that specific chip.
See common pin assignments for Ethernet examples from [upper level](../README.md#common-pin-assignments).
### Configure the project ### Configure the project

View File

@@ -1,3 +1,3 @@
dependencies: dependencies:
espressif/ethernet_init: espressif/ethernet_init:
version: "0.7.0" version: "*"

View File

@@ -1,4 +1,4 @@
dependencies: dependencies:
pcap: "^1.0.0" pcap: "^1.0.0"
espressif/ethernet_init: espressif/ethernet_init:
version: "0.7.0" version: "*"

View File

@@ -8,6 +8,6 @@ dependencies:
dns_server: dns_server:
path: ${IDF_PATH}/examples/protocols/http_server/captive_portal/components/dns_server path: ${IDF_PATH}/examples/protocols/http_server/captive_portal/components/dns_server
espressif/ethernet_init: espressif/ethernet_init:
version: "0.7.0" version: "*"
espressif/network_provisioning: espressif/network_provisioning:
version: "^1.0.5" version: "^1.0.5"

View File

@@ -1,3 +1,3 @@
dependencies: dependencies:
espressif/ethernet_init: espressif/ethernet_init:
version: "0.7.0" version: "*"

View File

@@ -1,7 +1,7 @@
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -1,7 +1,7 @@
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -1,7 +1,7 @@
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -1,7 +1,7 @@
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -3,7 +3,7 @@ CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -3,7 +3,7 @@ CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -1,7 +1,7 @@
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -3,7 +3,7 @@ CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -3,7 +3,7 @@ CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -3,7 +3,7 @@ CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -5,7 +5,7 @@ CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH="certs"
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -7,7 +7,7 @@ CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -13,7 +13,7 @@ CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -3,7 +3,7 @@ CONFIG_BROKER_URL="FROM_STDIN"
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -2,7 +2,7 @@ CONFIG_BROKER_URI="ws://${EXAMPLE_MQTT_BROKER_WS}/ws"
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -3,7 +3,7 @@ CONFIG_BROKER_CERTIFICATE_OVERRIDE="${EXAMPLE_MQTT_BROKER_CERTIFICATE}"
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -1,7 +1,7 @@
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -7,7 +7,7 @@ CONFIG_EXAMPLE_CONNECT_IPV6=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -7,7 +7,7 @@ CONFIG_EXAMPLE_CONNECT_IPV6=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=31 CONFIG_EXAMPLE_ETH_MDC_GPIO=31
CONFIG_EXAMPLE_ETH_MDIO_GPIO=52 CONFIG_EXAMPLE_ETH_MDIO_GPIO=52
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=51 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=51

View File

@@ -1,3 +1,3 @@
dependencies: dependencies:
espressif/ethernet_init: espressif/ethernet_init:
version: "0.7.0" version: "*"

View File

@@ -6,7 +6,7 @@ CONFIG_EXAMPLE_OTA_RECV_TIMEOUT=3000
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -14,7 +14,7 @@ CONFIG_BOOTLOADER_APP_SECURE_VERSION=1
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -7,7 +7,7 @@ CONFIG_EXAMPLE_ENABLE_OTA_RESUMPTION=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -9,7 +9,7 @@ CONFIG_EXAMPLE_ENABLE_OTA_RESUMPTION=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -10,7 +10,7 @@ CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -6,7 +6,7 @@ CONFIG_EXAMPLE_OTA_RECV_TIMEOUT=3000
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -14,7 +14,7 @@ CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key_ecdsa.pem"
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -16,7 +16,7 @@ CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

View File

@@ -5,7 +5,7 @@ CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23 CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5

Some files were not shown because too many files have changed in this diff Show More