From 51d79003afb52f25fbfd08d26fdc590c759a5b32 Mon Sep 17 00:00:00 2001 From: Abhik Roy Date: Fri, 28 Jul 2023 20:31:51 +1000 Subject: [PATCH] feat: Initialize Ethernet driver based on Espressif IDF Configuration --- ethernet_init/CMakeLists.txt | 3 + ethernet_init/Kconfig.projbuild | 251 +++++++++++++++++++++++++++ ethernet_init/LICENSE | 1 + ethernet_init/README.md | 3 + ethernet_init/ethernet_init.c | 294 ++++++++++++++++++++++++++++++++ ethernet_init/ethernet_init.h | 29 ++++ ethernet_init/idf_component.yml | 6 + 7 files changed, 587 insertions(+) create mode 100644 ethernet_init/CMakeLists.txt create mode 100644 ethernet_init/Kconfig.projbuild create mode 100644 ethernet_init/LICENSE create mode 100644 ethernet_init/README.md create mode 100644 ethernet_init/ethernet_init.c create mode 100644 ethernet_init/ethernet_init.h create mode 100644 ethernet_init/idf_component.yml diff --git a/ethernet_init/CMakeLists.txt b/ethernet_init/CMakeLists.txt new file mode 100644 index 0000000..382893e --- /dev/null +++ b/ethernet_init/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "ethernet_init.c" + PRIV_REQUIRES driver esp_eth + INCLUDE_DIRS ".") diff --git a/ethernet_init/Kconfig.projbuild b/ethernet_init/Kconfig.projbuild new file mode 100644 index 0000000..3e9a1b4 --- /dev/null +++ b/ethernet_init/Kconfig.projbuild @@ -0,0 +1,251 @@ +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_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 Tranceivers (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 + 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 + 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 + 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 0 31 + default 1 + help + Set PHY address according your board schematic. + 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 + default 4 if IDF_TARGET_ESP32H2 + 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 + default 5 if IDF_TARGET_ESP32H2 + 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 + default 0 if IDF_TARGET_ESP32H2 + 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 + default 1 if IDF_TARGET_ESP32H2 + 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 + 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 ENV_GPIO_RANGE_MIN 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 + default 10 if IDF_TARGET_ESP32H2 + help + Set the GPIO number used by the first SPI Ethernet module interrupt line. + + config EXAMPLE_ETH_SPI_INT1_GPIO + depends on EXAMPLE_SPI_ETHERNETS_NUM > 1 + int "Interrupt GPIO number SPI Ethernet module #2" + range ENV_GPIO_RANGE_MIN 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 + default 9 if IDF_TARGET_ESP32H2 + help + Set the GPIO number used by the second SPI Ethernet module interrupt line. + + 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 diff --git a/ethernet_init/LICENSE b/ethernet_init/LICENSE new file mode 100644 index 0000000..3406da4 --- /dev/null +++ b/ethernet_init/LICENSE @@ -0,0 +1 @@ +ethernet_init/LICENSE diff --git a/ethernet_init/README.md b/ethernet_init/README.md new file mode 100644 index 0000000..3b94a34 --- /dev/null +++ b/ethernet_init/README.md @@ -0,0 +1,3 @@ +# Component for Ethernet Initialization + +This component initializes Ethernet driver based on Espressif IoT Development Framework Configuration \ No newline at end of file diff --git a/ethernet_init/ethernet_init.c b/ethernet_init/ethernet_init.c new file mode 100644 index 0000000..72267cf --- /dev/null +++ b/ethernet_init/ethernet_init.c @@ -0,0 +1,294 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 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_ETH_USE_SPI_ETHERNET +#include "driver/spi_master.h" +#endif // CONFIG_ETH_USE_SPI_ETHERNET + +static const char *TAG = "example_eth_init"; + +#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].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; + uint8_t int_gpio; + int8_t phy_reset_gpio; + uint8_t phy_addr; + uint8_t *mac_addr; +}spi_eth_module_config_t; + +#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_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO; + esp32_emac_config.smi_mdio_gpio_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_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, ð_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; + + // Install GPIO ISR handler to be able to service SPI Eth modules interrupts + ret = gpio_install_isr_service(0); + if (ret != ESP_OK) { + 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; + } + } + + // 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; + 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; + 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; + 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(ð_config_spi, ð_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 ethernet_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_ETH_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 +} diff --git a/ethernet_init/ethernet_init.h b/ethernet_init/ethernet_init.h new file mode 100644 index 0000000..7a4f46f --- /dev/null +++ b/ethernet_init/ethernet_init.h @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: 2022 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 ethernet_init(esp_eth_handle_t *eth_handles_out[], uint8_t *eth_cnt_out); + +#ifdef __cplusplus +} +#endif diff --git a/ethernet_init/idf_component.yml b/ethernet_init/idf_component.yml new file mode 100644 index 0000000..9a77222 --- /dev/null +++ b/ethernet_init/idf_component.yml @@ -0,0 +1,6 @@ +dependencies: + idf: + version: '>=4.1' +description: This component initializes Ethernet driver based on Espressif IoT Development Framework Configuration. +url: https://github.com/espressif-abhikroy/esp-eth-drivers/tree/feat/ethernet_init +version: 0.0.1