forked from espressif/esp-idf
feat(esp_eth): added new generic PHY driver
This commit is contained in:
@@ -30,6 +30,7 @@ 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_dp83848.c"
|
"src/phy/esp_eth_phy_dp83848.c"
|
||||||
"src/phy/esp_eth_phy_ip101.c"
|
"src/phy/esp_eth_phy_ip101.c"
|
||||||
"src/phy/esp_eth_phy_ksz80xx.c"
|
"src/phy/esp_eth_phy_ksz80xx.c"
|
||||||
|
@@ -14,6 +14,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ESP_ETH_PHY_ADDR_AUTO (-1)
|
#define ESP_ETH_PHY_ADDR_AUTO (-1)
|
||||||
|
#define ESP_ETH_NO_POST_HW_RESET_DELAY (-1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Auto-negotiation control commands
|
* @brief Auto-negotiation control commands
|
||||||
@@ -277,6 +278,8 @@ typedef struct {
|
|||||||
uint32_t reset_timeout_ms; /*!< Reset timeout value (Unit: ms) */
|
uint32_t reset_timeout_ms; /*!< Reset timeout value (Unit: ms) */
|
||||||
uint32_t autonego_timeout_ms; /*!< Auto-negotiation timeout value (Unit: ms) */
|
uint32_t autonego_timeout_ms; /*!< Auto-negotiation timeout value (Unit: ms) */
|
||||||
int reset_gpio_num; /*!< Reset GPIO number, -1 means no hardware reset */
|
int reset_gpio_num; /*!< Reset GPIO number, -1 means no hardware reset */
|
||||||
|
int32_t hw_reset_assert_time_us; /*!< Time the reset pin is asserted (Unit: us), 0 to use chip specific default */
|
||||||
|
int32_t post_hw_reset_delay_ms; /*!< Time to wait after the HW reset (Unit: ms), 0 to use chip specific default, -1 means no wait */
|
||||||
} eth_phy_config_t;
|
} eth_phy_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -289,8 +292,27 @@ typedef struct {
|
|||||||
.reset_timeout_ms = 100, \
|
.reset_timeout_ms = 100, \
|
||||||
.autonego_timeout_ms = 4000, \
|
.autonego_timeout_ms = 4000, \
|
||||||
.reset_gpio_num = 5, \
|
.reset_gpio_num = 5, \
|
||||||
|
.hw_reset_assert_time_us = 0, \
|
||||||
|
.post_hw_reset_delay_ms = 0 \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 ).
|
||||||
|
* 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,
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @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_generic(const eth_phy_config_t *config);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a PHY instance of IP101
|
* @brief Create a PHY instance of IP101
|
||||||
*
|
*
|
||||||
|
@@ -26,6 +26,8 @@ typedef struct {
|
|||||||
uint32_t autonego_timeout_ms; /*!< Auto-negotiation timeout value (Unit: ms) */
|
uint32_t autonego_timeout_ms; /*!< Auto-negotiation timeout value (Unit: ms) */
|
||||||
eth_link_t link_status; /*!< Current Link status */
|
eth_link_t link_status; /*!< Current Link status */
|
||||||
int reset_gpio_num; /*!< Reset GPIO number, -1 means no hardware reset */
|
int reset_gpio_num; /*!< Reset GPIO number, -1 means no hardware reset */
|
||||||
|
int32_t hw_reset_assert_time_us; /*!< Time the reset pin is asserted (Unit: us) */
|
||||||
|
int32_t post_hw_reset_delay_ms; /*!< Time to wait after the HW reset (Unit: ms) */
|
||||||
} phy_802_3_t;
|
} phy_802_3_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,6 +75,16 @@ esp_err_t esp_eth_phy_802_3_reset(phy_802_3_t *phy_802_3);
|
|||||||
*/
|
*/
|
||||||
esp_err_t esp_eth_phy_802_3_autonego_ctrl(phy_802_3_t *phy_802_3, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat);
|
esp_err_t esp_eth_phy_802_3_autonego_ctrl(phy_802_3_t *phy_802_3, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieve link status and propagate the status to higher layers if the status changed
|
||||||
|
*
|
||||||
|
* @param phy_802_3 IEEE 802.3 PHY object infostructure
|
||||||
|
* @return
|
||||||
|
* - ESP_OK: Ethernet PHY link status retrieved successfully
|
||||||
|
* - ESP_FAIL: Error occurred during reading registry
|
||||||
|
*/
|
||||||
|
esp_err_t esp_eth_phy_802_3_updt_link_dup_spd(phy_802_3_t *phy_802_3);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Power control of Ethernet PHY
|
* @brief Power control of Ethernet PHY
|
||||||
*
|
*
|
||||||
@@ -183,7 +195,7 @@ esp_err_t esp_eth_phy_802_3_deinit(phy_802_3_t *phy_802_3);
|
|||||||
*
|
*
|
||||||
* @param phy_802_3 IEEE 802.3 PHY object infostructure
|
* @param phy_802_3 IEEE 802.3 PHY object infostructure
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: Ethrnet PHY infostructure deleted
|
* - ESP_OK: Ethernet PHY infostructure deleted
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_eth_phy_802_3_del(phy_802_3_t *phy_802_3);
|
esp_err_t esp_eth_phy_802_3_del(phy_802_3_t *phy_802_3);
|
||||||
|
|
||||||
@@ -194,6 +206,7 @@ esp_err_t esp_eth_phy_802_3_del(phy_802_3_t *phy_802_3);
|
|||||||
* @param reset_assert_us Hardware reset pin assertion time
|
* @param reset_assert_us Hardware reset pin assertion time
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: reset Ethernet PHY successfully
|
* - ESP_OK: reset Ethernet PHY successfully
|
||||||
|
* - ESP_ERR_NOT_ALLOWED: reset GPIO not defined
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_eth_phy_802_3_reset_hw(phy_802_3_t *phy_802_3, uint32_t reset_assert_us);
|
esp_err_t esp_eth_phy_802_3_reset_hw(phy_802_3_t *phy_802_3, uint32_t reset_assert_us);
|
||||||
|
|
||||||
|
@@ -16,11 +16,14 @@
|
|||||||
#include "esp_rom_sys.h"
|
#include "esp_rom_sys.h"
|
||||||
#include "esp_eth_phy_802_3.h"
|
#include "esp_eth_phy_802_3.h"
|
||||||
|
|
||||||
// Default reset assertion time is selected to be 100us as it is most commonly used value among PHY chips.
|
// Default reset assertion time is selected to be 100us as it is most commonly used value among ESP-IDF supported PHY chips.
|
||||||
#define PHY_RESET_ASSERTION_TIME_US 100
|
#define PHY_RESET_ASSERTION_TIME_US 100
|
||||||
|
|
||||||
static const char *TAG = "eth_phy_802_3";
|
static const char *TAG = "eth_phy_802_3";
|
||||||
|
|
||||||
|
// TODO: IDF-11362 (should be renamed to esp_eth_phy_802_3_reset_hw with the next major release)
|
||||||
|
static esp_err_t esp_eth_phy_802_3_reset_hw_internal(phy_802_3_t *phy_802_3);
|
||||||
|
|
||||||
static esp_err_t set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
|
static esp_err_t set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
|
||||||
{
|
{
|
||||||
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
|
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
|
||||||
@@ -33,10 +36,10 @@ static esp_err_t reset(esp_eth_phy_t *phy)
|
|||||||
return esp_eth_phy_802_3_reset(phy_802_3);
|
return esp_eth_phy_802_3_reset(phy_802_3);
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t reset_hw_default(esp_eth_phy_t *phy)
|
static esp_err_t reset_hw(esp_eth_phy_t *phy)
|
||||||
{
|
{
|
||||||
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
|
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
|
||||||
return esp_eth_phy_802_3_reset_hw(phy_802_3, PHY_RESET_ASSERTION_TIME_US);
|
return esp_eth_phy_802_3_reset_hw_internal(phy_802_3);
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat)
|
static esp_err_t autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat)
|
||||||
@@ -93,6 +96,14 @@ static esp_err_t set_link(esp_eth_phy_t *phy, eth_link_t link)
|
|||||||
return esp_eth_phy_802_3_set_link(phy_802_3, link);
|
return esp_eth_phy_802_3_set_link(phy_802_3, link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static esp_err_t get_link(esp_eth_phy_t *phy)
|
||||||
|
{
|
||||||
|
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
|
||||||
|
|
||||||
|
/* Update information about link, speed, duplex */
|
||||||
|
return esp_eth_phy_802_3_updt_link_dup_spd(phy_802_3);
|
||||||
|
}
|
||||||
|
|
||||||
static esp_err_t init(esp_eth_phy_t *phy)
|
static esp_err_t init(esp_eth_phy_t *phy)
|
||||||
{
|
{
|
||||||
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
|
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
|
||||||
@@ -143,21 +154,6 @@ err:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief PHY hardware reset with default assert time
|
|
||||||
*
|
|
||||||
* @note Default reset assertion time is selected to be 100us as it is most commonly used value among PHY chips.
|
|
||||||
* If your PHY chip requires different value, redefine the `reset_hw` function in derived PHY specific driver structure.
|
|
||||||
*
|
|
||||||
* @param phy Ethernet PHY instance
|
|
||||||
* @return
|
|
||||||
* - ESP_OK on success
|
|
||||||
*/
|
|
||||||
esp_err_t esp_eth_phy_802_3_reset_hw_default(phy_802_3_t *phy_802_3)
|
|
||||||
{
|
|
||||||
return esp_eth_phy_802_3_reset_hw(phy_802_3, PHY_RESET_ASSERTION_TIME_US);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t esp_eth_phy_802_3_autonego_ctrl(phy_802_3_t *phy_802_3, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat)
|
esp_err_t esp_eth_phy_802_3_autonego_ctrl(phy_802_3_t *phy_802_3, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
@@ -220,6 +216,67 @@ err:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_eth_phy_802_3_updt_link_dup_spd(phy_802_3_t *phy_802_3)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
esp_eth_mediator_t *eth = phy_802_3->eth;
|
||||||
|
uint32_t addr = phy_802_3->addr;
|
||||||
|
eth_speed_t speed = ETH_SPEED_10M;
|
||||||
|
eth_duplex_t duplex = ETH_DUPLEX_HALF;
|
||||||
|
uint32_t peer_pause_ability = false;
|
||||||
|
bmcr_reg_t bmcr;
|
||||||
|
bmsr_reg_t bmsr;
|
||||||
|
anar_reg_t anar;
|
||||||
|
anlpar_reg_t anlpar;
|
||||||
|
|
||||||
|
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 (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");
|
||||||
|
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)), err, TAG, "read ANAR failed");
|
||||||
|
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
|
||||||
|
if (bmcr.en_auto_nego) {
|
||||||
|
if (anar.base100_tx_fd && anlpar.base100_tx_fd) {
|
||||||
|
speed = ETH_SPEED_100M;
|
||||||
|
duplex = ETH_DUPLEX_FULL;
|
||||||
|
} else if (anar.base100_tx && anlpar.base100_tx) {
|
||||||
|
speed = ETH_SPEED_100M;
|
||||||
|
duplex = ETH_DUPLEX_HALF;
|
||||||
|
} else if (anar.base10_t_fd && anlpar.base10_t_fd) {
|
||||||
|
speed = ETH_SPEED_10M;
|
||||||
|
duplex = ETH_DUPLEX_FULL;
|
||||||
|
} else if (anar.base10_t && anlpar.base10_t) {
|
||||||
|
speed = ETH_SPEED_10M;
|
||||||
|
duplex = ETH_DUPLEX_HALF;
|
||||||
|
} else {
|
||||||
|
ESP_GOTO_ON_FALSE(false, ESP_FAIL, err, TAG, "invalid auto-nego speed/duplex advertising");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
speed = bmcr.speed_select ? ETH_SPEED_100M : ETH_SPEED_10M;
|
||||||
|
duplex = bmcr.duplex_mode ? 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");
|
||||||
|
phy_802_3->link_status = link;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t esp_eth_phy_802_3_pwrctl(phy_802_3_t *phy_802_3, bool enable)
|
esp_err_t esp_eth_phy_802_3_pwrctl(phy_802_3_t *phy_802_3, bool enable)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
@@ -392,9 +449,29 @@ esp_err_t esp_eth_phy_802_3_reset_hw(phy_802_3_t *phy_802_3, uint32_t reset_asse
|
|||||||
vTaskDelay(pdMS_TO_TICKS(reset_assert_us/1000));
|
vTaskDelay(pdMS_TO_TICKS(reset_assert_us/1000));
|
||||||
}
|
}
|
||||||
gpio_set_level(phy_802_3->reset_gpio_num, 1);
|
gpio_set_level(phy_802_3->reset_gpio_num, 1);
|
||||||
}
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
return ESP_ERR_NOT_ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Hardware reset with internal timing configuration defined during initialization
|
||||||
|
*
|
||||||
|
* @param phy_802_3 IEEE 802.3 PHY object infostructure
|
||||||
|
* @return
|
||||||
|
* - ESP_OK: reset Ethernet PHY successfully
|
||||||
|
* - ESP_ERR_NOT_ALLOWED: reset GPIO not defined
|
||||||
|
*/
|
||||||
|
static esp_err_t esp_eth_phy_802_3_reset_hw_internal(phy_802_3_t *phy_802_3)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
if ((ret = esp_eth_phy_802_3_reset_hw(phy_802_3, phy_802_3->hw_reset_assert_time_us)) == ESP_OK) {
|
||||||
|
if (phy_802_3->post_hw_reset_delay_ms > 0) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(phy_802_3->post_hw_reset_delay_ms));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t esp_eth_phy_802_3_detect_phy_addr(esp_eth_mediator_t *eth, int *detected_addr)
|
esp_err_t esp_eth_phy_802_3_detect_phy_addr(esp_eth_mediator_t *eth, int *detected_addr)
|
||||||
{
|
{
|
||||||
@@ -601,9 +678,19 @@ esp_err_t esp_eth_phy_802_3_obj_config_init(phy_802_3_t *phy_802_3, const eth_ph
|
|||||||
phy_802_3->reset_timeout_ms = config->reset_timeout_ms;
|
phy_802_3->reset_timeout_ms = config->reset_timeout_ms;
|
||||||
phy_802_3->reset_gpio_num = config->reset_gpio_num;
|
phy_802_3->reset_gpio_num = config->reset_gpio_num;
|
||||||
phy_802_3->autonego_timeout_ms = config->autonego_timeout_ms;
|
phy_802_3->autonego_timeout_ms = config->autonego_timeout_ms;
|
||||||
|
if (config->hw_reset_assert_time_us > 0) {
|
||||||
|
phy_802_3->hw_reset_assert_time_us = config->hw_reset_assert_time_us;
|
||||||
|
} else {
|
||||||
|
phy_802_3->hw_reset_assert_time_us = PHY_RESET_ASSERTION_TIME_US;
|
||||||
|
}
|
||||||
|
if (config->post_hw_reset_delay_ms > 0) {
|
||||||
|
phy_802_3->post_hw_reset_delay_ms = config->post_hw_reset_delay_ms;
|
||||||
|
} else {
|
||||||
|
phy_802_3->post_hw_reset_delay_ms = ESP_ETH_NO_POST_HW_RESET_DELAY;
|
||||||
|
}
|
||||||
|
|
||||||
phy_802_3->parent.reset = reset;
|
phy_802_3->parent.reset = reset;
|
||||||
phy_802_3->parent.reset_hw = reset_hw_default;
|
phy_802_3->parent.reset_hw = reset_hw;
|
||||||
phy_802_3->parent.init = init;
|
phy_802_3->parent.init = init;
|
||||||
phy_802_3->parent.deinit = deinit;
|
phy_802_3->parent.deinit = deinit;
|
||||||
phy_802_3->parent.set_mediator = set_mediator;
|
phy_802_3->parent.set_mediator = set_mediator;
|
||||||
@@ -617,7 +704,7 @@ esp_err_t esp_eth_phy_802_3_obj_config_init(phy_802_3_t *phy_802_3, const eth_ph
|
|||||||
phy_802_3->parent.set_duplex = set_duplex;
|
phy_802_3->parent.set_duplex = set_duplex;
|
||||||
phy_802_3->parent.del = del;
|
phy_802_3->parent.del = del;
|
||||||
phy_802_3->parent.set_link = set_link;
|
phy_802_3->parent.set_link = set_link;
|
||||||
phy_802_3->parent.get_link = NULL;
|
phy_802_3->parent.get_link = get_link;
|
||||||
phy_802_3->parent.custom_ioctl = NULL;
|
phy_802_3->parent.custom_ioctl = NULL;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
37
components/esp_eth/src/phy/esp_eth_phy_generic.c
Normal file
37
components/esp_eth/src/phy/esp_eth_phy_generic.c
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "esp_eth.h"
|
||||||
|
#include "esp_eth_phy_802_3.h"
|
||||||
|
|
||||||
|
static const char *TAG = "eth_phy_generic";
|
||||||
|
|
||||||
|
// Default reset timing is intentionally conservative
|
||||||
|
#define DEFAULT_PHY_GENERIC_RESET_ASSERTION_TIME_US 10000
|
||||||
|
#define DEFAULT_PHY_GENERIC_POST_RESET_DELAY_MS 500
|
||||||
|
|
||||||
|
esp_eth_phy_t *esp_eth_phy_new_generic(const eth_phy_config_t *config)
|
||||||
|
{
|
||||||
|
esp_eth_phy_t *ret = NULL;
|
||||||
|
phy_802_3_t *phy_802_3 = calloc(1, sizeof(phy_802_3_t));
|
||||||
|
eth_phy_config_t phy_802_3_config = *config;
|
||||||
|
// default chip specific configuration if not defined by user
|
||||||
|
if (config->hw_reset_assert_time_us == 0) {
|
||||||
|
phy_802_3_config.hw_reset_assert_time_us = DEFAULT_PHY_GENERIC_RESET_ASSERTION_TIME_US;
|
||||||
|
}
|
||||||
|
if (config->post_hw_reset_delay_ms == 0) {
|
||||||
|
phy_802_3_config.post_hw_reset_delay_ms = DEFAULT_PHY_GENERIC_POST_RESET_DELAY_MS;
|
||||||
|
}
|
||||||
|
ESP_GOTO_ON_FALSE(esp_eth_phy_802_3_obj_config_init(phy_802_3, &phy_802_3_config) == ESP_OK,
|
||||||
|
NULL, err, TAG, "configuration initialization of PHY 802.3 failed");
|
||||||
|
|
||||||
|
return &phy_802_3->parent;
|
||||||
|
err:
|
||||||
|
return ret;
|
||||||
|
}
|
@@ -173,14 +173,6 @@ err:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t ip101_reset_hw(esp_eth_phy_t *phy)
|
|
||||||
{
|
|
||||||
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
|
|
||||||
esp_err_t ret = esp_eth_phy_802_3_reset_hw(phy_802_3, IP101_PHY_RESET_ASSERTION_TIME_US);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(IP101_PHY_POST_RESET_INIT_TIME_MS));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static esp_err_t ip101_init(esp_eth_phy_t *phy)
|
static esp_err_t ip101_init(esp_eth_phy_t *phy)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
@@ -206,13 +198,20 @@ esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config)
|
|||||||
esp_eth_phy_t *ret = NULL;
|
esp_eth_phy_t *ret = NULL;
|
||||||
phy_ip101_t *ip101 = calloc(1, sizeof(phy_ip101_t));
|
phy_ip101_t *ip101 = calloc(1, sizeof(phy_ip101_t));
|
||||||
ESP_GOTO_ON_FALSE(ip101, NULL, err, TAG, "calloc ip101 failed");
|
ESP_GOTO_ON_FALSE(ip101, NULL, err, TAG, "calloc ip101 failed");
|
||||||
ESP_GOTO_ON_FALSE(esp_eth_phy_802_3_obj_config_init(&ip101->phy_802_3, config) == ESP_OK,
|
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");
|
NULL, err, TAG, "configuration initialization of PHY 802.3 failed");
|
||||||
|
|
||||||
// redefine functions which need to be customized for sake of IP101
|
// redefine functions which need to be customized for sake of IP101
|
||||||
ip101->phy_802_3.parent.init = ip101_init;
|
ip101->phy_802_3.parent.init = ip101_init;
|
||||||
ip101->phy_802_3.parent.get_link = ip101_get_link;
|
ip101->phy_802_3.parent.get_link = ip101_get_link;
|
||||||
ip101->phy_802_3.parent.reset_hw = ip101_reset_hw;
|
|
||||||
|
|
||||||
return &ip101->phy_802_3.parent;
|
return &ip101->phy_802_3.parent;
|
||||||
err:
|
err:
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -14,6 +14,9 @@
|
|||||||
|
|
||||||
static const char *TAG = "lan87xx";
|
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***************/
|
/***************List of Supported Models***************/
|
||||||
|
|
||||||
// See Microchip's Application Note AN25.3 summarizing differences among below models
|
// See Microchip's Application Note AN25.3 summarizing differences among below models
|
||||||
@@ -287,12 +290,6 @@ err:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t lan87xx_reset_hw(esp_eth_phy_t *phy)
|
|
||||||
{
|
|
||||||
/* It was observed that assert nRST signal on LAN87xx needs to be a little longer than the minimum specified in datasheet */
|
|
||||||
return esp_eth_phy_802_3_reset_hw(esp_eth_phy_into_phy_802_3(phy), 150);
|
|
||||||
}
|
|
||||||
|
|
||||||
static esp_err_t lan87xx_autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat)
|
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;
|
esp_err_t ret = ESP_OK;
|
||||||
@@ -366,11 +363,18 @@ esp_eth_phy_t *esp_eth_phy_new_lan87xx(const eth_phy_config_t *config)
|
|||||||
esp_eth_phy_t *ret = NULL;
|
esp_eth_phy_t *ret = NULL;
|
||||||
phy_lan87xx_t *lan87xx = calloc(1, sizeof(phy_lan87xx_t));
|
phy_lan87xx_t *lan87xx = calloc(1, sizeof(phy_lan87xx_t));
|
||||||
ESP_GOTO_ON_FALSE(lan87xx, NULL, err, TAG, "calloc lan87xx failed");
|
ESP_GOTO_ON_FALSE(lan87xx, NULL, err, TAG, "calloc lan87xx failed");
|
||||||
ESP_GOTO_ON_FALSE(esp_eth_phy_802_3_obj_config_init(&lan87xx->phy_802_3, config) == ESP_OK,
|
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");
|
NULL, err, TAG, "configuration initialization of PHY 802.3 failed");
|
||||||
|
|
||||||
// redefine functions which need to be customized for sake of LAN87xx
|
// redefine functions which need to be customized for sake of LAN87xx
|
||||||
lan87xx->phy_802_3.parent.reset_hw = lan87xx_reset_hw;
|
|
||||||
lan87xx->phy_802_3.parent.init = lan87xx_init;
|
lan87xx->phy_802_3.parent.init = lan87xx_init;
|
||||||
lan87xx->phy_802_3.parent.get_link = lan87xx_get_link;
|
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.autonego_ctrl = lan87xx_autonego_ctrl;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -149,15 +149,6 @@ err:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t rtl8201_reset_hw(esp_eth_phy_t *phy)
|
|
||||||
{
|
|
||||||
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
|
|
||||||
esp_err_t ret = esp_eth_phy_802_3_reset_hw(phy_802_3, RTL8201_PHY_RESET_ASSERTION_TIME_US);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(RTL8201_PHY_POST_RESET_INIT_TIME_MS));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static esp_err_t rtl8201_init(esp_eth_phy_t *phy)
|
static esp_err_t rtl8201_init(esp_eth_phy_t *phy)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
@@ -183,7 +174,15 @@ esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config)
|
|||||||
esp_eth_phy_t *ret = NULL;
|
esp_eth_phy_t *ret = NULL;
|
||||||
phy_rtl8201_t *rtl8201 = calloc(1, sizeof(phy_rtl8201_t));
|
phy_rtl8201_t *rtl8201 = calloc(1, sizeof(phy_rtl8201_t));
|
||||||
ESP_GOTO_ON_FALSE(rtl8201, NULL, err, TAG, "calloc rtl8201 failed");
|
ESP_GOTO_ON_FALSE(rtl8201, NULL, err, TAG, "calloc rtl8201 failed");
|
||||||
ESP_GOTO_ON_FALSE(esp_eth_phy_802_3_obj_config_init(&rtl8201->phy_802_3, config) == ESP_OK,
|
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");
|
NULL, err, TAG, "configuration initialization of PHY 802.3 failed");
|
||||||
|
|
||||||
// redefine functions which need to be customized for sake of RTL8201
|
// redefine functions which need to be customized for sake of RTL8201
|
||||||
@@ -191,7 +190,6 @@ esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config)
|
|||||||
rtl8201->phy_802_3.parent.get_link = rtl8201_get_link;
|
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.autonego_ctrl = rtl8201_autonego_ctrl;
|
||||||
rtl8201->phy_802_3.parent.loopback = rtl8201_loopback;
|
rtl8201->phy_802_3.parent.loopback = rtl8201_loopback;
|
||||||
rtl8201->phy_802_3.parent.reset_hw = rtl8201_reset_hw;
|
|
||||||
|
|
||||||
return &rtl8201->phy_802_3.parent;
|
return &rtl8201->phy_802_3.parent;
|
||||||
err:
|
err:
|
||||||
|
@@ -269,6 +269,10 @@ Configuration for PHY is described in :cpp:class:`eth_phy_config_t`, including:
|
|||||||
|
|
||||||
* :cpp:member:`eth_phy_config_t::reset_gpio_num`: if your board also connects the PHY reset pin to one of the GPIO, then set it here. Otherwise, set this field to ``-1``.
|
* :cpp:member:`eth_phy_config_t::reset_gpio_num`: if your board also connects the PHY reset pin to one of the GPIO, then set it here. Otherwise, set this field to ``-1``.
|
||||||
|
|
||||||
|
* :cpp:member:`eth_phy_config_t::hw_reset_assert_time_us`: Time the PHY reset pin is asserted in usec. Set this field to ``0`` to use chip specific default timing.
|
||||||
|
|
||||||
|
* :cpp:member:`eth_phy_config_t::post_hw_reset_delay_ms`: Time to wait after the PHY hardware reset is done in msec. Set this field to ``0`` to use chip specific default timing. Set this field to ``-1`` to not wait after the PHY hardware reset.
|
||||||
|
|
||||||
ESP-IDF provides a default configuration for MAC and PHY in macro :c:macro:`ETH_MAC_DEFAULT_CONFIG` and :c:macro:`ETH_PHY_DEFAULT_CONFIG`.
|
ESP-IDF provides a default configuration for MAC and PHY in macro :c:macro:`ETH_MAC_DEFAULT_CONFIG` and :c:macro:`ETH_PHY_DEFAULT_CONFIG`.
|
||||||
|
|
||||||
|
|
||||||
@@ -288,19 +292,23 @@ The Ethernet driver is implemented in an Object-Oriented style. Any operation on
|
|||||||
|
|
||||||
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); // apply default common MAC configuration
|
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); // apply default common MAC configuration
|
||||||
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); // apply default vendor-specific MAC configuration
|
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); // apply default vendor-specific MAC configuration
|
||||||
esp32_emac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO; // alter the GPIO used for MDC signal
|
esp32_emac_config.smi_gpio.mdc_num = CONFIG_EXAMPLE_ETH_MDC_GPIO; // alter the GPIO used for MDC signal
|
||||||
esp32_emac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO; // alter the GPIO used for MDIO signal
|
esp32_emac_config.smi_gpio.mdio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO; // alter the GPIO used for MDIO signa
|
||||||
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
|
||||||
|
|
||||||
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); // apply default PHY configuration
|
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); // apply default PHY configuration
|
||||||
phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR; // alter the PHY address according to your board design
|
phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR; // alter the PHY address according to your board design
|
||||||
phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO; // alter the GPIO used for PHY reset
|
phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO; // alter the GPIO used for PHY reset
|
||||||
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); // create PHY instance
|
esp_eth_phy_t *phy = esp_eth_phy_new_generic(&phy_config); // create generic PHY instance
|
||||||
// ESP-IDF officially supports several different Ethernet PHY chip driver
|
// 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_rtl8201(&phy_config);
|
||||||
// esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&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);
|
// esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
|
||||||
|
|
||||||
|
.. 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.
|
||||||
|
|
||||||
Optional Runtime MAC Clock Configuration
|
Optional Runtime MAC Clock Configuration
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
@@ -557,10 +565,12 @@ Application Examples
|
|||||||
Advanced Topics
|
Advanced Topics
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
.. _custom-phy-driver:
|
||||||
|
|
||||||
Custom PHY Driver
|
Custom PHY Driver
|
||||||
^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
There are multiple PHY manufacturers with wide portfolios of chips available. The ESP-IDF already supports several PHY chips however one can easily get to a point where none of them satisfies the user's actual needs due to price, features, stock availability, etc.
|
There are multiple PHY manufacturers with wide portfolios of chips available. The ESP-IDF supports ``Generic PHY`` and also several specific PHY chips however one can easily get to a point where none of them satisfies the user's actual needs due to price, features, stock availability, etc.
|
||||||
|
|
||||||
Luckily, a management interface between EMAC and PHY is standardized by IEEE 802.3 in Section 22.2.4 Management Functions. It defines provisions of the so-called "MII Management Interface" to control the PHY and gather status from the PHY. A set of management registers is defined to control chip behavior, link properties, auto-negotiation configuration, etc. This basic management functionality is addressed by :component_file:`esp_eth/src/phy/esp_eth_phy_802_3.c` in ESP-IDF and so it makes the creation of a new custom PHY chip driver quite a simple task.
|
Luckily, a management interface between EMAC and PHY is standardized by IEEE 802.3 in Section 22.2.4 Management Functions. It defines provisions of the so-called "MII Management Interface" to control the PHY and gather status from the PHY. A set of management registers is defined to control chip behavior, link properties, auto-negotiation configuration, etc. This basic management functionality is addressed by :component_file:`esp_eth/src/phy/esp_eth_phy_802_3.c` in ESP-IDF and so it makes the creation of a new custom PHY chip driver quite a simple task.
|
||||||
|
|
||||||
|
@@ -183,6 +183,15 @@ menu "Example Connection Configuration"
|
|||||||
help
|
help
|
||||||
Select the Ethernet PHY device to use in the example.
|
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
|
config EXAMPLE_ETH_PHY_IP101
|
||||||
bool "IP101"
|
bool "IP101"
|
||||||
help
|
help
|
||||||
|
@@ -103,7 +103,9 @@ static esp_netif_t *eth_start(void)
|
|||||||
esp32_emac_config.smi_gpio.mdc_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;
|
esp32_emac_config.smi_gpio.mdc_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;
|
||||||
esp32_emac_config.smi_gpio.mdio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;
|
esp32_emac_config.smi_gpio.mdio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;
|
||||||
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_IP101
|
#if CONFIG_EXAMPLE_ETH_PHY_GENERIC
|
||||||
|
s_phy = esp_eth_phy_new_generic(&phy_config);
|
||||||
|
#elif CONFIG_EXAMPLE_ETH_PHY_IP101
|
||||||
s_phy = esp_eth_phy_new_ip101(&phy_config);
|
s_phy = esp_eth_phy_new_ip101(&phy_config);
|
||||||
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
|
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
|
||||||
s_phy = esp_eth_phy_new_rtl8201(&phy_config);
|
s_phy = esp_eth_phy_new_rtl8201(&phy_config);
|
||||||
|
@@ -17,6 +17,15 @@ menu "Example Ethernet Configuration"
|
|||||||
help
|
help
|
||||||
Select the Ethernet PHY device to use in the example.
|
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
|
config EXAMPLE_ETH_PHY_IP101
|
||||||
bool "IP101"
|
bool "IP101"
|
||||||
help
|
help
|
||||||
|
@@ -83,7 +83,9 @@ static esp_eth_handle_t eth_init_internal(esp_eth_mac_t **mac_out, esp_eth_phy_t
|
|||||||
// Create new ESP32 Ethernet MAC instance
|
// Create new ESP32 Ethernet MAC instance
|
||||||
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
|
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
|
||||||
// Create new PHY instance based on board configuration
|
// Create new PHY instance based on board configuration
|
||||||
#if CONFIG_EXAMPLE_ETH_PHY_IP101
|
#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);
|
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
|
||||||
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
|
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
|
||||||
esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config);
|
esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config);
|
||||||
|
@@ -10,6 +10,7 @@ from pytest_embedded import Dut
|
|||||||
@pytest.mark.esp32
|
@pytest.mark.esp32
|
||||||
@pytest.mark.parametrize('config', [
|
@pytest.mark.parametrize('config', [
|
||||||
pytest.param('default_ip101', marks=[pytest.mark.ethernet_router]),
|
pytest.param('default_ip101', marks=[pytest.mark.ethernet_router]),
|
||||||
|
pytest.param('default_generic', marks=[pytest.mark.ethernet_router]),
|
||||||
pytest.param('default_dm9051', marks=[pytest.mark.eth_dm9051]),
|
pytest.param('default_dm9051', marks=[pytest.mark.eth_dm9051]),
|
||||||
], indirect=True)
|
], indirect=True)
|
||||||
def test_esp_eth_basic(
|
def test_esp_eth_basic(
|
||||||
|
11
examples/ethernet/basic/sdkconfig.ci.default_generic
Normal file
11
examples/ethernet/basic/sdkconfig.ci.default_generic
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
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
|
||||||
|
CONFIG_ETH_PHY_INTERFACE_RMII=y
|
||||||
|
CONFIG_ETH_RMII_CLK_INPUT=y
|
Reference in New Issue
Block a user