From 877af17cf870614da5f42a557e1c2671930b4bfa Mon Sep 17 00:00:00 2001 From: Abhik Roy Date: Wed, 16 Aug 2023 00:12:14 +1000 Subject: [PATCH] feat: Added api for deinitialization of ethernet. --- ethernet_init/Kconfig.projbuild | 157 ++++--- ethernet_init/LICENSE | 202 ++++++++- ethernet_init/README.md | 31 +- ethernet_init/ethernet_init.c | 412 +++++++++++++----- ethernet_init/ethernet_init.h | 45 +- .../examples/simple-ethernet/CMakeLists.txt | 8 + .../simple-ethernet/main/CMakeLists.txt | 2 + .../simple-ethernet/main/idf_component.yml | 8 + .../simple-ethernet/main/simple-ethernet.c | 101 +++++ ethernet_init/idf_component.yml | 6 +- 10 files changed, 781 insertions(+), 191 deletions(-) create mode 100644 ethernet_init/examples/simple-ethernet/CMakeLists.txt create mode 100644 ethernet_init/examples/simple-ethernet/main/CMakeLists.txt create mode 100644 ethernet_init/examples/simple-ethernet/main/idf_component.yml create mode 100644 ethernet_init/examples/simple-ethernet/main/simple-ethernet.c diff --git a/ethernet_init/Kconfig.projbuild b/ethernet_init/Kconfig.projbuild index 3e9a1b4..1464bd3 100644 --- a/ethernet_init/Kconfig.projbuild +++ b/ethernet_init/Kconfig.projbuild @@ -1,8 +1,8 @@ -menu "Example Ethernet Configuration" +menu "Ethernet Configuration" orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps" - config EXAMPLE_USE_INTERNAL_ETHERNET + config ETHERNET_INTERNAL_SUPPORT depends on SOC_EMAC_SUPPORTED select ETH_USE_ESP32_EMAC default y @@ -10,26 +10,26 @@ menu "Example Ethernet Configuration" help Use internal Ethernet MAC controller. - if EXAMPLE_USE_INTERNAL_ETHERNET - choice EXAMPLE_ETH_PHY_MODEL + if ETHERNET_INTERNAL_SUPPORT + choice ETHERNET_PHY_MODEL prompt "Ethernet PHY Device" - default EXAMPLE_ETH_PHY_IP101 + default ETHERNET_PHY_IP101 help - Select the Ethernet PHY device to use in the example. + Select the Ethernet PHY device to use. - config EXAMPLE_ETH_PHY_IP101 + config ETHERNET_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 + config ETHERNET_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 + config ETHERNET_PHY_LAN87XX bool "LAN87xx" help Below chips are supported: @@ -42,13 +42,13 @@ menu "Example Ethernet Configuration" flexPWR® Technology. Goto https://www.microchip.com for more information about them. - config EXAMPLE_ETH_PHY_DP83848 + config ETHERNET_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 + config ETHERNET_PHY_KSZ80XX bool "KSZ80xx" help With the KSZ80xx series, Microchip offers single-chip 10BASE-T/100BASE-TX @@ -56,23 +56,23 @@ menu "Example Ethernet Configuration" 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 + endchoice # ETHERNET_PHY_MODEL - config EXAMPLE_ETH_MDC_GPIO + config ETHERNET_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 + config ETHERNET_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 + config ETHERNET_PHY_RST_GPIO int "PHY Reset GPIO number" range -1 ENV_GPIO_OUT_RANGE_MAX default 5 @@ -80,23 +80,23 @@ menu "Example Ethernet Configuration" Set the GPIO number used to reset PHY chip. Set to -1 to disable PHY chip hardware reset. - config EXAMPLE_ETH_PHY_ADDR + config ETHERNET_PHY_ADDR int "PHY Address" - range 0 31 + range -1 31 default 1 help Set PHY address according your board schematic. - endif # EXAMPLE_USE_INTERNAL_ETHERNET + endif # ETHERNET_INTERNAL_SUPPORT - config EXAMPLE_USE_SPI_ETHERNET + config ETHERNET_SPI_SUPPORT 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 + if ETHERNET_SPI_SUPPORT + config ETHERNET_SPI_NUMBER int "Number of SPI Ethernet modules to use at a time" range 1 2 default 1 @@ -104,39 +104,39 @@ menu "Example Ethernet Configuration" 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 + choice ETHERNET_TYPE_SPI prompt "Ethernet SPI" - default EXAMPLE_USE_W5500 + default ETHERNET_USE_W5500 help - Select which kind of Ethernet will be used in the example. + Select which kind of spi Ethernet will be used. - config EXAMPLE_USE_DM9051 + config ETHERNET_USE_DM9051 bool "DM9051 Module" select ETH_SPI_ETHERNET_DM9051 help Select external SPI-Ethernet module (DM9051). - config EXAMPLE_USE_KSZ8851SNL + config ETHERNET_USE_KSZ8851SNL bool "KSZ8851SNL Module" select ETH_SPI_ETHERNET_KSZ8851SNL help Select external SPI-Ethernet module (KSZ8851SNL). - config EXAMPLE_USE_W5500 + config ETHERNET_USE_W5500 bool "W5500 Module" select ETH_SPI_ETHERNET_W5500 help Select external SPI-Ethernet module (W5500). endchoice - config EXAMPLE_ETH_SPI_HOST + config ETHERNET_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 + config ETHERNET_SPI_SCLK_GPIO int "SPI SCLK GPIO number" range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX default 14 if IDF_TARGET_ESP32 @@ -146,7 +146,7 @@ menu "Example Ethernet Configuration" help Set the GPIO number used by SPI SCLK. - config EXAMPLE_ETH_SPI_MOSI_GPIO + config ETHERNET_SPI_MOSI_GPIO int "SPI MOSI GPIO number" range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX default 13 if IDF_TARGET_ESP32 @@ -156,7 +156,7 @@ menu "Example Ethernet Configuration" help Set the GPIO number used by SPI MOSI. - config EXAMPLE_ETH_SPI_MISO_GPIO + config ETHERNET_SPI_MISO_GPIO int "SPI MISO GPIO number" range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX default 12 if IDF_TARGET_ESP32 @@ -166,14 +166,14 @@ menu "Example Ethernet Configuration" help Set the GPIO number used by SPI MISO. - config EXAMPLE_ETH_SPI_CLOCK_MHZ + config ETHERNET_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 + config ETHERNET_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 @@ -183,8 +183,44 @@ menu "Example Ethernet Configuration" 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 + config ETHERNET_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 ETHERNET_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 ETHERNET_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 ETHERNET_SPI_AUTOCONFIG_MAC_ADDR0 + bool "Auto-configure MAC address of SPI Ethernet #1" + default y + select ETH_SPI_CONFIG_ENABLE_MAC_ADDR0 + help + Auto-configure mac address for SPI Ethernet + + config ETHERNET_SPI_MAC_ADDR0 + string "MAC address of SPI Ethernet #1" + default "5a:bf:25:e0:41:00" + depends on !ETHERNET_SPI_AUTOCONFIG_MAC_ADDR0 + + config ETHERNET_SPI_CS1_GPIO + depends on ETHERNET_SPI_NUMBER > 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 @@ -196,17 +232,8 @@ menu "Example Ethernet Configuration" 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 + config ETHERNET_SPI_INT1_GPIO + depends on ETHERNET_SPI_NUMBER > 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 @@ -216,16 +243,8 @@ menu "Example Ethernet Configuration" 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 + config ETHERNET_SPI_PHY_RST1_GPIO + depends on ETHERNET_SPI_NUMBER > 1 int "PHY Reset GPIO number of SPI Ethernet Module #2" range -1 ENV_GPIO_OUT_RANGE_MAX default -1 @@ -233,19 +252,25 @@ menu "Example Ethernet Configuration" 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 + config ETHERNET_SPI_PHY_ADDR1 + depends on ETHERNET_SPI_NUMBER > 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 + + config ETHERNET_SPI_AUTOCONFIG_MAC_ADDR1 + depends on ETHERNET_SPI_NUMBER > 1 + bool "Auto-configure MAC address of SPI Ethernet #2" + default y + help + Auto-configure mac address for SPI Ethernet + + config ETHERNET_SPI_MAC_ADDR1 + string "MAC address of SPI Ethernet #2" + default "5a:bf:25:e0:41:01" + depends on (!ETHERNET_SPI_AUTOCONFIG_MAC_ADDR1) && (ETHERNET_SPI_NUMBER > 1) + + endif # ETHERNET_SPI_SUPPORT endmenu diff --git a/ethernet_init/LICENSE b/ethernet_init/LICENSE index 3406da4..f49a4e1 100644 --- a/ethernet_init/LICENSE +++ b/ethernet_init/LICENSE @@ -1 +1,201 @@ -ethernet_init/LICENSE + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/ethernet_init/README.md b/ethernet_init/README.md index 3b94a34..3c18a2b 100644 --- a/ethernet_init/README.md +++ b/ethernet_init/README.md @@ -1,3 +1,32 @@ # Component for Ethernet Initialization -This component initializes Ethernet driver based on Espressif IoT Development Framework Configuration \ No newline at end of file +This component makes it easier to set up and control Ethernet connections in Espressif IoT projects. It hides the lower-level complexities of Ethernet driver initialization and configuration, so developers can focus on building their applications without delving deep into hardware details. +It also allows users to select from various supported Ethernet chips, making development faster. + +Supported devices are: +* IP101 +* RTL8201/SR8201 +* LAN87xx +* DP83848 +* KSZ80xx +* SPI Ethernet: + * DM9051 Module + * KSZ8851SNL Module + * W5500 Module + +## API + +### Steps to use the component in an example code: +1. Add this component to your project using ```idf.py add-dependency``` command. +2. Include ```ethernet_init.h``` +3. Call the following functions as required: + ```c + // Initialize Ethernet driver + ESP_ERROR_CHECK(ethernet_init_all(ð_handles, ð_port_cnt)); + + // Get the device information of the ethernet handle + eth_dev_info_t eth_info = ethernet_init_get_dev_info(eth_handle); + + // Stop and Deinitialize ethernet + ethernet_deinit_all(eth_handles); + ``` diff --git a/ethernet_init/ethernet_init.c b/ethernet_init/ethernet_init.c index 72267cf..1c67b03 100644 --- a/ethernet_init/ethernet_init.c +++ b/ethernet_init/ethernet_init.c @@ -1,10 +1,13 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * - * SPDX-License-Identifier: Unlicense OR CC0-1.0 + * SPDX-License-Identifier: Apache-2.0 */ +#include +#include #include "ethernet_init.h" #include "esp_log.h" +#include "esp_event.h" #include "esp_check.h" #include "esp_mac.h" #include "driver/gpio.h" @@ -12,16 +15,16 @@ #if CONFIG_ETH_USE_SPI_ETHERNET #include "driver/spi_master.h" #endif // CONFIG_ETH_USE_SPI_ETHERNET +#include "ethernet_init.h" -static const char *TAG = "example_eth_init"; -#if CONFIG_EXAMPLE_SPI_ETHERNETS_NUM -#define SPI_ETHERNETS_NUM CONFIG_EXAMPLE_SPI_ETHERNETS_NUM +#if CONFIG_ETHERNET_SPI_NUMBER +#define SPI_ETHERNETS_NUM CONFIG_ETHERNET_SPI_NUMBER #else #define SPI_ETHERNETS_NUM 0 #endif -#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET +#if CONFIG_ETHERNET_INTERNAL_SUPPORT #define INTERNAL_ETHERNETS_NUM 1 #else #define INTERNAL_ETHERNETS_NUM 0 @@ -29,93 +32,169 @@ static const char *TAG = "example_eth_init"; #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; \ + eth_module_config[num].spi_cs_gpio = CONFIG_ETHERNET_SPI_CS ##num## _GPIO; \ + eth_module_config[num].int_gpio = CONFIG_ETHERNET_SPI_INT ##num## _GPIO; \ + eth_module_config[num].phy_reset_gpio = CONFIG_ETHERNET_SPI_PHY_RST ##num## _GPIO; \ + eth_module_config[num].phy_addr = CONFIG_ETHERNET_SPI_PHY_ADDR ##num; \ } while(0) +#if !defined(CONFIG_ETHERNET_INTERNAL_SUPPORT) +#define CONFIG_ETHERNET_INTERNAL_SUPPORT 0 +#endif + +#if !defined(CONFIG_ETHERNET_SPI_NUMBER) +#define CONFIG_ETHERNET_SPI_NUMBER 0 +#endif + 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; +} spi_eth_module_config_t; + +typedef enum { + DEV_STATE_UNINITIALIZED, + DEV_STATE_INITIALIZED, +} dev_state; -#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET +typedef struct { + esp_eth_handle_t eth_handle; + esp_eth_mac_t *mac; + esp_eth_phy_t *phy; + dev_state state; + eth_dev_info_t dev_info; +} eth_device; + +static const char *TAG = "ethernet_init"; +static uint8_t eth_cnt_g = 0; +static eth_device eth_instance_g[CONFIG_ETHERNET_INTERNAL_SUPPORT + CONFIG_ETHERNET_SPI_NUMBER]; + + +void eth_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + uint8_t pin1 = 0, pin2 = 0; + uint8_t mac_addr[6] = {0}; + // we can get the ethernet driver handle from event data + esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data; + eth_dev_info_t dev_info = ethernet_init_get_dev_info(eth_handle); + + if (dev_info.type == ETH_DEV_TYPE_INTERNAL_ETH) { + pin1 = dev_info.pin.eth_internal_mdc; + pin2 = dev_info.pin.eth_internal_mdio; + } else if (dev_info.type == ETH_DEV_TYPE_SPI) { + pin1 = dev_info.pin.eth_spi_cs; + pin2 = dev_info.pin.eth_spi_int; + } + + switch (event_id) { + case ETHERNET_EVENT_CONNECTED: + esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr); + ESP_LOGI(TAG, "Ethernet(%s[%d,%d]) Link Up", dev_info.name, pin1, pin2); + ESP_LOGI(TAG, "Ethernet(%s[%d,%d]) HW Addr %02x:%02x:%02x:%02x:%02x:%02x", dev_info.name, pin1, pin2, + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + break; + case ETHERNET_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "Ethernet(%s[%d,%d]) Link Down", dev_info.name, pin1, pin2); + break; + case ETHERNET_EVENT_START: + ESP_LOGI(TAG, "Ethernet(%s[%d,%d]) Started", dev_info.name, pin1, pin2); + break; + case ETHERNET_EVENT_STOP: + ESP_LOGI(TAG, "Ethernet(%s[%d,%d]) Stopped", dev_info.name, pin1, pin2); + break; + default: + ESP_LOGI(TAG, "Default Event"); + break; + } +} + + +#if CONFIG_ETHERNET_INTERNAL_SUPPORT /** * @brief Internal ESP32 Ethernet initialization * - * @param[out] mac_out optionally returns Ethernet MAC object - * @param[out] phy_out optionally returns Ethernet PHY object + * @param[out] dev_out device information of the ethernet * @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) +static esp_eth_handle_t eth_init_internal(eth_device *dev_out) { esp_eth_handle_t ret = NULL; - // Init common MAC and PHY configs to default + if (dev_out == NULL) { + ESP_LOGE(TAG, "eth_device NULL"); + return ret; + } + + // Init common MAC 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 + esp32_emac_config.smi_mdc_gpio_num = CONFIG_ETHERNET_MDC_GPIO; + esp32_emac_config.smi_mdio_gpio_num = CONFIG_ETHERNET_MDIO_GPIO; + +#if CONFIG_ETHERNET_SPI_SUPPORT // 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 +#endif // CONFIG_ETHERNET_SPI_SUPPORT + // Create new ESP32 Ethernet MAC instance - esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); + dev_out->mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); + + // Init common PHY configs to default + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + + // Update PHY config based on board specific configuration + phy_config.phy_addr = CONFIG_ETHERNET_PHY_ADDR; + phy_config.reset_gpio_num = CONFIG_ETHERNET_PHY_RST_GPIO; + // 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); +#if CONFIG_ETHERNET_PHY_IP101 + dev_out->phy = esp_eth_phy_new_ip101(&phy_config); + sprintf(dev_out->dev_info.name, "IP101"); +#elif CONFIG_ETHERNET_PHY_RTL8201 + dev_out->phy = esp_eth_phy_new_rtl8201(&phy_config); + sprintf(dev_out->dev_info.name, "RTL8201"); +#elif CONFIG_ETHERNET_PHY_LAN87XX + dev_out->phy = esp_eth_phy_new_lan87xx(&phy_config); + sprintf(dev_out->dev_info.name, "LAN87XX"); +#elif CONFIG_ETHERNET_PHY_DP83848 + dev_out->phy = esp_eth_phy_new_dp83848(&phy_config); + sprintf(dev_out->dev_info.name, "DP83848"); +#elif CONFIG_ETHERNET_PHY_KSZ80XX + dev_out->phy = esp_eth_phy_new_ksz80xx(&phy_config); + sprintf(dev_out->dev_info.name, "KSZ80XX"); #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_eth_config_t config = ETH_DEFAULT_CONFIG(dev_out->mac, dev_out->phy); ESP_GOTO_ON_FALSE(esp_eth_driver_install(&config, ð_handle) == ESP_OK, NULL, - err, TAG, "Ethernet driver install failed"); + 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 (dev_out->mac != NULL) { + dev_out->mac->del(dev_out->mac); } - if (phy != NULL) { - phy->del(phy); + if (dev_out->phy != NULL) { + dev_out->phy->del(dev_out->phy); } return ret; } -#endif // CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET +#endif // CONFIG_ETHERNET_INTERNAL_SUPPORT -#if CONFIG_EXAMPLE_USE_SPI_ETHERNET +#if CONFIG_ETHERNET_SPI_SUPPORT /** * @brief SPI bus initialization (to be used by Ethernet SPI modules) * @@ -140,14 +219,14 @@ static esp_err_t spi_bus_init(void) // 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, + .miso_io_num = CONFIG_ETHERNET_SPI_MISO_GPIO, + .mosi_io_num = CONFIG_ETHERNET_SPI_MOSI_GPIO, + .sclk_io_num = CONFIG_ETHERNET_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); + ESP_GOTO_ON_ERROR(spi_bus_initialize(CONFIG_ETHERNET_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO), + err, TAG, "SPI host #%d init failed", CONFIG_ETHERNET_SPI_HOST); err: return ret; @@ -157,16 +236,20 @@ static esp_err_t spi_bus_init(void) * @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 + * @param[out] dev device information of the ethernet * @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) +static esp_eth_handle_t eth_init_spi(spi_eth_module_config_t *spi_eth_module_config, eth_device *dev_out) { esp_eth_handle_t ret = NULL; + if (dev_out == NULL) { + ESP_LOGE(TAG, "eth_device NULL"); + return ret; + } + // 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(); @@ -178,117 +261,212 @@ static esp_eth_handle_t eth_init_spi(spi_eth_module_config_t *spi_eth_module_con // 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, + .clock_speed_hz = CONFIG_ETHERNET_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); + /* Init vendor specific MAC config to default, and create new SPI Ethernet MAC instance + and new PHY instance based on board configuration */ +#if CONFIG_ETHERNET_USE_KSZ8851SNL + eth_ksz8851snl_config_t ksz8851snl_config = ETH_KSZ8851SNL_DEFAULT_CONFIG(CONFIG_ETHERNET_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); + dev->mac = esp_eth_mac_new_ksz8851snl(&ksz8851snl_config, &mac_config); + dev->phy = esp_eth_phy_new_ksz8851snl(&phy_config); + sprintf(dev->dev_info.name, "KSZ8851SNL"); +#elif CONFIG_ETHERNET_USE_DM9051 + eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(CONFIG_ETHERNET_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); + dev->mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config); + dev->phy = esp_eth_phy_new_dm9051(&phy_config); + sprintf(dev->dev_info.name, "DM9051"); +#elif CONFIG_ETHERNET_USE_W5500 + eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(CONFIG_ETHERNET_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 + dev_out->mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config); + dev_out->phy = esp_eth_phy_new_w5500(&phy_config); + sprintf(dev_out->dev_info.name, "W5500"); +#endif //CONFIG_ETHERNET_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_eth_config_t eth_config_spi = ETH_DEFAULT_CONFIG(dev_out->mac, dev_out->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"); + 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 (dev_out->mac != NULL) { + dev_out->mac->del(dev_out->mac); } - if (phy != NULL) { - phy->del(phy); + if (dev_out->phy != NULL) { + dev_out->phy->del(dev_out->phy); } return ret; } -#endif // CONFIG_EXAMPLE_USE_SPI_ETHERNET +#endif // CONFIG_ETHERNET_SPI_SUPPORT + -esp_err_t ethernet_init(esp_eth_handle_t *eth_handles_out[], uint8_t *eth_cnt_out) +esp_err_t ethernet_init_all(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; + static int called = 0; -#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET || CONFIG_EXAMPLE_USE_SPI_ETHERNET + if (called == 0) { + ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL)); + called = 1; + } + +#if CONFIG_ETHERNET_INTERNAL_SUPPORT || CONFIG_ETHERNET_SPI_SUPPORT 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"); + 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_ETHERNET_INTERNAL_SUPPORT + eth_handles[eth_cnt_g] = eth_init_internal(ð_instance_g[eth_cnt_g]); + ESP_GOTO_ON_FALSE(eth_handles[eth_cnt_g], ESP_FAIL, err, TAG, "internal Ethernet init failed"); + eth_instance_g[eth_cnt_g].state = DEV_STATE_INITIALIZED; + eth_instance_g[eth_cnt_g].eth_handle = eth_handles[eth_cnt_g]; + eth_instance_g[eth_cnt_g].dev_info.type = ETH_DEV_TYPE_INTERNAL_ETH; + eth_instance_g[eth_cnt_g].dev_info.pin.eth_internal_mdc = CONFIG_ETHERNET_MDC_GPIO; + eth_instance_g[eth_cnt_g].dev_info.pin.eth_internal_mdio = CONFIG_ETHERNET_MDIO_GPIO; + eth_cnt_g++; +#endif //CONFIG_ETHERNET_INTERNAL_SUPPORT -#if CONFIG_EXAMPLE_USE_SPI_ETHERNET +#if CONFIG_ETHERNET_SPI_SUPPORT 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! + spi_eth_module_config_t spi_eth_module_config[CONFIG_ETHERNET_SPI_NUMBER] = { 0 }; + + /* + The SPI Ethernet module(s) might not have a burned factory MAC address, hence use manually configured address(es). + In this component, a locally administered MAC address derived from ESP32x base MAC address is used or + the MAC address is configured via Kconfig. + Note: The locally administered OUI range should be used only when testing on a LAN under your control! + */ + + uint8_t local_mac_0[ETH_ADDR_LEN]; +#if CONFIG_ETHERNET_SPI_AUTOCONFIG_MAC_ADDR0 || CONFIG_ETHERNET_SPI_AUTOCONFIG_MAC_ADDR1 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"); +#endif + +#if CONFIG_ETHERNET_SPI_AUTOCONFIG_MAC_ADDR0 + esp_derive_local_mac(local_mac_0, base_mac_addr); +#else + sscanf(CONFIG_ETHERNET_SPI_MAC_ADDR0, "%2x:%2x:%2x:%2x:%2x:%2x", (unsigned int *) & (local_mac_0[0]), + (unsigned int *)&local_mac_0[1], + (unsigned int *)&local_mac_0[2], + (unsigned int *)&local_mac_0[3], + (unsigned int *)&local_mac_0[4], + (unsigned int *)&local_mac_0[5]); +#endif + INIT_SPI_ETH_MODULE_CONFIG(spi_eth_module_config, 0); + spi_eth_module_config[0].mac_addr = local_mac_0; + +#if CONFIG_ETHERNET_SPI_NUMBER > 1 uint8_t local_mac_1[ETH_ADDR_LEN]; +#if CONFIG_ETHERNET_SPI_AUTOCONFIG_MAC_ADDR1 + base_mac_addr[ETH_ADDR_LEN - 1] += 1; 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 +#else + sscanf(CONFIG_ETHERNET_SPI_MAC_ADDR1, "%2x:%2x:%2x:%2x:%2x:%2x", (unsigned int *) & (local_mac_1[0]), + (unsigned int *)&local_mac_1[1], + (unsigned int *)&local_mac_1[2], + (unsigned int *)&local_mac_1[3], + (unsigned int *)&local_mac_1[4], + (unsigned int *)&local_mac_1[5]); +#endif 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; + spi_eth_module_config[1].mac_addr = local_mac_1; #endif -#if CONFIG_EXAMPLE_SPI_ETHERNETS_NUM > 2 + +#if CONFIG_ETHERNET_SPI_NUMBER > 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++; + + for (int i = 0; i < CONFIG_ETHERNET_SPI_NUMBER; i++) { + eth_handles[eth_cnt_g] = eth_init_spi(&spi_eth_module_config[i], ð_instance_g[eth_cnt_g]); + ESP_GOTO_ON_FALSE(eth_handles[eth_cnt_g], ESP_FAIL, err, TAG, "SPI Ethernet init failed"); + eth_instance_g[eth_cnt_g].state = DEV_STATE_INITIALIZED; + eth_instance_g[eth_cnt_g].eth_handle = eth_handles[eth_cnt_g]; + eth_instance_g[eth_cnt_g].dev_info.type = ETH_DEV_TYPE_SPI; + eth_instance_g[eth_cnt_g].dev_info.pin.eth_spi_cs = CONFIG_ETHERNET_SPI_CS0_GPIO; + eth_instance_g[eth_cnt_g].dev_info.pin.eth_spi_int = CONFIG_ETHERNET_SPI_INT0_GPIO; + eth_cnt_g++; } -#endif // CONFIG_ETH_USE_SPI_ETHERNET +#endif // CONFIG_ETHERNET_SPI_SUPPORT + #else ESP_LOGD(TAG, "no Ethernet device selected to init"); -#endif // CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET || CONFIG_EXAMPLE_USE_SPI_ETHERNET +#endif // CONFIG_ETHERNET_INTERNAL_SUPPORT || CONFIG_ETHERNET_SPI_SUPPORT *eth_handles_out = eth_handles; - *eth_cnt_out = eth_cnt; + *eth_cnt_out = eth_cnt_g; return ret; -#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET || CONFIG_EXAMPLE_USE_SPI_ETHERNET +#if CONFIG_ETHERNET_INTERNAL_SUPPORT || CONFIG_ETHERNET_SPI_SUPPORT err: - free(eth_handles); + ethernet_deinit_all(eth_handles); return ret; #endif } + + +void ethernet_deinit_all(esp_eth_handle_t *eth_handles) +{ + while (eth_cnt_g) { + eth_cnt_g--; + if ((eth_instance_g[eth_cnt_g].state == DEV_STATE_INITIALIZED) && + (eth_instance_g[eth_cnt_g].eth_handle != NULL)) { + if (esp_eth_driver_uninstall(eth_instance_g[eth_cnt_g].eth_handle) != ESP_OK) { + ESP_LOGE(TAG, "Unable to deinitialize ethernet handle: %d", eth_cnt_g); + } + + if (eth_instance_g[eth_cnt_g].mac != NULL) { + eth_instance_g[eth_cnt_g].mac->del(eth_instance_g[eth_cnt_g].mac); + } + if (eth_instance_g[eth_cnt_g].phy != NULL) { + eth_instance_g[eth_cnt_g].phy->del(eth_instance_g[eth_cnt_g].phy); + } + } + } + +#if CONFIG_ETHERNET_SPI_SUPPORT + spi_bus_free(CONFIG_ETHERNET_SPI_HOST); + gpio_uninstall_isr_service(); +#endif + + free(eth_handles); + if (eth_cnt_g != 0) { + ESP_LOGE(TAG, "Something is very wrong. eth_cnt_g is not zero(%d).", eth_cnt_g); + } +} + + +/** + * @brief Returns the device type of the ethernet handle + * + * @param[out] eth_handles Initialized Ethernet driver handles + * @return + * - eth_dev_info_t device information of the ethernet handle + */ +eth_dev_info_t ethernet_init_get_dev_info(esp_eth_handle_t *eth_handle) +{ + eth_dev_info_t ret = {.type = ETH_DEV_TYPE_UNKNOWN}; + + for (int i = 0; i < eth_cnt_g; i++) { + if (eth_handle == eth_instance_g[i].eth_handle) { + return eth_instance_g[i].dev_info; + } + } + + return ret; +} \ No newline at end of file diff --git a/ethernet_init/ethernet_init.h b/ethernet_init/ethernet_init.h index 7a4f46f..aa41432 100644 --- a/ethernet_init/ethernet_init.h +++ b/ethernet_init/ethernet_init.h @@ -1,7 +1,7 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * - * SPDX-License-Identifier: Unlicense OR CC0-1.0 + * SPDX-License-Identifier: Apache-2.0 */ #pragma once @@ -11,6 +11,29 @@ extern "C" { #endif + +typedef enum { + ETH_DEV_TYPE_UNKNOWN, + ETH_DEV_TYPE_INTERNAL_ETH, + ETH_DEV_TYPE_SPI, +} eth_dev_type_t; + +typedef struct { + char name[12]; + eth_dev_type_t type; + union { + struct { + uint8_t eth_internal_mdc; // MDC gpio of internal ethernet + uint8_t eth_internal_mdio; // MDIO gpio of internal ethernet + }; + struct { + uint8_t eth_spi_cs; // CS gpio of spi ethernet + uint8_t eth_spi_int; // INT gpio of spi ethernet + }; + } pin; +} eth_dev_info_t; + + /** * @brief Initialize Ethernet driver based on Espressif IoT Development Framework Configuration * @@ -22,7 +45,23 @@ extern "C" { * - 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); +esp_err_t ethernet_init_all(esp_eth_handle_t *eth_handles_out[], uint8_t *eth_cnt_out); + + +/** + * @brief Deinitialize Ethernet driver + */ +void ethernet_deinit_all(esp_eth_handle_t *eth_handles); + + +/** + * @brief Returns the device type of the ethernet handle + * + * @param[out] eth_handles Initialized Ethernet driver handles + * @return + * - eth_dev_info_t device information of the ethernet handle + */ +eth_dev_info_t ethernet_init_get_dev_info(esp_eth_handle_t *eth_handle); #ifdef __cplusplus } diff --git a/ethernet_init/examples/simple-ethernet/CMakeLists.txt b/ethernet_init/examples/simple-ethernet/CMakeLists.txt new file mode 100644 index 0000000..e586271 --- /dev/null +++ b/ethernet_init/examples/simple-ethernet/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(simple-ethernet) diff --git a/ethernet_init/examples/simple-ethernet/main/CMakeLists.txt b/ethernet_init/examples/simple-ethernet/main/CMakeLists.txt new file mode 100644 index 0000000..4cbd22b --- /dev/null +++ b/ethernet_init/examples/simple-ethernet/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "simple-ethernet.c" + INCLUDE_DIRS ".") diff --git a/ethernet_init/examples/simple-ethernet/main/idf_component.yml b/ethernet_init/examples/simple-ethernet/main/idf_component.yml new file mode 100644 index 0000000..468e4cc --- /dev/null +++ b/ethernet_init/examples/simple-ethernet/main/idf_component.yml @@ -0,0 +1,8 @@ +dependencies: + idf: + version: '>=5.0' + ethernet_init: + version: '*' + + # For local development use the local copy of the component + override_path: '../../../' \ No newline at end of file diff --git a/ethernet_init/examples/simple-ethernet/main/simple-ethernet.c b/ethernet_init/examples/simple-ethernet/main/simple-ethernet.c new file mode 100644 index 0000000..90b3223 --- /dev/null +++ b/ethernet_init/examples/simple-ethernet/main/simple-ethernet.c @@ -0,0 +1,101 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_netif.h" +#include "esp_eth.h" +#include "esp_event.h" +#include "esp_log.h" +#include "ethernet_init.h" +#include "sdkconfig.h" + +static const char *TAG = "ethernet_basic"; + + +/* Event handler for IP_EVENT_ETH_GOT_IP */ +static void got_ip_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; + const esp_netif_ip_info_t *ip_info = &event->ip_info; + + ESP_LOGI(TAG, "Ethernet Got IP Address"); + ESP_LOGI(TAG, "~~~~~~~~~~~"); + ESP_LOGI(TAG, "IP: " IPSTR, IP2STR(&ip_info->ip)); + ESP_LOGI(TAG, "MASK: " IPSTR, IP2STR(&ip_info->netmask)); + ESP_LOGI(TAG, "GW: " IPSTR, IP2STR(&ip_info->gw)); + ESP_LOGI(TAG, "~~~~~~~~~~~"); +} + +void app_main(void) +{ + uint8_t eth_port_cnt = 0; + esp_eth_handle_t *eth_handles; + char if_key_str[10]; + char if_desc_str[10]; + + // Initialize TCP/IP network interface aka the esp-netif (should be called only once in application) + ESP_ERROR_CHECK(esp_netif_init()); + // Create default event loop that running in background + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // Initialize Ethernet driver + ESP_ERROR_CHECK(ethernet_init_all(ð_handles, ð_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 + // default esp-netif configuration parameters. + esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); + esp_netif_t *eth_netif = esp_netif_new(&cfg); + // Attach Ethernet driver to TCP/IP stack + ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[0]))); + } 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 + }; + + for (int i = 0; i < eth_port_cnt; i++) { + sprintf(if_key_str, "ETH_%d", i); + sprintf(if_desc_str, "eth%d", i); + esp_netif_config.if_key = if_key_str; + esp_netif_config.if_desc = if_desc_str; + esp_netif_config.route_prio -= i * 5; + esp_netif_t *eth_netif = esp_netif_new(&cfg_spi); + + // Attach Ethernet driver to TCP/IP stack + ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[i]))); + } + } + + // Register user defined event handers + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); + + // Start Ethernet driver state machine + for (int i = 0; i < eth_port_cnt; i++) { + ESP_ERROR_CHECK(esp_eth_start(eth_handles[i])); + } + + // Print each device info + for (int i = 0; i < eth_port_cnt; i++) { + eth_dev_info_t info = ethernet_init_get_dev_info(eth_handles[i]); + if (info.type == ETH_DEV_TYPE_INTERNAL_ETH) { + ESP_LOGI(TAG, "Device Name: %s", info.name); + ESP_LOGI(TAG, "Device type: ETH_DEV_TYPE_INTERNAL_ETH(%d)", info.type); + ESP_LOGI(TAG, "Pins: mdc: %d, mdio: %d", info.pin.eth_internal_mdc, info.pin.eth_internal_mdio); + } else if (info.type == ETH_DEV_TYPE_SPI) { + ESP_LOGI(TAG, "Device Name: %s", info.name); + ESP_LOGI(TAG, "Device type: ETH_DEV_TYPE_SPI(%d)", info.type); + ESP_LOGI(TAG, "Pins: cs: %d, intr: %d", info.pin.eth_spi_cs, info.pin.eth_spi_int); + } + } +} diff --git a/ethernet_init/idf_component.yml b/ethernet_init/idf_component.yml index 9a77222..b420525 100644 --- a/ethernet_init/idf_component.yml +++ b/ethernet_init/idf_component.yml @@ -1,6 +1,6 @@ dependencies: idf: - version: '>=4.1' + version: '>=5.0' 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 +url: https://github.com/espressif/esp-eth-drivers/tree/master/ethernet_init +version: 0.0.7