From 42a462d584d4e6d1f47193d21ef53f3f73e738b3 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Thu, 14 Nov 2019 12:03:14 +0800 Subject: [PATCH 1/6] ethernet: add gpio number into config structure --- components/esp_eth/CMakeLists.txt | 1 - components/esp_eth/Kconfig | 41 +---- components/esp_eth/component.mk | 1 - components/esp_eth/include/esp_eth_mac.h | 7 +- components/esp_eth/include/esp_eth_phy.h | 28 ++- components/esp_eth/linker.lf | 12 -- components/esp_eth/src/dm9051.h | 162 +++++++++++++++++ components/esp_eth/src/esp_eth.c | 2 + components/esp_eth/src/esp_eth_mac_dm9051.c | 168 ++---------------- components/esp_eth/src/esp_eth_mac_esp32.c | 37 ++-- components/esp_eth/src/esp_eth_phy_dm9051.c | 17 ++ components/esp_eth/src/esp_eth_phy_dp83848.c | 16 ++ components/esp_eth/src/esp_eth_phy_ip101.c | 16 ++ components/esp_eth/src/esp_eth_phy_lan8720.c | 16 ++ components/esp_eth/src/esp_eth_phy_rtl8201.c | 16 ++ components/esp_eth/test/test_emac.c | 1 + components/soc/esp32/emac_hal.c | 12 +- components/soc/linker.lf | 7 - .../Kconfig.projbuild | 54 ++++-- .../protocol_examples_common/connect.c | 22 ++- .../ethernet/basic/main/Kconfig.projbuild | 54 ++++-- .../basic/main/ethernet_example_main.c | 22 ++- .../ethernet/eth2ap/main/Kconfig.projbuild | 54 ++++-- .../eth2ap/main/ethernet_example_main.c | 21 ++- .../ethernet/iperf/main/Kconfig.projbuild | 54 ++++-- examples/ethernet/iperf/main/cmd_ethernet.c | 22 ++- 26 files changed, 546 insertions(+), 317 deletions(-) delete mode 100644 components/esp_eth/linker.lf create mode 100644 components/esp_eth/src/dm9051.h diff --git a/components/esp_eth/CMakeLists.txt b/components/esp_eth/CMakeLists.txt index 3829df1885..ed9845218f 100644 --- a/components/esp_eth/CMakeLists.txt +++ b/components/esp_eth/CMakeLists.txt @@ -15,6 +15,5 @@ endif() idf_component_register(SRCS "${esp_eth_srcs}" INCLUDE_DIRS "include" - LDFRAGMENTS "linker.lf" REQUIRES "esp_event" PRIV_REQUIRES "tcpip_adapter" "driver" "log") diff --git a/components/esp_eth/Kconfig b/components/esp_eth/Kconfig index 8e894d397d..2a6fbf2d72 100644 --- a/components/esp_eth/Kconfig +++ b/components/esp_eth/Kconfig @@ -75,36 +75,6 @@ menu "Ethernet" endif endif - config ETH_SMI_MDC_GPIO - int "SMI MDC GPIO number" - default 23 - range 0 33 - help - Set the GPIO number used by SMI MDC. - - config ETH_SMI_MDIO_GPIO - int "SMI MDIO GPIO number" - default 18 - range 0 33 - help - Set the GPIO number used by SMI MDIO. - - config ETH_PHY_USE_RST - bool "Use Reset Pin of PHY Chip" - default y - help - Set this option to true if you want to control PHY chip's reset using a GPIO. - Check the schematic of you board to make sure if it's necessary to use this feature. - - if ETH_PHY_USE_RST - config ETH_PHY_RST_GPIO - int "PHY RST GPIO number" - default 5 - range 0 33 - help - Set the GPIO number used by the PHY chip's RST pin. - endif - config ETH_DMA_BUFFER_SIZE int "Ethernet DMA buffer size (Byte)" range 256 1600 @@ -136,21 +106,12 @@ menu "Ethernet" ESP-IDF can also support some SPI-Ethernet module. if ETH_USE_SPI_ETHERNET - menuconfig ETH_SPI_ETHERNET_DM9051 + config ETH_SPI_ETHERNET_DM9051 bool "Use DM9051" default y help DM9051 is a fast Ethernet controller with an SPI interface. It's also integrated with a 10/100M PHY and MAC. Set true to enable DM9051 driver. - - if ETH_SPI_ETHERNET_DM9051 - config ETH_DM9051_INT_GPIO - int "DM9051 Interrupt GPIO number" - default 4 - range 0 33 - help - Set the GPIO number used by DM9051's Interrupt pin. - endif endif endmenu diff --git a/components/esp_eth/component.mk b/components/esp_eth/component.mk index 3a768fdf8c..a9c95f19af 100644 --- a/components/esp_eth/component.mk +++ b/components/esp_eth/component.mk @@ -3,7 +3,6 @@ # COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_SRCDIRS := src -COMPONENT_ADD_LDFRAGMENTS += linker.lf ifndef CONFIG_ETH_USE_ESP32_EMAC COMPONENT_OBJEXCLUDE += src/esp_eth_mac_esp32.o diff --git a/components/esp_eth/include/esp_eth_mac.h b/components/esp_eth/include/esp_eth_mac.h index c189acb289..7b4cff2fc5 100644 --- a/components/esp_eth/include/esp_eth_mac.h +++ b/components/esp_eth/include/esp_eth_mac.h @@ -21,7 +21,6 @@ extern "C" { #include "esp_eth_com.h" #include "sdkconfig.h" #if CONFIG_ETH_USE_SPI_ETHERNET -#include "driver/gpio.h" #include "driver/spi_master.h" #endif @@ -247,6 +246,8 @@ typedef struct { uint32_t sw_reset_timeout_ms; /*!< Software reset timeout value (Unit: ms) */ uint32_t rx_task_stack_size; /*!< Stack size of the receive task */ uint32_t rx_task_prio; /*!< Priority of the receive task */ + int smi_mdc_gpio_num; /*!< SMI MDC GPIO number */ + int smi_mdio_gpio_num; /*!< SMI MDIO GPIO number */ } eth_mac_config_t; /** @@ -258,6 +259,8 @@ typedef struct { .sw_reset_timeout_ms = 100, \ .rx_task_stack_size = 4096, \ .rx_task_prio = 15, \ + .smi_mdc_gpio_num = 23, \ + .smi_mdio_gpio_num = 18, \ } #if CONFIG_ETH_USE_ESP32_EMAC @@ -280,6 +283,7 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config); */ typedef struct { spi_device_handle_t spi_hdl; /*!< Handle of SPI device driver */ + int int_gpio_num; /*!< Interrupt GPIO number */ } eth_dm9051_config_t; /** @@ -289,6 +293,7 @@ typedef struct { #define ETH_DM9051_DEFAULT_CONFIG(spi_device) \ { \ .spi_hdl = spi_device, \ + .int_gpio_num = 4, \ } /** diff --git a/components/esp_eth/include/esp_eth_phy.h b/components/esp_eth/include/esp_eth_phy.h index b30fdad5dd..2e27350e3a 100644 --- a/components/esp_eth/include/esp_eth_phy.h +++ b/components/esp_eth/include/esp_eth_phy.h @@ -46,7 +46,7 @@ struct esp_eth_phy_s { esp_err_t (*set_mediator)(esp_eth_phy_t *phy, esp_eth_mediator_t *mediator); /** - * @brief Reset Ethernet PHY + * @brief Software Reset Ethernet PHY * * @param[in] phy: Ethernet PHY instance * @@ -57,6 +57,20 @@ struct esp_eth_phy_s { */ esp_err_t (*reset)(esp_eth_phy_t *phy); + /** + * @brief Hardware Reset Ethernet PHY + * + * @note Hardware reset is mostly done by pull down and up PHY's nRST pin + * + * @param[in] phy: Ethernet PHY instance + * + * @return + * - ESP_OK: reset Ethernet PHY successfully + * - ESP_FAIL: reset Ethernet PHY failed because some error occurred + * + */ + esp_err_t (*reset_hw)(esp_eth_phy_t *phy); + /** * @brief Initialize Ethernet PHY * @@ -165,17 +179,19 @@ typedef struct { uint32_t phy_addr; /*!< PHY address */ uint32_t reset_timeout_ms; /*!< Reset 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 */ } eth_phy_config_t; /** * @brief Default configuration for Ethernet PHY object * */ -#define ETH_PHY_DEFAULT_CONFIG() \ - { \ - .phy_addr = 1, \ - .reset_timeout_ms = 100, \ - .autonego_timeout_ms = 4000 \ +#define ETH_PHY_DEFAULT_CONFIG() \ + { \ + .phy_addr = 1, \ + .reset_timeout_ms = 100, \ + .autonego_timeout_ms = 4000, \ + .reset_gpio_num = 5, \ } /** diff --git a/components/esp_eth/linker.lf b/components/esp_eth/linker.lf deleted file mode 100644 index 64969708d9..0000000000 --- a/components/esp_eth/linker.lf +++ /dev/null @@ -1,12 +0,0 @@ -[mapping:esp_eth] -archive: libesp_eth.a -entries: - if ETH_USE_ESP32_EMAC = y: - esp_eth_mac_esp32:emac_hal_tx_complete_cb (noflash_text) - esp_eth_mac_esp32:emac_hal_tx_unavail_cb (noflash_text) - esp_eth_mac_esp32:emac_hal_rx_complete_cb (noflash_text) - esp_eth_mac_esp32:emac_hal_rx_early_cb (noflash_text) - esp_eth_mac_esp32:emac_hal_rx_unavail_cb (noflash_text) - esp_eth_mac_esp32:emac_esp32_isr_handler (noflash_text) - if ETH_SPI_ETHERNET_DM9051 = y: - esp_eth_mac_dm9051:dm9051_isr_handler (noflash_text) diff --git a/components/esp_eth/src/dm9051.h b/components/esp_eth/src/dm9051.h new file mode 100644 index 0000000000..acc855dec3 --- /dev/null +++ b/components/esp_eth/src/dm9051.h @@ -0,0 +1,162 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Registers in DM9051 + * + */ +#define DM9051_NCR (0x00) // Network Control Register +#define DM9051_NSR (0x01) // Network Status Register +#define DM9051_TCR (0x02) // Tx Control Register +#define DM9051_TSR1 (0x03) // Tx Status Register I +#define DM9051_TSR2 (0x04) // Tx Status Register II +#define DM9051_RCR (0x05) // Rx Control Register +#define DM9051_RSR (0x06) // Rx Status Register +#define DM9051_ROCR (0x07) // Receive Overflow Counter Register +#define DM9051_BPTR (0x08) // Back Pressure Threshold Register +#define DM9051_FCTR (0x09) // Flow Control Threshold Register +#define DM9051_FCR (0x0A) // Rx/Tx Flow Control Register +#define DM9051_EPCR (0x0B) // EEPROM & PHY Control Register +#define DM9051_EPAR (0x0C) // EEPROM & PHY Address Register +#define DM9051_EPDRL (0x0D) // EEPROM & PHY Data Register Low +#define DM9051_EPDRH (0x0E) // EEPROM & PHY Data Register High +#define DM9051_WCR (0x0F) // Wake Up Control Register +#define DM9051_PAR (0x10) // Physical Address Register +#define DM9051_MAR (0x16) // Multicast Address Hash Table Register +#define DM9051_GPCR (0x1E) // General Purpose Control Register +#define DM9051_GPR (0x1F) // General Purpose Register +#define DM9051_TRPAL (0x22) // Tx Memory Read Pointer Address Low Byte +#define DM9051_TRPAH (0x23) // Tx Memory Read Pointer Address High Byte +#define DM9051_RWPAL (0x24) // Rx Memory Read Pointer Address Low Byte +#define DM9051_RWPAH (0x25) // Rx Memory Read Pointer Address High Byte +#define DM9051_VIDL (0x28) // Vendor ID Low Byte +#define DM9051_VIDH (0x29) // Vendor ID High Byte +#define DM9051_PIDL (0x2A) // Product ID Low Byte +#define DM9051_PIDH (0x2B) // Product ID High Byte +#define DM9051_CHIPR (0x2C) // CHIP Revision +#define DM9051_TCR2 (0x2D) // Transmit Control Register 2 +#define DM9051_ATCR (0x30) // Auto-Transmit Control Register +#define DM9051_TCSCR (0x31) // Transmit Check Sum Control Register +#define DM9051_RCSCSR (0x32) // Receive Check Sum Control Status Register +#define DM9051_SBCR (0x38) // SPI Bus Control Register +#define DM9051_INTCR (0x39) // INT Pin Control Register +#define DM9051_PPCSR (0x3D) // Pause Packet Control Status Register +#define DM9051_EEE_IN (0x3E) // IEEE 802.3az Enter Counter Register +#define DM9051_EEE_OUT (0x3F) // IEEE 802.3az Leave Counter Register +#define DM9051_ALNCR (0x4A) // SPI Byte Align Error Counter Register +#define DM9051_RLENCR (0x52) // Rx Packet Length Control Register +#define DM9051_BCASTCR (0x53) // RX Broadcast Control Register +#define DM9051_INTCKCR (0x54) // INT Pin Clock Output Control Register +#define DM9051_MPTRCR (0x55) // Memory Pointer Control Register +#define DM9051_MLEDCR (0x57) // More LED Control Register +#define DM9051_MEMSCR (0x59) // Memory Control Register +#define DM9051_TMEMR (0x5A) // Transmit Memory Size Register +#define DM9051_MBSR (0x5D) // Memory BIST Status Register +#define DM9051_MRCMDX (0x70) // Memory Data Pre-Fetch Read Command Without Address Increment Register +#define DM9051_MRCMDX1 (0x71) // Memory Read Command Without Pre-Fetch and Without Address Increment Register +#define DM9051_MRCMD (0x72) // Memory Data Read Command With Address Increment Register +#define DM9051_SDR_DLY (0x73) // SPI Data Read Delay Counter Register +#define DM9051_MRRL (0x74) // Memory Data Read Address Register Low Byte +#define DM9051_MRRH (0x75) // Memory Data Read Address Register High Byte +#define DM9051_MWCMDX (0x76) // Memory Data Write Command Without Address Increment Register +#define DM9051_MWCMD (0x78) // Memory Data Write Command With Address Increment Register +#define DM9051_MWRL (0x7A) // Memory Data Write Address Register Low Byte +#define DM9051_MWRH (0x7B) // Memory Data Write Address Register High Byte +#define DM9051_TXPLL (0x7C) // TX Packet Length Low Byte Register +#define DM9051_TXPLH (0x7D) // TX Packet Length High Byte Register +#define DM9051_ISR (0x7E) // Interrupt Status Register +#define DM9051_IMR (0x7F) // Interrupt Mask Register + +/** + * @brief status and flag of DM9051 specific registers + * + */ +#define DM9051_SPI_RD (0) // Burst Read Command +#define DM9051_SPI_WR (1) // Burst Write Command + +#define NCR_WAKEEN (1 << 6) // Enable Wakeup Function +#define NCR_FDX (1 << 3) // Duplex Mode of the Internal PHY +#define NCR_RST (1 << 0) // Software Reset and Auto-Clear after 10us + +#define NSR_SPEED (1 << 7) // Speed of Internal PHY +#define NSR_LINKST (1 << 6) // Link Status of Internal PHY +#define NSR_WAKEST (1 << 5) // Wakeup Event Status +#define NSR_TX2END (1 << 3) // TX Packet Index II Complete Status +#define NSR_TX1END (1 << 2) // TX Packet Index I Complete Status +#define NSR_RXOV (1 << 1) // RX Memory Overflow Status +#define NSR_RXRDY (1 << 0) // RX Packet Ready + +#define TCR_TXREQ (1 << 0) // TX Request. Auto-Clear after Sending Completely + +#define RCR_WTDIS (1 << 6) // Watchdog Timer Disable +#define RCR_DIS_LONG (1 << 5) // Discard Long Packet +#define RCR_DIS_CRC (1 << 4) // Discard CRC Error Packet +#define RCR_ALL (1 << 3) // Receive All Multicast +#define RCR_RUNT (1 << 2) // Receive Runt Packet +#define RCR_PRMSC (1 << 1) // Promiscuous Mode +#define RCR_RXEN (1 << 0) // RX Enable + +#define RSR_RF (1 << 7) // Runt Frame +#define RSR_MF (1 << 6) // Multicast Frame +#define RSR_LCS (1 << 5) // Late Collision Seen +#define RSR_RWTO (1 << 4) // Receive Watchdog Time-Out +#define RSR_PLE (1 << 3) // Physical Layer Error +#define RSR_AE (1 << 2) // Alignment Error +#define RSR_CE (1 << 1) // CRC Error +#define RSR_FOE (1 << 0) // RX Memory Overflow Error + +#define FCR_FLOW_ENABLE (0x39) // Enable Flow Control + +#define EPCR_REEP (1 << 5) // Reload EEPROM +#define EPCR_WEP (1 << 4) // Write EEPROM Enable +#define EPCR_EPOS (1 << 3) // EEPROM or PHY Operation Select +#define EPCR_ERPRR (1 << 2) // EEPROM Read or PHY Register Read Command +#define EPCR_ERPRW (1 << 1) // EEPROM Write or PHY Register Write Command +#define EPCR_ERRE (1 << 0) // EEPROM Access Status or PHY Access Status + +#define TCR2_RLCP (1 << 6) // Retry Late Collision Packet + +#define ATCR_AUTO_TX (1 << 7) // Auto-Transmit Control + +#define TCSCR_UDPCSE (1 << 2) // UDP CheckSum Generation +#define TCSCR_TCPCSE (1 << 1) // TCP CheckSum Generation +#define TCSCR_IPCSE (1 << 0) // IPv4 CheckSum Generation + +#define MPTRCR_RST_TX (1 << 1) // Reset TX Memory Pointer +#define MPTRCR_RST_RX (1 << 0) // Reset RX Memory Pointer + +#define ISR_LNKCHGS (1 << 5) // Link Status Change +#define ISR_ROO (1 << 3) // Receive Overflow Counter Overflow +#define ISR_ROS (1 << 2) // Receive Overflow +#define ISR_PT (1 << 1) // Packet Transmitted +#define ISR_PR (1 << 0) // Packet Received +#define ISR_CLR_STATUS (ISR_LNKCHGS | ISR_ROO | ISR_ROS | ISR_PT | ISR_PR) + +#define IMR_PAR (1 << 7) // Pointer Auto-Return Mode +#define IMR_LNKCHGI (1 << 5) // Enable Link Status Change Interrupt +#define IMR_ROOI (1 << 3) // Enable Receive Overflow Counter Overflow Interrupt +#define IMR_ROI (1 << 2) // Enable Receive Overflow Interrupt +#define IMR_PTI (1 << 1) // Enable Packet Transmitted Interrupt +#define IMR_PRI (1 << 0) // Enable Packet Received Interrupt +#define IMR_ALL (IMR_PAR | IMR_LNKCHGI | IMR_ROOI | IMR_ROI | IMR_PTI | IMR_PRI) + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_eth/src/esp_eth.c b/components/esp_eth/src/esp_eth.c index adef9096e3..ea813687d4 100644 --- a/components/esp_eth/src/esp_eth.c +++ b/components/esp_eth/src/esp_eth.c @@ -176,6 +176,8 @@ esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_ eth_driver->mediator.phy_reg_write = eth_phy_reg_write; eth_driver->mediator.stack_input = eth_stack_input; eth_driver->mediator.on_state_changed = eth_on_state_changed; + /* some PHY can't output RMII clock if in reset state, so hardware reset PHY chip firstly */ + phy->reset_hw(phy); ETH_CHECK(mac->set_mediator(mac, ð_driver->mediator) == ESP_OK, "set mediator for mac failed", err_mediator, ESP_FAIL); ETH_CHECK(phy->set_mediator(phy, ð_driver->mediator) == ESP_OK, "set mediator for phy failed", err_mediator, ESP_FAIL); ETH_CHECK(mac->init(mac) == ESP_OK, "init mac failed", err_init_mac, ESP_FAIL); diff --git a/components/esp_eth/src/esp_eth_mac_dm9051.c b/components/esp_eth/src/esp_eth_mac_dm9051.c index c87f3e9ca5..1e7bb99c34 100644 --- a/components/esp_eth/src/esp_eth_mac_dm9051.c +++ b/components/esp_eth/src/esp_eth_mac_dm9051.c @@ -16,6 +16,7 @@ #include #include "driver/gpio.h" #include "driver/spi_master.h" +#include "esp_attr.h" #include "esp_log.h" #include "esp_eth.h" #include "esp_system.h" @@ -24,6 +25,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" +#include "dm9051.h" #include "sdkconfig.h" static const char *TAG = "emac_dm9051"; @@ -42,145 +44,6 @@ static const char *TAG = "emac_dm9051"; #define DM9051_SPI_LOCK_TIMEOUT_MS (50) #define DM9051_PHY_OPERATION_TIMEOUT_US (1000) -/** - * @brief Registers in DM9051 - * - */ -#define DM9051_NCR (0x00) // Network Control Register -#define DM9051_NSR (0x01) // Network Status Register -#define DM9051_TCR (0x02) // Tx Control Register -#define DM9051_TSR1 (0x03) // Tx Status Register I -#define DM9051_TSR2 (0x04) // Tx Status Register II -#define DM9051_RCR (0x05) // Rx Control Register -#define DM9051_RSR (0x06) // Rx Status Register -#define DM9051_ROCR (0x07) // Receive Overflow Counter Register -#define DM9051_BPTR (0x08) // Back Pressure Threshold Register -#define DM9051_FCTR (0x09) // Flow Control Threshold Register -#define DM9051_FCR (0x0A) // Rx/Tx Flow Control Register -#define DM9051_EPCR (0x0B) // EEPROM & PHY Control Register -#define DM9051_EPAR (0x0C) // EEPROM & PHY Address Register -#define DM9051_EPDRL (0x0D) // EEPROM & PHY Data Register Low -#define DM9051_EPDRH (0x0E) // EEPROM & PHY Data Register High -#define DM9051_WCR (0x0F) // Wake Up Control Register -#define DM9051_PAR (0x10) // Physical Address Register -#define DM9051_MAR (0x16) // Multicast Address Hash Table Register -#define DM9051_GPCR (0x1E) // General Purpose Control Register -#define DM9051_GPR (0x1F) // General Purpose Register -#define DM9051_TRPAL (0x22) // Tx Memory Read Pointer Address Low Byte -#define DM9051_TRPAH (0x23) // Tx Memory Read Pointer Address High Byte -#define DM9051_RWPAL (0x24) // Rx Memory Read Pointer Address Low Byte -#define DM9051_RWPAH (0x25) // Rx Memory Read Pointer Address High Byte -#define DM9051_VIDL (0x28) // Vendor ID Low Byte -#define DM9051_VIDH (0x29) // Vendor ID High Byte -#define DM9051_PIDL (0x2A) // Product ID Low Byte -#define DM9051_PIDH (0x2B) // Product ID High Byte -#define DM9051_CHIPR (0x2C) // CHIP Revision -#define DM9051_TCR2 (0x2D) // Transmit Control Register 2 -#define DM9051_ATCR (0x30) // Auto-Transmit Control Register -#define DM9051_TCSCR (0x31) // Transmit Check Sum Control Register -#define DM9051_RCSCSR (0x32) // Receive Check Sum Control Status Register -#define DM9051_SBCR (0x38) // SPI Bus Control Register -#define DM9051_INTCR (0x39) // INT Pin Control Register -#define DM9051_PPCSR (0x3D) // Pause Packet Control Status Register -#define DM9051_EEE_IN (0x3E) // IEEE 802.3az Enter Counter Register -#define DM9051_EEE_OUT (0x3F) // IEEE 802.3az Leave Counter Register -#define DM9051_ALNCR (0x4A) // SPI Byte Align Error Counter Register -#define DM9051_RLENCR (0x52) // Rx Packet Length Control Register -#define DM9051_BCASTCR (0x53) // RX Broadcast Control Register -#define DM9051_INTCKCR (0x54) // INT Pin Clock Output Control Register -#define DM9051_MPTRCR (0x55) // Memory Pointer Control Register -#define DM9051_MLEDCR (0x57) // More LED Control Register -#define DM9051_MEMSCR (0x59) // Memory Control Register -#define DM9051_TMEMR (0x5A) // Transmit Memory Size Register -#define DM9051_MBSR (0x5D) // Memory BIST Status Register -#define DM9051_MRCMDX (0x70) // Memory Data Pre-Fetch Read Command Without Address Increment Register -#define DM9051_MRCMDX1 (0x71) // Memory Read Command Without Pre-Fetch and Without Address Increment Register -#define DM9051_MRCMD (0x72) // Memory Data Read Command With Address Increment Register -#define DM9051_SDR_DLY (0x73) // SPI Data Read Delay Counter Register -#define DM9051_MRRL (0x74) // Memory Data Read Address Register Low Byte -#define DM9051_MRRH (0x75) // Memory Data Read Address Register High Byte -#define DM9051_MWCMDX (0x76) // Memory Data Write Command Without Address Increment Register -#define DM9051_MWCMD (0x78) // Memory Data Write Command With Address Increment Register -#define DM9051_MWRL (0x7A) // Memory Data Write Address Register Low Byte -#define DM9051_MWRH (0x7B) // Memory Data Write Address Register High Byte -#define DM9051_TXPLL (0x7C) // TX Packet Length Low Byte Register -#define DM9051_TXPLH (0x7D) // TX Packet Length High Byte Register -#define DM9051_ISR (0x7E) // Interrupt Status Register -#define DM9051_IMR (0x7F) // Interrupt Mask Register - -/** - * @brief status and flag of DM9051 specific registers - * - */ -#define DM9051_SPI_RD (0) // Burst Read Command -#define DM9051_SPI_WR (1) // Burst Write Command - -#define NCR_WAKEEN (1 << 6) // Enable Wakeup Function -#define NCR_FDX (1 << 3) // Duplex Mode of the Internal PHY -#define NCR_RST (1 << 0) // Software Reset and Auto-Clear after 10us - -#define NSR_SPEED (1 << 7) // Speed of Internal PHY -#define NSR_LINKST (1 << 6) // Link Status of Internal PHY -#define NSR_WAKEST (1 << 5) // Wakeup Event Status -#define NSR_TX2END (1 << 3) // TX Packet Index II Complete Status -#define NSR_TX1END (1 << 2) // TX Packet Index I Complete Status -#define NSR_RXOV (1 << 1) // RX Memory Overflow Status -#define NSR_RXRDY (1 << 0) // RX Packet Ready - -#define TCR_TXREQ (1 << 0) // TX Request. Auto-Clear after Sending Completely - -#define RCR_WTDIS (1 << 6) // Watchdog Timer Disable -#define RCR_DIS_LONG (1 << 5) // Discard Long Packet -#define RCR_DIS_CRC (1 << 4) // Discard CRC Error Packet -#define RCR_ALL (1 << 3) // Receive All Multicast -#define RCR_RUNT (1 << 2) // Receive Runt Packet -#define RCR_PRMSC (1 << 1) // Promiscuous Mode -#define RCR_RXEN (1 << 0) // RX Enable - -#define RSR_RF (1 << 7) // Runt Frame -#define RSR_MF (1 << 6) // Multicast Frame -#define RSR_LCS (1 << 5) // Late Collision Seen -#define RSR_RWTO (1 << 4) // Receive Watchdog Time-Out -#define RSR_PLE (1 << 3) // Physical Layer Error -#define RSR_AE (1 << 2) // Alignment Error -#define RSR_CE (1 << 1) // CRC Error -#define RSR_FOE (1 << 0) // RX Memory Overflow Error - -#define FCR_FLOW_ENABLE (0x39) // Enable Flow Control - -#define EPCR_REEP (1 << 5) // Reload EEPROM -#define EPCR_WEP (1 << 4) // Write EEPROM Enable -#define EPCR_EPOS (1 << 3) // EEPROM or PHY Operation Select -#define EPCR_ERPRR (1 << 2) // EEPROM Read or PHY Register Read Command -#define EPCR_ERPRW (1 << 1) // EEPROM Write or PHY Register Write Command -#define EPCR_ERRE (1 << 0) // EEPROM Access Status or PHY Access Status - -#define TCR2_RLCP (1 << 6) // Retry Late Collision Packet - -#define ATCR_AUTO_TX (1 << 7) // Auto-Transmit Control - -#define TCSCR_UDPCSE (1 << 2) // UDP CheckSum Generation -#define TCSCR_TCPCSE (1 << 1) // TCP CheckSum Generation -#define TCSCR_IPCSE (1 << 0) // IPv4 CheckSum Generation - -#define MPTRCR_RST_TX (1 << 1) // Reset TX Memory Pointer -#define MPTRCR_RST_RX (1 << 0) // Reset RX Memory Pointer - -#define ISR_LNKCHGS (1 << 5) // Link Status Change -#define ISR_ROO (1 << 3) // Receive Overflow Counter Overflow -#define ISR_ROS (1 << 2) // Receive Overflow -#define ISR_PT (1 << 1) // Packet Transmitted -#define ISR_PR (1 << 0) // Packet Received -#define ISR_CLR_STATUS (ISR_LNKCHGS | ISR_ROO | ISR_ROS | ISR_PT | ISR_PR) - -#define IMR_PAR (1 << 7) // Pointer Auto-Return Mode -#define IMR_LNKCHGI (1 << 5) // Enable Link Status Change Interrupt -#define IMR_ROOI (1 << 3) // Enable Receive Overflow Counter Overflow Interrupt -#define IMR_ROI (1 << 2) // Enable Receive Overflow Interrupt -#define IMR_PTI (1 << 1) // Enable Packet Transmitted Interrupt -#define IMR_PRI (1 << 0) // Enable Packet Received Interrupt -#define IMR_ALL (IMR_PAR | IMR_LNKCHGI | IMR_ROOI | IMR_ROI | IMR_PTI | IMR_PRI) - typedef struct { uint8_t flag; uint8_t status; @@ -195,6 +58,7 @@ typedef struct { SemaphoreHandle_t spi_lock; TaskHandle_t rx_task_hdl; uint32_t sw_reset_timeout_ms; + int int_gpio_num; uint8_t addr[6]; bool packets_remain; } emac_dm9051_t; @@ -483,7 +347,7 @@ err: return ret; } -static void dm9051_isr_handler(void *arg) +IRAM_ATTR static void dm9051_isr_handler(void *arg) { emac_dm9051_t *emac = (emac_dm9051_t *)arg; BaseType_t high_task_wakeup = pdFALSE; @@ -769,13 +633,12 @@ static esp_err_t emac_dm9051_init(esp_eth_mac_t *mac) esp_err_t ret = ESP_OK; emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); esp_eth_mediator_t *eth = emac->eth; - /* init gpio used by spi-ethernet interrupt */ - gpio_pad_select_gpio(CONFIG_ETH_DM9051_INT_GPIO); - gpio_set_direction(CONFIG_ETH_DM9051_INT_GPIO, GPIO_MODE_INPUT); - gpio_set_pull_mode(CONFIG_ETH_DM9051_INT_GPIO, GPIO_PULLDOWN_ONLY); - gpio_set_intr_type(CONFIG_ETH_DM9051_INT_GPIO, GPIO_INTR_POSEDGE); - gpio_intr_enable(CONFIG_ETH_DM9051_INT_GPIO); - gpio_isr_handler_add(CONFIG_ETH_DM9051_INT_GPIO, dm9051_isr_handler, emac); + gpio_pad_select_gpio(emac->int_gpio_num); + gpio_set_direction(emac->int_gpio_num, GPIO_MODE_INPUT); + gpio_set_pull_mode(emac->int_gpio_num, GPIO_PULLDOWN_ONLY); + gpio_set_intr_type(emac->int_gpio_num, GPIO_INTR_POSEDGE); + gpio_intr_enable(emac->int_gpio_num); + gpio_isr_handler_add(emac->int_gpio_num, dm9051_isr_handler, emac); MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL); /* reset dm9051 */ MAC_CHECK(dm9051_reset(emac) == ESP_OK, "reset dm9051 failed", err, ESP_FAIL); @@ -789,8 +652,8 @@ static esp_err_t emac_dm9051_init(esp_eth_mac_t *mac) MAC_CHECK(dm9051_get_mac_addr(emac) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL); return ESP_OK; err: - gpio_isr_handler_remove(CONFIG_ETH_DM9051_INT_GPIO); - gpio_reset_pin(CONFIG_ETH_DM9051_INT_GPIO); + gpio_isr_handler_remove(emac->int_gpio_num); + gpio_reset_pin(emac->int_gpio_num); eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); return ret; } @@ -800,8 +663,8 @@ static esp_err_t emac_dm9051_deinit(esp_eth_mac_t *mac) emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); esp_eth_mediator_t *eth = emac->eth; dm9051_stop(emac); - gpio_isr_handler_remove(CONFIG_ETH_DM9051_INT_GPIO); - gpio_reset_pin(CONFIG_ETH_DM9051_INT_GPIO); + gpio_isr_handler_remove(emac->int_gpio_num); + gpio_reset_pin(emac->int_gpio_num); eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); return ESP_OK; } @@ -822,8 +685,11 @@ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, MAC_CHECK(mac_config, "can't set mac config to null", err, NULL); emac_dm9051_t *emac = calloc(1, sizeof(emac_dm9051_t)); MAC_CHECK(emac, "calloc emac failed", err, NULL); + /* dm9051 receive is driven by interrupt only for now*/ + MAC_CHECK(dm9051_config->int_gpio_num >= 0, "error interrupt gpio number", err, NULL); /* bind methods and attributes */ emac->sw_reset_timeout_ms = mac_config->sw_reset_timeout_ms; + emac->int_gpio_num = dm9051_config->int_gpio_num; emac->spi_hdl = dm9051_config->spi_hdl; emac->parent.set_mediator = emac_dm9051_set_mediator; emac->parent.init = emac_dm9051_init; diff --git a/components/esp_eth/src/esp_eth_mac_esp32.c b/components/esp_eth/src/esp_eth_mac_esp32.c index bbc3df22da..e68c9e8e67 100644 --- a/components/esp_eth/src/esp_eth_mac_esp32.c +++ b/components/esp_eth/src/esp_eth_mac_esp32.c @@ -16,6 +16,7 @@ #include #include "driver/periph_ctrl.h" #include "driver/gpio.h" +#include "esp_attr.h" #include "esp_log.h" #include "esp_eth.h" #include "esp_system.h" @@ -51,6 +52,8 @@ typedef struct { TaskHandle_t rx_task_hdl; uint32_t sw_reset_timeout_ms; uint32_t frames_remain; + int smi_mdc_gpio_num; + int smi_mdio_gpio_num; uint8_t addr[6]; uint8_t *rx_buf[CONFIG_ETH_DMA_RX_BUFFER_NUM]; uint8_t *tx_buf[CONFIG_ETH_DMA_TX_BUFFER_NUM]; @@ -255,17 +258,17 @@ static void emac_esp32_rx_task(void *arg) vTaskDelete(NULL); } -static void emac_esp32_init_smi_gpio(void) +static void emac_esp32_init_smi_gpio(emac_esp32_t *emac) { /* Setup SMI MDC GPIO */ - gpio_set_direction(CONFIG_ETH_SMI_MDC_GPIO, GPIO_MODE_OUTPUT); - gpio_matrix_out(CONFIG_ETH_SMI_MDC_GPIO, EMAC_MDC_O_IDX, false, false); - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[CONFIG_ETH_SMI_MDC_GPIO], PIN_FUNC_GPIO); + gpio_set_direction(emac->smi_mdc_gpio_num, GPIO_MODE_OUTPUT); + gpio_matrix_out(emac->smi_mdc_gpio_num, EMAC_MDC_O_IDX, false, false); + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[emac->smi_mdc_gpio_num], PIN_FUNC_GPIO); /* Setup SMI MDIO GPIO */ - gpio_set_direction(CONFIG_ETH_SMI_MDIO_GPIO, GPIO_MODE_INPUT_OUTPUT); - gpio_matrix_out(CONFIG_ETH_SMI_MDIO_GPIO, EMAC_MDO_O_IDX, false, false); - gpio_matrix_in(CONFIG_ETH_SMI_MDIO_GPIO, EMAC_MDI_I_IDX, false); - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[CONFIG_ETH_SMI_MDIO_GPIO], PIN_FUNC_GPIO); + gpio_set_direction(emac->smi_mdio_gpio_num, GPIO_MODE_INPUT_OUTPUT); + gpio_matrix_out(emac->smi_mdio_gpio_num, EMAC_MDO_O_IDX, false, false); + gpio_matrix_in(emac->smi_mdio_gpio_num, EMAC_MDI_I_IDX, false); + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[emac->smi_mdio_gpio_num], PIN_FUNC_GPIO); } static esp_err_t emac_esp32_init(esp_eth_mac_t *mac) @@ -278,12 +281,7 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac) /* enable clock, config gpio, etc */ emac_hal_lowlevel_init(&emac->hal); /* init gpio used by gpio */ - emac_esp32_init_smi_gpio(); -#if CONFIG_ETH_PHY_USE_RST - gpio_pad_select_gpio(CONFIG_ETH_PHY_RST_GPIO); - gpio_set_direction(CONFIG_ETH_PHY_RST_GPIO, GPIO_MODE_OUTPUT); - gpio_set_level(CONFIG_ETH_PHY_RST_GPIO, 1); -#endif + emac_esp32_init_smi_gpio(emac); MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL); /* software reset */ emac_hal_reset(&emac->hal); @@ -318,9 +316,6 @@ static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac) { emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); esp_eth_mediator_t *eth = emac->eth; -#if CONFIG_ETH_PHY_USE_RST - gpio_set_level(CONFIG_ETH_PHY_RST_GPIO, 0); -#endif emac_hal_stop(&emac->hal); eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); periph_module_disable(PERIPH_EMAC_MODULE); @@ -344,7 +339,7 @@ static esp_err_t emac_esp32_del(esp_eth_mac_t *mac) return ESP_OK; } -void emac_esp32_isr_handler(void *args) +IRAM_ATTR void emac_esp32_isr_handler(void *args) { emac_hal_context_t *hal = (emac_hal_context_t *)args; emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal); @@ -398,6 +393,8 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) /* initialize hal layer driver */ emac_hal_init(&emac->hal, descriptors, emac->rx_buf, emac->tx_buf); emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; + emac->smi_mdc_gpio_num = config->smi_mdc_gpio_num; + emac->smi_mdio_gpio_num = config->smi_mdio_gpio_num; emac->parent.set_mediator = emac_esp32_set_mediator; emac->parent.init = emac_esp32_init; emac->parent.deinit = emac_esp32_deinit; @@ -438,7 +435,7 @@ err: return ret; } -void emac_hal_rx_complete_cb(void *arg) +IRAM_ATTR void emac_hal_rx_complete_cb(void *arg) { emac_hal_context_t *hal = (emac_hal_context_t *)arg; emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal); @@ -450,7 +447,7 @@ void emac_hal_rx_complete_cb(void *arg) } } -void emac_hal_rx_unavail_cb(void *arg) +IRAM_ATTR void emac_hal_rx_unavail_cb(void *arg) { emac_hal_context_t *hal = (emac_hal_context_t *)arg; emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal); diff --git a/components/esp_eth/src/esp_eth_phy_dm9051.c b/components/esp_eth/src/esp_eth_phy_dm9051.c index cb658c181d..b7d167b5ed 100644 --- a/components/esp_eth/src/esp_eth_phy_dm9051.c +++ b/components/esp_eth/src/esp_eth_phy_dm9051.c @@ -19,6 +19,7 @@ #include "eth_phy_regs_struct.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "driver/gpio.h" static const char *TAG = "dm9051"; #define PHY_CHECK(a, str, goto_tag, ...) \ @@ -84,6 +85,7 @@ typedef struct { uint32_t reset_timeout_ms; uint32_t autonego_timeout_ms; eth_link_t link_status; + int reset_gpio_num; } phy_dm9051_t; static esp_err_t dm9051_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) @@ -143,6 +145,19 @@ err: return ESP_FAIL; } +static esp_err_t dm9051_reset_hw(esp_eth_phy_t *phy) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + // set reset_gpio_num minus zero can skip hardware reset phy chip + if (dm9051->reset_gpio_num >= 0) { + gpio_pad_select_gpio(dm9051->reset_gpio_num); + gpio_set_direction(dm9051->reset_gpio_num, GPIO_MODE_OUTPUT); + gpio_set_level(dm9051->reset_gpio_num, 0); + gpio_set_level(dm9051->reset_gpio_num, 1); + } + return ESP_OK; +} + static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy) { phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); @@ -283,9 +298,11 @@ esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config) dm9051->name = "dm9051"; dm9051->addr = config->phy_addr; dm9051->reset_timeout_ms = config->reset_timeout_ms; + dm9051->reset_gpio_num = config->reset_gpio_num; dm9051->link_status = ETH_LINK_DOWN; dm9051->autonego_timeout_ms = config->autonego_timeout_ms; dm9051->parent.reset = dm9051_reset; + dm9051->parent.reset_hw = dm9051_reset_hw; dm9051->parent.init = dm9051_init; dm9051->parent.deinit = dm9051_deinit; dm9051->parent.set_mediator = dm9051_set_mediator; diff --git a/components/esp_eth/src/esp_eth_phy_dp83848.c b/components/esp_eth/src/esp_eth_phy_dp83848.c index ac76f7a99c..e62ced932d 100644 --- a/components/esp_eth/src/esp_eth_phy_dp83848.c +++ b/components/esp_eth/src/esp_eth_phy_dp83848.c @@ -19,6 +19,7 @@ #include "eth_phy_regs_struct.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "driver/gpio.h" static const char *TAG = "dp83848"; #define PHY_CHECK(a, str, goto_tag, ...) \ @@ -90,6 +91,7 @@ typedef struct { uint32_t reset_timeout_ms; uint32_t autonego_timeout_ms; eth_link_t link_status; + int reset_gpio_num; } phy_dp83848_t; static esp_err_t dp83848_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) @@ -144,6 +146,18 @@ err: return ESP_FAIL; } +static esp_err_t dp83848_reset_hw(esp_eth_phy_t *phy) +{ + phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); + if (dp83848->reset_gpio_num >= 0) { + gpio_pad_select_gpio(dp83848->reset_gpio_num); + gpio_set_direction(dp83848->reset_gpio_num, GPIO_MODE_OUTPUT); + gpio_set_level(dp83848->reset_gpio_num, 0); + gpio_set_level(dp83848->reset_gpio_num, 1); + } + return ESP_OK; +} + static esp_err_t dp83848_negotiate(esp_eth_phy_t *phy) { phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); @@ -285,8 +299,10 @@ esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config) dp83848->addr = config->phy_addr; dp83848->reset_timeout_ms = config->reset_timeout_ms; dp83848->link_status = ETH_LINK_DOWN; + dp83848->reset_gpio_num = config->reset_gpio_num; dp83848->autonego_timeout_ms = config->autonego_timeout_ms; dp83848->parent.reset = dp83848_reset; + dp83848->parent.reset_hw = dp83848_reset_hw; dp83848->parent.init = dp83848_init; dp83848->parent.deinit = dp83848_deinit; dp83848->parent.set_mediator = dp83848_set_mediator; diff --git a/components/esp_eth/src/esp_eth_phy_ip101.c b/components/esp_eth/src/esp_eth_phy_ip101.c index e5dfd55557..3fb51d1ea0 100644 --- a/components/esp_eth/src/esp_eth_phy_ip101.c +++ b/components/esp_eth/src/esp_eth_phy_ip101.c @@ -19,6 +19,7 @@ #include "eth_phy_regs_struct.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "driver/gpio.h" static const char *TAG = "ip101"; #define PHY_CHECK(a, str, goto_tag, ...) \ @@ -107,6 +108,7 @@ typedef struct { uint32_t reset_timeout_ms; uint32_t autonego_timeout_ms; eth_link_t link_status; + int reset_gpio_num; } phy_ip101_t; static esp_err_t ip101_page_select(phy_ip101_t *ip101, uint32_t page) @@ -173,6 +175,18 @@ err: return ESP_FAIL; } +static esp_err_t ip101_reset_hw(esp_eth_phy_t *phy) +{ + phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); + if (ip101->reset_gpio_num >= 0) { + gpio_pad_select_gpio(ip101->reset_gpio_num); + gpio_set_direction(ip101->reset_gpio_num, GPIO_MODE_OUTPUT); + gpio_set_level(ip101->reset_gpio_num, 0); + gpio_set_level(ip101->reset_gpio_num, 1); + } + return ESP_OK; +} + static esp_err_t ip101_negotiate(esp_eth_phy_t *phy) { phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); @@ -326,9 +340,11 @@ esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config) ip101->name = "ip101"; ip101->addr = config->phy_addr; ip101->reset_timeout_ms = config->reset_timeout_ms; + ip101->reset_gpio_num = config->reset_gpio_num; ip101->link_status = ETH_LINK_DOWN; ip101->autonego_timeout_ms = config->autonego_timeout_ms; ip101->parent.reset = ip101_reset; + ip101->parent.reset_hw = ip101_reset_hw; ip101->parent.init = ip101_init; ip101->parent.deinit = ip101_deinit; ip101->parent.set_mediator = ip101_set_mediator; diff --git a/components/esp_eth/src/esp_eth_phy_lan8720.c b/components/esp_eth/src/esp_eth_phy_lan8720.c index 8cbcd11298..98a91e10ab 100644 --- a/components/esp_eth/src/esp_eth_phy_lan8720.c +++ b/components/esp_eth/src/esp_eth_phy_lan8720.c @@ -19,6 +19,7 @@ #include "eth_phy_regs_struct.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "driver/gpio.h" static const char *TAG = "lan8720"; #define PHY_CHECK(a, str, goto_tag, ...) \ @@ -162,6 +163,7 @@ typedef struct { uint32_t reset_timeout_ms; uint32_t autonego_timeout_ms; eth_link_t link_status; + int reset_gpio_num; } phy_lan8720_t; static esp_err_t lan8720_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) @@ -216,6 +218,18 @@ err: return ESP_FAIL; } +static esp_err_t lan8720_reset_hw(esp_eth_phy_t *phy) +{ + phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); + if (lan8720->reset_gpio_num >= 0) { + gpio_pad_select_gpio(lan8720->reset_gpio_num); + gpio_set_direction(lan8720->reset_gpio_num, GPIO_MODE_OUTPUT); + gpio_set_level(lan8720->reset_gpio_num, 0); + gpio_set_level(lan8720->reset_gpio_num, 1); + } + return ESP_OK; +} + static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy) { phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); @@ -365,10 +379,12 @@ esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config) PHY_CHECK(lan8720, "calloc lan8720 object failed", err); lan8720->name = "lan8720"; lan8720->addr = config->phy_addr; + lan8720->reset_gpio_num = config->reset_gpio_num; lan8720->reset_timeout_ms = config->reset_timeout_ms; lan8720->link_status = ETH_LINK_DOWN; lan8720->autonego_timeout_ms = config->autonego_timeout_ms; lan8720->parent.reset = lan8720_reset; + lan8720->parent.reset_hw = lan8720_reset_hw; lan8720->parent.init = lan8720_init; lan8720->parent.deinit = lan8720_deinit; lan8720->parent.set_mediator = lan8720_set_mediator; diff --git a/components/esp_eth/src/esp_eth_phy_rtl8201.c b/components/esp_eth/src/esp_eth_phy_rtl8201.c index b927ed5c9c..7b97a12342 100644 --- a/components/esp_eth/src/esp_eth_phy_rtl8201.c +++ b/components/esp_eth/src/esp_eth_phy_rtl8201.c @@ -20,6 +20,7 @@ #include "eth_phy_regs_struct.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "driver/gpio.h" static const char *TAG = "rtl8201"; #define PHY_CHECK(a, str, goto_tag, ...) \ @@ -68,6 +69,7 @@ typedef struct { uint32_t reset_timeout_ms; uint32_t autonego_timeout_ms; eth_link_t link_status; + int reset_gpio_num; } phy_rtl8201_t; static esp_err_t rtl8201_page_select(phy_rtl8201_t *rtl8201, uint32_t page) @@ -134,6 +136,18 @@ err: return ESP_FAIL; } +static esp_err_t rtl8201_reset_hw(esp_eth_phy_t *phy) +{ + phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); + if (rtl8201->reset_gpio_num >= 0) { + gpio_pad_select_gpio(rtl8201->reset_gpio_num); + gpio_set_direction(rtl8201->reset_gpio_num, GPIO_MODE_OUTPUT); + gpio_set_level(rtl8201->reset_gpio_num, 0); + gpio_set_level(rtl8201->reset_gpio_num, 1); + } + return ESP_OK; +} + static esp_err_t rtl8201_negotiate(esp_eth_phy_t *phy) { phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); @@ -272,10 +286,12 @@ esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config) PHY_CHECK(rtl8201, "calloc rtl8201 object failed", err); rtl8201->name = "rtl8201"; rtl8201->addr = config->phy_addr; + rtl8201->reset_gpio_num = config->reset_gpio_num; rtl8201->reset_timeout_ms = config->reset_timeout_ms; rtl8201->link_status = ETH_LINK_DOWN; rtl8201->autonego_timeout_ms = config->autonego_timeout_ms; rtl8201->parent.reset = rtl8201_reset; + rtl8201->parent.reset_hw = rtl8201_reset_hw; rtl8201->parent.init = rtl8201_init; rtl8201->parent.deinit = rtl8201_deinit; rtl8201->parent.set_mediator = rtl8201_set_mediator; diff --git a/components/esp_eth/test/test_emac.c b/components/esp_eth/test/test_emac.c index 405139ab49..78995d8c5e 100644 --- a/components/esp_eth/test/test_emac.c +++ b/components/esp_eth/test/test_emac.c @@ -10,6 +10,7 @@ #include "esp_event.h" #include "esp_eth.h" #include "esp_log.h" +#include "driver/gpio.h" static const char *TAG = "esp_eth_test"; diff --git a/components/soc/esp32/emac_hal.c b/components/soc/esp32/emac_hal.c index 121bc53269..93ff771db1 100644 --- a/components/soc/esp32/emac_hal.c +++ b/components/soc/esp32/emac_hal.c @@ -544,7 +544,7 @@ uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t return len; } -void emac_hal_isr(void *arg) +IRAM_ATTR void emac_hal_isr(void *arg) { emac_hal_context_t *hal = (emac_hal_context_t *)arg; typeof(hal->dma_regs->dmastatus) dma_status = hal->dma_regs->dmastatus; @@ -615,7 +615,7 @@ void emac_hal_isr(void *arg) } } -__attribute__((weak)) void emac_hal_tx_complete_cb(void *arg) +IRAM_ATTR __attribute__((weak)) void emac_hal_tx_complete_cb(void *arg) { // This is a weak function, do nothing by default // Upper code can rewrite this function @@ -623,7 +623,7 @@ __attribute__((weak)) void emac_hal_tx_complete_cb(void *arg) return; } -__attribute__((weak)) void emac_hal_tx_unavail_cb(void *arg) +IRAM_ATTR __attribute__((weak)) void emac_hal_tx_unavail_cb(void *arg) { // This is a weak function, do nothing by default // Upper code can rewrite this function @@ -631,7 +631,7 @@ __attribute__((weak)) void emac_hal_tx_unavail_cb(void *arg) return; } -__attribute__((weak)) void emac_hal_rx_complete_cb(void *arg) +IRAM_ATTR __attribute__((weak)) void emac_hal_rx_complete_cb(void *arg) { // This is a weak function, do nothing by default // Upper code can rewrite this function @@ -639,7 +639,7 @@ __attribute__((weak)) void emac_hal_rx_complete_cb(void *arg) return; } -__attribute__((weak)) void emac_hal_rx_early_cb(void *arg) +IRAM_ATTR __attribute__((weak)) void emac_hal_rx_early_cb(void *arg) { // This is a weak function, do nothing by default // Upper code can rewrite this function @@ -647,7 +647,7 @@ __attribute__((weak)) void emac_hal_rx_early_cb(void *arg) return; } -__attribute__((weak)) void emac_hal_rx_unavail_cb(void *arg) +IRAM_ATTR __attribute__((weak)) void emac_hal_rx_unavail_cb(void *arg) { // This is a weak function, do nothing by default // Upper code can rewrite this function diff --git a/components/soc/linker.lf b/components/soc/linker.lf index 21aa0a0331..092322a0c7 100644 --- a/components/soc/linker.lf +++ b/components/soc/linker.lf @@ -14,10 +14,3 @@ entries: spi_slave_hal_iram (noflash_text) spi_flash_hal_iram (noflash) lldesc (noflash_text) - if ETH_USE_ESP32_EMAC = y: - emac_hal:emac_hal_isr (noflash_text) - emac_hal:emac_hal_tx_complete_cb (noflash_text) - emac_hal:emac_hal_tx_unavail_cb (noflash_text) - emac_hal:emac_hal_rx_complete_cb (noflash_text) - emac_hal:emac_hal_rx_early_cb (noflash_text) - emac_hal:emac_hal_rx_unavail_cb (noflash_text) diff --git a/examples/common_components/protocol_examples_common/Kconfig.projbuild b/examples/common_components/protocol_examples_common/Kconfig.projbuild index f5d288e9ae..6c58242761 100644 --- a/examples/common_components/protocol_examples_common/Kconfig.projbuild +++ b/examples/common_components/protocol_examples_common/Kconfig.projbuild @@ -33,7 +33,7 @@ menu "Example Connection Configuration" choice EXAMPLE_USE_ETHERNET prompt "Ethernet Type" default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32 - default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32 + default EXAMPLE_USE_DM9051 if !IDF_TARGET_ESP32 help Select which kind of Ethernet will be used in the example. @@ -44,9 +44,10 @@ menu "Example Connection Configuration" help Select internal Ethernet MAC controller. - config EXAMPLE_USE_SPI_ETHERNET - bool "SPI Ethernet Module" + config EXAMPLE_USE_DM9051 + bool "DM9051 Module" select ETH_USE_SPI_ETHERNET + select ETH_SPI_ETHERNET_DM9051 help Select external SPI-Ethernet module. endchoice @@ -82,51 +83,84 @@ menu "Example Connection Configuration" DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. Goto http://www.ti.com/product/DP83848J for more information about it. endchoice + + config EXAMPLE_ETH_MDC_GPIO + int "SMI MDC GPIO number" + default 23 + help + Set the GPIO number used by SMI MDC. + + config EXAMPLE_ETH_MDIO_GPIO + int "SMI MDIO GPIO number" + default 18 + help + Set the GPIO number used by SMI MDIO. endif - if EXAMPLE_USE_SPI_ETHERNET - config EXAMPLE_ETH_SPI_HOST + if EXAMPLE_USE_DM9051 + config EXAMPLE_DM9051_SPI_HOST int "SPI Host Number" range 0 2 default 1 help Set the SPI host used to communicate with DM9051. - config EXAMPLE_ETH_SCLK_GPIO + config EXAMPLE_DM9051_SCLK_GPIO int "SPI SCLK GPIO number" range 0 33 default 19 help Set the GPIO number used by SPI SCLK. - config EXAMPLE_ETH_MOSI_GPIO + config EXAMPLE_DM9051_MOSI_GPIO int "SPI MOSI GPIO number" range 0 33 default 23 help Set the GPIO number used by SPI MOSI. - config EXAMPLE_ETH_MISO_GPIO + config EXAMPLE_DM9051_MISO_GPIO int "SPI MISO GPIO number" range 0 33 default 25 help Set the GPIO number used by SPI MISO. - config EXAMPLE_ETH_CS_GPIO + config EXAMPLE_DM9051_CS_GPIO int "SPI CS GPIO number" range 0 33 default 22 help Set the GPIO number used by SPI CS. - config EXAMPLE_ETH_SPI_CLOCK_MHZ + config EXAMPLE_DM9051_SPI_CLOCK_MHZ int "SPI clock speed (MHz)" range 20 80 default 20 help Set the clock speed (MHz) of SPI interface. + + config EXAMPLE_DM9051_INT_GPIO + int "Interrupt GPIO number" + default 4 + help + Set the GPIO number used by DM9051 interrupt. endif + + config EXAMPLE_ETH_PHY_RST_GPIO + int "PHY Reset GPIO number" + 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 if EXAMPLE_USE_INTERNAL_ETHERNET + range 1 1 if !EXAMPLE_USE_INTERNAL_ETHERNET + default 1 + help + Set PHY address according your board schematic. endif config EXAMPLE_CONNECT_IPV6 diff --git a/examples/common_components/protocol_examples_common/connect.c b/examples/common_components/protocol_examples_common/connect.c index 27cc8fe2b3..06c5212b7a 100644 --- a/examples/common_components/protocol_examples_common/connect.c +++ b/examples/common_components/protocol_examples_common/connect.c @@ -15,6 +15,7 @@ #include "esp_eth.h" #include "esp_log.h" #include "tcpip_adapter.h" +#include "driver/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" @@ -188,7 +189,11 @@ static void start() #endif eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR; + phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO; #if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET + mac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO; + mac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO; s_mac = esp_eth_mac_new_esp32(&mac_config); #if CONFIG_EXAMPLE_ETH_PHY_IP101 s_phy = esp_eth_phy_new_ip101(&phy_config); @@ -199,28 +204,29 @@ static void start() #elif CONFIG_EXAMPLE_ETH_PHY_DP83848 s_phy = esp_eth_phy_new_dp83848(&phy_config); #endif -#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET +#elif CONFIG_EXAMPLE_USE_DM9051 gpio_install_isr_service(0); spi_device_handle_t spi_handle = NULL; spi_bus_config_t buscfg = { - .miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO, - .mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO, - .sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO, + .miso_io_num = CONFIG_EXAMPLE_DM9051_MISO_GPIO, + .mosi_io_num = CONFIG_EXAMPLE_DM9051_MOSI_GPIO, + .sclk_io_num = CONFIG_EXAMPLE_DM9051_SCLK_GPIO, .quadwp_io_num = -1, .quadhd_io_num = -1, }; - ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1)); + ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_DM9051_SPI_HOST, &buscfg, 1)); spi_device_interface_config_t devcfg = { .command_bits = 1, .address_bits = 7, .mode = 0, - .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000, - .spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO, + .clock_speed_hz = CONFIG_EXAMPLE_DM9051_SPI_CLOCK_MHZ * 1000 * 1000, + .spics_io_num = CONFIG_EXAMPLE_DM9051_CS_GPIO, .queue_size = 20 }; - ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); + ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_DM9051_SPI_HOST, &devcfg, &spi_handle)); /* dm9051 ethernet driver is based on spi driver */ eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); + dm9051_config.int_gpio_num = CONFIG_EXAMPLE_DM9051_INT_GPIO; s_mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config); s_phy = esp_eth_phy_new_dm9051(&phy_config); #endif diff --git a/examples/ethernet/basic/main/Kconfig.projbuild b/examples/ethernet/basic/main/Kconfig.projbuild index 9c6cae1f73..167a1ede20 100644 --- a/examples/ethernet/basic/main/Kconfig.projbuild +++ b/examples/ethernet/basic/main/Kconfig.projbuild @@ -2,7 +2,7 @@ menu "Example Configuration" choice EXAMPLE_USE_ETHERNET prompt "Ethernet Type" default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32 - default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32 + default EXAMPLE_USE_DM9051 if !IDF_TARGET_ESP32 help Select which kind of Ethernet will be used in the example. @@ -13,9 +13,10 @@ menu "Example Configuration" help Select internal Ethernet MAC controller. - config EXAMPLE_USE_SPI_ETHERNET - bool "SPI Ethernet Module" + config EXAMPLE_USE_DM9051 + bool "DM9051 Module" select ETH_USE_SPI_ETHERNET + select ETH_SPI_ETHERNET_DM9051 help Select external SPI-Ethernet module. endchoice @@ -51,49 +52,82 @@ menu "Example Configuration" DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. Goto http://www.ti.com/product/DP83848J for more information about it. endchoice + + config EXAMPLE_ETH_MDC_GPIO + int "SMI MDC GPIO number" + default 23 + help + Set the GPIO number used by SMI MDC. + + config EXAMPLE_ETH_MDIO_GPIO + int "SMI MDIO GPIO number" + default 18 + help + Set the GPIO number used by SMI MDIO. endif - if EXAMPLE_USE_SPI_ETHERNET - config EXAMPLE_ETH_SPI_HOST + if EXAMPLE_USE_DM9051 + config EXAMPLE_DM9051_SPI_HOST int "SPI Host Number" range 0 2 default 1 help Set the SPI host used to communicate with DM9051. - config EXAMPLE_ETH_SCLK_GPIO + config EXAMPLE_DM9051_SCLK_GPIO int "SPI SCLK GPIO number" range 0 33 default 19 help Set the GPIO number used by SPI SCLK. - config EXAMPLE_ETH_MOSI_GPIO + config EXAMPLE_DM9051_MOSI_GPIO int "SPI MOSI GPIO number" range 0 33 default 23 help Set the GPIO number used by SPI MOSI. - config EXAMPLE_ETH_MISO_GPIO + config EXAMPLE_DM9051_MISO_GPIO int "SPI MISO GPIO number" range 0 33 default 25 help Set the GPIO number used by SPI MISO. - config EXAMPLE_ETH_CS_GPIO + config EXAMPLE_DM9051_CS_GPIO int "SPI CS GPIO number" range 0 33 default 22 help Set the GPIO number used by SPI CS. - config EXAMPLE_ETH_SPI_CLOCK_MHZ + config EXAMPLE_DM9051_SPI_CLOCK_MHZ int "SPI clock speed (MHz)" range 20 80 default 20 help Set the clock speed (MHz) of SPI interface. + + config EXAMPLE_DM9051_INT_GPIO + int "Interrupt GPIO number" + default 4 + help + Set the GPIO number used by DM9051 interrupt. endif + + config EXAMPLE_ETH_PHY_RST_GPIO + int "PHY Reset GPIO number" + 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 if EXAMPLE_USE_INTERNAL_ETHERNET + range 1 1 if !EXAMPLE_USE_INTERNAL_ETHERNET + default 1 + help + Set PHY address according your board schematic. endmenu diff --git a/examples/ethernet/basic/main/ethernet_example_main.c b/examples/ethernet/basic/main/ethernet_example_main.c index e387283fa9..e161f435c7 100644 --- a/examples/ethernet/basic/main/ethernet_example_main.c +++ b/examples/ethernet/basic/main/ethernet_example_main.c @@ -14,6 +14,7 @@ #include "esp_eth.h" #include "esp_event.h" #include "esp_log.h" +#include "driver/gpio.h" #include "sdkconfig.h" static const char *TAG = "eth_example"; @@ -73,7 +74,11 @@ void app_main() eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR; + phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO; #if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET + mac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO; + mac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO; esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); #if CONFIG_EXAMPLE_ETH_PHY_IP101 esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); @@ -84,28 +89,29 @@ void app_main() #elif CONFIG_EXAMPLE_ETH_PHY_DP83848 esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config); #endif -#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET +#elif CONFIG_EXAMPLE_USE_DM9051 gpio_install_isr_service(0); spi_device_handle_t spi_handle = NULL; spi_bus_config_t buscfg = { - .miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO, - .mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO, - .sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO, + .miso_io_num = CONFIG_EXAMPLE_DM9051_MISO_GPIO, + .mosi_io_num = CONFIG_EXAMPLE_DM9051_MOSI_GPIO, + .sclk_io_num = CONFIG_EXAMPLE_DM9051_SCLK_GPIO, .quadwp_io_num = -1, .quadhd_io_num = -1, }; - ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1)); + ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_DM9051_SPI_HOST, &buscfg, 1)); spi_device_interface_config_t devcfg = { .command_bits = 1, .address_bits = 7, .mode = 0, - .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000, - .spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO, + .clock_speed_hz = CONFIG_EXAMPLE_DM9051_SPI_CLOCK_MHZ * 1000 * 1000, + .spics_io_num = CONFIG_EXAMPLE_DM9051_CS_GPIO, .queue_size = 20 }; - ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); + ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_DM9051_SPI_HOST, &devcfg, &spi_handle)); /* dm9051 ethernet driver is based on spi driver */ eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); + dm9051_config.int_gpio_num = CONFIG_EXAMPLE_DM9051_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); #endif diff --git a/examples/ethernet/eth2ap/main/Kconfig.projbuild b/examples/ethernet/eth2ap/main/Kconfig.projbuild index 40b54b9ad3..8497f862d8 100644 --- a/examples/ethernet/eth2ap/main/Kconfig.projbuild +++ b/examples/ethernet/eth2ap/main/Kconfig.projbuild @@ -2,7 +2,7 @@ menu "Example Configuration" choice EXAMPLE_USE_ETHERNET prompt "Ethernet Type" default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32 - default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32 + default EXAMPLE_USE_DM9051 if !IDF_TARGET_ESP32 help Select which kind of Ethernet will be used in the example. @@ -13,9 +13,10 @@ menu "Example Configuration" help Select internal Ethernet MAC controller. - config EXAMPLE_USE_SPI_ETHERNET - bool "SPI Ethernet Module" + config EXAMPLE_USE_DM9051 + bool "DM9051 Module" select ETH_USE_SPI_ETHERNET + select ETH_SPI_ETHERNET_DM9051 help Select external SPI-Ethernet module. endchoice @@ -51,52 +52,85 @@ menu "Example Configuration" DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. Goto http://www.ti.com/product/DP83848J for more information about it. endchoice + + config EXAMPLE_ETH_MDC_GPIO + int "SMI MDC GPIO number" + default 23 + help + Set the GPIO number used by SMI MDC. + + config EXAMPLE_ETH_MDIO_GPIO + int "SMI MDIO GPIO number" + default 18 + help + Set the GPIO number used by SMI MDIO. endif - if EXAMPLE_USE_SPI_ETHERNET - config EXAMPLE_ETH_SPI_HOST + if EXAMPLE_USE_DM9051 + config EXAMPLE_DM9051_SPI_HOST int "SPI Host Number" range 0 2 default 1 help Set the SPI host used to communicate with DM9051. - config EXAMPLE_ETH_SCLK_GPIO + config EXAMPLE_DM9051_SCLK_GPIO int "SPI SCLK GPIO number" range 0 33 default 19 help Set the GPIO number used by SPI SCLK. - config EXAMPLE_ETH_MOSI_GPIO + config EXAMPLE_DM9051_MOSI_GPIO int "SPI MOSI GPIO number" range 0 33 default 23 help Set the GPIO number used by SPI MOSI. - config EXAMPLE_ETH_MISO_GPIO + config EXAMPLE_DM9051_MISO_GPIO int "SPI MISO GPIO number" range 0 33 default 25 help Set the GPIO number used by SPI MISO. - config EXAMPLE_ETH_CS_GPIO + config EXAMPLE_DM9051_CS_GPIO int "SPI CS GPIO number" range 0 33 default 22 help Set the GPIO number used by SPI CS. - config EXAMPLE_ETH_SPI_CLOCK_MHZ + config EXAMPLE_DM9051_SPI_CLOCK_MHZ int "SPI clock speed (MHz)" range 20 80 default 20 help Set the clock speed (MHz) of SPI interface. + + config EXAMPLE_DM9051_INT_GPIO + int "Interrupt GPIO number" + default 4 + help + Set the GPIO number used by DM9051 interrupt. endif + config EXAMPLE_ETH_PHY_RST_GPIO + int "PHY Reset GPIO number" + 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 if EXAMPLE_USE_INTERNAL_ETHERNET + range 1 1 if !EXAMPLE_USE_INTERNAL_ETHERNET + default 1 + help + Set PHY address according your board schematic. + config EXAMPLE_WIFI_SSID string "Wi-Fi SSID" default "eth2ap" diff --git a/examples/ethernet/eth2ap/main/ethernet_example_main.c b/examples/ethernet/eth2ap/main/ethernet_example_main.c index 99afe94f84..004183945b 100644 --- a/examples/ethernet/eth2ap/main/ethernet_example_main.c +++ b/examples/ethernet/eth2ap/main/ethernet_example_main.c @@ -146,7 +146,11 @@ static void initialize_ethernet(void) ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler, NULL)); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR; + phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO; #if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET + mac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO; + mac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO; esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); #if CONFIG_EXAMPLE_ETH_PHY_IP101 esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); @@ -157,28 +161,29 @@ static void initialize_ethernet(void) #elif CONFIG_EXAMPLE_ETH_PHY_DP83848 esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config); #endif -#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET +#elif CONFIG_EXAMPLE_USE_DM9051 gpio_install_isr_service(0); spi_device_handle_t spi_handle = NULL; spi_bus_config_t buscfg = { - .miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO, - .mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO, - .sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO, + .miso_io_num = CONFIG_EXAMPLE_DM9051_MISO_GPIO, + .mosi_io_num = CONFIG_EXAMPLE_DM9051_MOSI_GPIO, + .sclk_io_num = CONFIG_EXAMPLE_DM9051_SCLK_GPIO, .quadwp_io_num = -1, .quadhd_io_num = -1, }; - ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1)); + ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_DM9051_SPI_HOST, &buscfg, 1)); spi_device_interface_config_t devcfg = { .command_bits = 1, .address_bits = 7, .mode = 0, - .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000, - .spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO, + .clock_speed_hz = CONFIG_EXAMPLE_DM9051_SPI_CLOCK_MHZ * 1000 * 1000, + .spics_io_num = CONFIG_EXAMPLE_DM9051_CS_GPIO, .queue_size = 20 }; - ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); + ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_DM9051_SPI_HOST, &devcfg, &spi_handle)); /* dm9051 ethernet driver is based on spi driver */ eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); + dm9051_config.int_gpio_num = CONFIG_EXAMPLE_DM9051_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); #endif diff --git a/examples/ethernet/iperf/main/Kconfig.projbuild b/examples/ethernet/iperf/main/Kconfig.projbuild index b84eefa7e7..e71121e188 100644 --- a/examples/ethernet/iperf/main/Kconfig.projbuild +++ b/examples/ethernet/iperf/main/Kconfig.projbuild @@ -10,7 +10,7 @@ menu "Example Configuration" choice EXAMPLE_USE_ETHERNET prompt "Ethernet Type" default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32 - default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32 + default EXAMPLE_USE_DM9051 if !IDF_TARGET_ESP32 help Select which kind of Ethernet will be used in the example. @@ -21,9 +21,10 @@ menu "Example Configuration" help Select internal Ethernet MAC controller. - config EXAMPLE_USE_SPI_ETHERNET - bool "SPI Ethernet Module" + config EXAMPLE_USE_DM9051 + bool "DM9051 Module" select ETH_USE_SPI_ETHERNET + select ETH_SPI_ETHERNET_DM9051 help Select external SPI-Ethernet module. endchoice @@ -59,49 +60,82 @@ menu "Example Configuration" DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver. Goto http://www.ti.com/product/DP83848J for more information about it. endchoice + + config EXAMPLE_ETH_MDC_GPIO + int "SMI MDC GPIO number" + default 23 + help + Set the GPIO number used by SMI MDC. + + config EXAMPLE_ETH_MDIO_GPIO + int "SMI MDIO GPIO number" + default 18 + help + Set the GPIO number used by SMI MDIO. endif - if EXAMPLE_USE_SPI_ETHERNET - config EXAMPLE_ETH_SPI_HOST + if EXAMPLE_USE_DM9051 + config EXAMPLE_DM9051_SPI_HOST int "SPI Host Number" range 0 2 default 1 help Set the SPI host used to communicate with DM9051. - config EXAMPLE_ETH_SCLK_GPIO + config EXAMPLE_DM9051_SCLK_GPIO int "SPI SCLK GPIO number" range 0 33 default 19 help Set the GPIO number used by SPI SCLK. - config EXAMPLE_ETH_MOSI_GPIO + config EXAMPLE_DM9051_MOSI_GPIO int "SPI MOSI GPIO number" range 0 33 default 23 help Set the GPIO number used by SPI MOSI. - config EXAMPLE_ETH_MISO_GPIO + config EXAMPLE_DM9051_MISO_GPIO int "SPI MISO GPIO number" range 0 33 default 25 help Set the GPIO number used by SPI MISO. - config EXAMPLE_ETH_CS_GPIO + config EXAMPLE_DM9051_CS_GPIO int "SPI CS GPIO number" range 0 33 default 22 help Set the GPIO number used by SPI CS. - config EXAMPLE_ETH_SPI_CLOCK_MHZ + config EXAMPLE_DM9051_SPI_CLOCK_MHZ int "SPI clock speed (MHz)" range 20 80 default 20 help Set the clock speed (MHz) of SPI interface. + + config EXAMPLE_DM9051_INT_GPIO + int "Interrupt GPIO number" + default 4 + help + Set the GPIO number used by DM9051 interrupt. endif + + config EXAMPLE_ETH_PHY_RST_GPIO + int "PHY Reset GPIO number" + 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 if EXAMPLE_USE_INTERNAL_ETHERNET + range 1 1 if !EXAMPLE_USE_INTERNAL_ETHERNET + default 1 + help + Set PHY address according your board schematic. endmenu diff --git a/examples/ethernet/iperf/main/cmd_ethernet.c b/examples/ethernet/iperf/main/cmd_ethernet.c index 15f0d0e9f5..48c3b35eb6 100644 --- a/examples/ethernet/iperf/main/cmd_ethernet.c +++ b/examples/ethernet/iperf/main/cmd_ethernet.c @@ -15,6 +15,7 @@ #include "esp_console.h" #include "esp_event.h" #include "esp_eth.h" +#include "driver/gpio.h" #include "argtable3/argtable3.h" #include "iperf.h" #include "sdkconfig.h" @@ -184,7 +185,11 @@ void register_ethernet() eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR; + phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO; #if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET + mac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO; + mac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO; esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); #if CONFIG_EXAMPLE_ETH_PHY_IP101 esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); @@ -195,28 +200,29 @@ void register_ethernet() #elif CONFIG_EXAMPLE_ETH_PHY_DP83848 esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config); #endif -#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET +#elif CONFIG_EXAMPLE_USE_DM9051 gpio_install_isr_service(0); spi_device_handle_t spi_handle = NULL; spi_bus_config_t buscfg = { - .miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO, - .mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO, - .sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO, + .miso_io_num = CONFIG_EXAMPLE_DM9051_MISO_GPIO, + .mosi_io_num = CONFIG_EXAMPLE_DM9051_MOSI_GPIO, + .sclk_io_num = CONFIG_EXAMPLE_DM9051_SCLK_GPIO, .quadwp_io_num = -1, .quadhd_io_num = -1, }; - ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1)); + ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_DM9051_SPI_HOST, &buscfg, 1)); spi_device_interface_config_t devcfg = { .command_bits = 1, .address_bits = 7, .mode = 0, - .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000, - .spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO, + .clock_speed_hz = CONFIG_EXAMPLE_DM9051_SPI_CLOCK_MHZ * 1000 * 1000, + .spics_io_num = CONFIG_EXAMPLE_DM9051_CS_GPIO, .queue_size = 20 }; - ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle)); + ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_DM9051_SPI_HOST, &devcfg, &spi_handle)); /* dm9051 ethernet driver is based on spi driver */ eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); + dm9051_config.int_gpio_num = CONFIG_EXAMPLE_DM9051_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); #endif From 14dd44c05ff34822823994afe1902b55a829c77a Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Thu, 14 Nov 2019 12:04:43 +0800 Subject: [PATCH 2/6] doc: move common Ethernet config explanation into a single file --- examples/ethernet/README.md | 63 ++++++++++++++++++++++++ examples/ethernet/basic/README.md | 64 ++++++------------------ examples/ethernet/eth2ap/README.md | 79 +++++++++--------------------- examples/ethernet/iperf/README.md | 69 +++++++------------------- 4 files changed, 119 insertions(+), 156 deletions(-) diff --git a/examples/ethernet/README.md b/examples/ethernet/README.md index b7bc93cbd7..d2b98cab5e 100644 --- a/examples/ethernet/README.md +++ b/examples/ethernet/README.md @@ -1,3 +1,66 @@ # Ethernet Examples See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples. + +## Common Pin Assignments + +### Using ESP32 internal MAC + +* RMII PHY wiring is fixed and can not be changed through either IOMUX or GPIO Matrix. By default, they're connected as follows: + +| GPIO | RMII Signal | Notes | +| ------ | ----------- | ------------ | +| GPIO21 | TX_EN | EMAC_TX_EN | +| GPIO19 | TX0 | EMAC_TXD0 | +| GPIO22 | TX1 | EMAC_TXD1 | +| GPIO25 | RX0 | EMAC_RXD0 | +| GPIO26 | RX1 | EMAC_RXD1 | +| GPIO27 | CRS_DV | EMAC_RX_DRV | + +* SMI (Serial Management Interface) wiring is not fixed. You may need to changed it according to your board schematic. By default they're connected as follows: + +| GPIO | SMI Signal | Notes | +| ------ | ----------- | ------------- | +| GPIO23 | MDC | Output to PHY | +| GPIO18 | MDIO | Bidirectional | + +* PHY chip has a reset pin, if want to do a hardware reset during initialization, then you have to connect it with one GPIO on ESP32. See more information from [here](#configure-the-project). The default GPIO used for resetting PHY chip is GPIO5. + +### Using DM9051 + +* DM9051 Ethernet module consumes one SPI interface plus an interrupt and reset GPIO. By default they're connected as follows: + +| GPIO | DM9051 | +| ------ | ----------- | +| GPIO19 | SPI_CLK | +| GPIO23 | SPI_MOSI | +| GPIO25 | SPI_MISO | +| GPIO22 | SPI_CS | +| GPIO4 | Interrupt | +| GPIO5 | Reset | + +## Common Configurations + +1. In the `Example Configuration` menu: + * Choose the kind of Ethernet under `Ethernet Type`. + * If `Internal EMAC` is selected: + * Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board. + * Set GPIO number used by SMI signal under `SMI MDC GPIO number` and `SMI MDIO GPIO number` respectively. + * If `DM9051 Module` is selected: + * Set SPI specific configuration, including SPI host number, GPIO number and clock rate. + * Set GPIO number used by PHY chip reset under `PHY Reset GPIO number`, you may have to change the default value according to your board schematic. **PHY hardware reset can be disabled by set this value to -1**. + * Set PHY address under `PHY Address`, you may have to change the default value according to your board schematic. + +2. In the `Component config > Ethernet` menu: + * Under `Support ESP32 internal EMAC controller` sub-menu: + * In the `PHY interface`, select `Reduced Media Independent Interface (RMII)`, ESP-IDF currently only support RMII mode. + * In the `RMII clock mode`, select one of the source that RMII clock (50MHz) comes from: `Input RMII clock from external` or `Output RMII clock from internal`. + * If `Output RMII clock from internal` is enabled, you also have to set the GPIO number that used to output the RMII clock, under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17. + * If `Output RMII clock from GPIO0 (Experimental!)` is also enabled, then you have no choice but GPIO0 to output the RMII clock. + * In `Amount of Ethernet DMA Rx buffers` and `Amount of Ethernet DMA Tx buffers`, you can set the amount of DMA buffers used for Tx and Rx. + * Under `Support SPI to Ethernet Module` sub-menu, select the SPI module that you used for this example. Currently ESP-IDF only supports `DM9051`. + +## Common Troubleshooting + +* The data panel between ESP32's MAC and PHY needs a fixed 50MHz clock to do synchronization, which also called RMII clock. It can either be provided by an external oscillator or generated from internal APLL. The signal integrity of RMII clock is strict, so keep the trace as short as possible! +* If the RMII clock is generated from internal APLL, then APLL can't be used for other purpose (e.g. I2S). diff --git a/examples/ethernet/basic/README.md b/examples/ethernet/basic/README.md index 8f5552dcf0..a2f49723a4 100644 --- a/examples/ethernet/basic/README.md +++ b/examples/ethernet/basic/README.md @@ -17,49 +17,29 @@ If you have a new Ethernet application to go (for example, connect to IoT cloud To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves. -`esp_eth` component not only supports ESP32 internal Ethernet MAC controller, but also can drive third-party Ethernet module which integrates MAC and PHY and provides SPI interface. This example also take the **DM9051** as an example, illustrating how to install the Ethernet driver with only a little different configuration. +Besides that, `esp_eth` component can drive third-party Ethernet module which integrates MAC and PHY and provides common communication interface (e.g. SPI, USB, etc). This example will take the **DM9051** as an example, illustrating how to install the Ethernet driver in the same manner. -### Project configuration in menuconfig +#### Pin Assignment -Enter `idf.py menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system. +See common pin assignments for Ethernet examples from [upper level](../README.md#common-pin-assignments). -1. In the `Example Configuration` menu: - * Choose the kind of Ethernet this example will run on under `Ethernet Type`. - * If `Internal EMAC` is selected: - * Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board. +### Configure the project - * If `SPI Ethernet Module` is selected: - * Set SPI specific configuration, including GPIO and clock speed. +``` +idf.py menuconfig +``` -2. In the `Component config > Ethernet` menu: - * If `Internal EMAC` is selected: - * Enable `Use ESP32 internal EMAC controller`, and then go into this menu. - * In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins. - * In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`. - * Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17. - * Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock. - * Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below: +See common configurations for Ethernet examples from [upper level](../README.md#common-configurations). - | Default Example GPIO | RMII Signal | Notes | - | -------------------- | ----------- | ------------- | - | GPIO23 | MDC | Output to PHY | - | GPIO18 | MDIO | Bidirectional | +### Build, Flash, and Run - * If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`. +Build the project and flash it to the board, then run monitor tool to view serial output: - * If `SPI Ethernet Module` is selected: - * Set the GPIO number used by interrupt pin under `DM9051 Interrupt GPIO number`. +``` +idf.py -p PORT build flash monitor +``` - -### Extra configuration in the code (Optional) - -* By default Ethernet driver will assume the PHY address to `1`, but you can alway reconfigure this value after `eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();`. The actual PHY address should depend on the hardware you use, so make sure to consult the schematic and datasheet. - -**Note:** DM9051 has a fixed PHY address `1`, which cannot be modified. - -### Build and Flash - -Enter `idf.py -p PORT flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you' are using CMake based build system. +(Replace PORT with the name of the serial port to use.) (To exit the serial monitor, type ``Ctrl-]``.) @@ -84,20 +64,6 @@ Now you can ping your ESP32 in the terminal by entering `ping 192.168.2.151` (it ## Troubleshooting -* RMII Clock - * ESP32's MAC and the external PHY device need a common 50MHz reference clock (aka RMII clock). This clock can either be provided by an externally oscillator or generated from internal APLL. The signal integrity of RMII clock is strict, so it is highly recommended to add a 33Ω resistor in series to reduce possible ringing. - * ESP32 can generate a 50MHz clock using internal APLL. But if the APLL is already used for other purposes (e.g. I2S peripheral), then you have no choice but use an external RMII clock. - -* GPIO connections - * RMII PHY wiring is fixed and can not be changed through either IOMUX or GPIO Matrix. They're described as below: - - | GPIO | RMII Signal | ESP32 EMAC Function | - | ------ | ----------- | ------------------- | - | GPIO21 | TX_EN | EMAC_TX_EN | - | GPIO19 | TX0 | EMAC_TXD0 | - | GPIO22 | TX1 | EMAC_TXD1 | - | GPIO25 | RX0 | EMAC_RXD0 | - | GPIO26 | RX1 | EMAC_RXD1 | - | GPIO27 | CRS_DV | EMAC_RX_DRV | +See common troubleshooting for Ethernet examples from [upper level](../README.md#common-troubleshooting). (For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.) diff --git a/examples/ethernet/eth2ap/README.md b/examples/ethernet/eth2ap/README.md index 16a43d6d36..73a8e67bec 100644 --- a/examples/ethernet/eth2ap/README.md +++ b/examples/ethernet/eth2ap/README.md @@ -10,56 +10,39 @@ The similarities on MAC layer between Ethernet and Wi-Fi make it easy to forward **Note:** In this example, ESP32 works like a *bridge* between Ethernet and Wi-Fi, and it won't perform any actions on Layer3 and higher layer, which means there's no need to initialize the TCP/IP stack. -## How to use this example +## How to use example ### Hardware Required To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves. -`esp_eth` component not only supports ESP32 internal Ethernet MAC controller, but also can drive third-party Ethernet module which integrates MAC and PHY and provides SPI interface. This example also take the **DM9051** as an example, illustrating how to install the Ethernet driver with only a little different configuration. +Besides that, `esp_eth` component can drive third-party Ethernet module which integrates MAC and PHY and provides common communication interface (e.g. SPI, USB, etc). This example will take the **DM9051** as an example, illustrating how to install the Ethernet driver in the same manner. -### Project configuration in menuconfig +#### Pin Assignment -Open the project configuration menu (`idf.py menuconfig`). +See common pin assignments for Ethernet examples from [upper level](../README.md#common-pin-assignments). -1. In the `Example Configuration` menu: - * Set the SSID and password for Wi-Fi ap interface under `Wi-Fi SSID` and `Wi-Fi Password`. - * Set the maximum connection number under `Maximum STA connections`. - * Choose the kind of Ethernet this example will run on under `Ethernet Type`. - * If `Internal EMAC` is selected: - * Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board. +### Configure the project - * If `SPI Ethernet Module` is selected: - * Set SPI specific configuration, including GPIO and clock speed. +``` +idf.py menuconfig +``` -2. In the `Component config > Ethernet` menu: - * If `Internal EMAC` is selected: - * Enable `Use ESP32 internal EMAC controller`, and then go into this menu. - * In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins. - * In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`. - * Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17. - * Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock. - * Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below: +In addition to the common configurations for Ethernet examples from [upper level](../README.md#common-configurations), you might also need to update the default value of following configurations: - | Default Example GPIO | RMII Signal | Notes | - | -------------------- | ----------- | ------------- | - | GPIO23 | MDC | Output to PHY | - | GPIO18 | MDIO | Bidirectional | +In the `Example Configuration` menu: +* Set the SSID and password for Wi-Fi ap interface under `Wi-Fi SSID` and `Wi-Fi Password`. +* Set the maximum connection number under `Maximum STA connections`. - * If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`. +### Build, Flash, and Run - * If `SPI Ethernet Module` is selected: - * Set the GPIO number used by interrupt pin under `DM9051 Interrupt GPIO number`. +Build the project and flash it to the board, then run monitor tool to view serial output: -### Extra configuration in the code (Optional) +``` +idf.py -p PORT build flash monitor +``` -* By default Ethernet driver will assume the PHY address to `1`, but you can alway reconfigure this value after `eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();`. The actual PHY address should depend on the hardware you use, so make sure to consult the schematic and datasheet.peripheral (e.g. I²S), you'd better choose the external clock. - -**Note:** DM9051 has a fixed PHY address `1`, which cannot be modified. - -### Build and Flash - -To build and flash the example, enter `idf.py -p PORT flash monitor`. +(Replace PORT with the name of the serial port to use.) (To exit the serial monitor, type ``Ctrl-]``.) @@ -118,29 +101,11 @@ Now your mobile phone should get access to the Internet. ## Troubleshooting -* RMII Clock - * ESP32's MAC and the external PHY device need a common 50MHz reference clock (aka RMII clock). This clock can either be provided by an externally oscillator or generated from internal APLL. The signal integrity of RMII clock is strict, so it is highly recommended to add a 33Ω resistor in series to reduce possible ringing. - * ESP32 can generate a 50MHz clock using internal APLL. But if the APLL is already used for other purposes (e.g. I2S peripheral), then you have no choice but use an external RMII clock. +See common troubleshooting for Ethernet examples from [upper level](../README.md#common-troubleshooting). -* GPIO connections - * RMII PHY wiring is fixed and can not be changed through either IOMUX or GPIO Matrix. They're described as below: - - | GPIO | RMII Signal | ESP32 EMAC Function | - | ------ | ----------- | ------------------- | - | GPIO21 | TX_EN | EMAC_TX_EN | - | GPIO19 | TX0 | EMAC_TXD0 | - | GPIO22 | TX1 | EMAC_TXD1 | - | GPIO25 | RX0 | EMAC_RXD0 | - | GPIO26 | RX1 | EMAC_RXD1 | - | GPIO27 | CRS_DV | EMAC_RX_DRV | - -* Got error message `WiFi send packet failed` when running the example. - * Ethernet process packets faster than Wi-Fi on ESP32, so have a try to enlarge the value of `FLOW_CONTROL_WIFI_SEND_DELAY_MS`. - -* Got error message `send flow control message failed or timeout` when running the example. - * Enlarge the length of `FLOW_CONTROL_QUEUE_LENGTH`. - -* Wi-Fi station doesn't receive any IP via DHCP. +* If you got error message like `WiFi send packet failed` when running the example, you may need to enlarge the value of `FLOW_CONTROL_WIFI_SEND_DELAY_MS` in "ethernet_example_main.c", because Ethernet process packets faster than Wi-Fi on ESP32. +* If you got error message like `send flow control message failed or timeout` when running the example, you may need to enlarge the value of `FLOW_CONTROL_QUEUE_LENGTH` in "ethernet_example_main". +* Wi-Fi station doesn't receive any IP via DHCP? * All Layer 3 (TCP/IP functions) on the ESP32 are disabled, including the SoftAP DHCP server. This means that devices must be able to access another DHCP server (for example on a Wi-Fi router connected via ethernet) or should use statically assigned IP addresses. (For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.) diff --git a/examples/ethernet/iperf/README.md b/examples/ethernet/iperf/README.md index b33bab61d7..053230e01f 100644 --- a/examples/ethernet/iperf/README.md +++ b/examples/ethernet/iperf/README.md @@ -14,56 +14,39 @@ The cli environment in the example is based on the [console component](https://d To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves. -`esp_eth` component not only supports ESP32 internal Ethernet MAC controller, but also can drive third-party Ethernet module which integrates MAC and PHY and provides SPI interface. This example also take the **DM9051** as an example, illustrating how to install the Ethernet driver with only a little different configuration. +Besides that, `esp_eth` component can drive third-party Ethernet module which integrates MAC and PHY and provides common communication interface (e.g. SPI, USB, etc). This example will take the **DM9051** as an example, illustrating how to install the Ethernet driver in the same manner. -### Other Preparation +#### Pin Assignment + +See common pin assignments for Ethernet examples from [upper level](../README.md#common-pin-assignments). + +### Software Tools Preparation 1. Install iperf tool on PC * Debian/Ubuntu: `sudo apt-get install iperf` * macOS: `brew install iperf`(if using Homebrew) or `sudo port install iperf`(if using MacPorts) * Windows(MSYS2): Downloads binaries from [here]( https://iperf.fr/iperf-download.php#windows) -### Project configuration in menuconfig +### Configure the project -Enter `idf.py menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system. +``` +idf.py menuconfig +``` + +In addition to the common configurations for Ethernet examples from [upper level](../README.md#common-configurations), you might also need to update the default value of following configurations: 1. In the `Example Configuration` menu: * Enable storing history commands in flash under `Store command history in flash`. - * Choose the kind of Ethernet this example will run on under `Ethernet Type`. - * If `Internal EMAC` is selected: - * Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board. - * If `SPI Ethernet Module` is selected: - * Set SPI specific configuration, including GPIO and clock speed. +### Build, Flash, and Run -2. In the `Component config > Ethernet` menu: - * If `Internal EMAC` is selected: - * Enable `Use ESP32 internal EMAC controller`, and then go into this menu. - * In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins. - * In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`. - * Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17. - * Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock. - * Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below: +Build the project and flash it to the board, then run monitor tool to view serial output: - | Default Example GPIO | RMII Signal | Notes | - | -------------------- | ----------- | ------------- | - | GPIO23 | MDC | Output to PHY | - | GPIO18 | MDIO | Bidirectional | +``` +idf.py -p PORT build flash monitor +``` - * If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`. - - * If `SPI Ethernet Module` is selected: - * Set the GPIO number used by interrupt pin under `DM9051 Interrupt GPIO number`. - -### Extra configuration in the code (Optional) - -* By default Ethernet driver will assume the PHY address to `1`, but you can alway reconfigure this value after `eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();`. The actual PHY address should depend on the hardware you use, so make sure to consult the schematic and datasheet. - -**Note:** DM9051 has a fixed PHY address `1`, which cannot be modified. - -### Build and Flash - -Enter `idf.py -p PORT flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you' are using CMake based build system. +(Replace PORT with the name of the serial port to use.) (To exit the serial monitor, type ``Ctrl-]``.) @@ -168,20 +151,6 @@ I (2534456) iperf: want recv=16384 ## Troubleshooting -* RMII Clock - * ESP32's MAC and the external PHY device need a common 50MHz reference clock (aka RMII clock). This clock can either be provided by an externally oscillator or generated from internal APLL. The signal integrity of RMII clock is strict, so it is highly recommended to add a 33Ω resistor in series to reduce possible ringing. - * ESP32 can generate a 50MHz clock using internal APLL. But if the APLL is already used for other purposes (e.g. I2S peripheral), then you have no choice but use an external RMII clock. - -* GPIO connections - * RMII PHY wiring is fixed and can not be changed through either IOMUX or GPIO Matrix. They're described as below: - - | GPIO | RMII Signal | ESP32 EMAC Function | - | ------ | ----------- | ------------------- | - | GPIO21 | TX_EN | EMAC_TX_EN | - | GPIO19 | TX0 | EMAC_TXD0 | - | GPIO22 | TX1 | EMAC_TXD1 | - | GPIO25 | RX0 | EMAC_RXD0 | - | GPIO26 | RX1 | EMAC_RXD1 | - | GPIO27 | CRS_DV | EMAC_RX_DRV | +See common troubleshooting for Ethernet examples from [upper level](../README.md#common-troubleshooting). (For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.) From 37154d4c08b57c2b5410138a4c516ff5ecf93e2b Mon Sep 17 00:00:00 2001 From: morris Date: Wed, 27 Nov 2019 21:38:27 +0800 Subject: [PATCH 3/6] ethernet:add reference counter --- components/esp_eth/CMakeLists.txt | 3 +++ components/esp_eth/component.mk | 3 +++ components/esp_eth/include/esp_eth.h | 29 +++++++++++++++++++++++++ components/esp_eth/src/esp_eth.c | 30 ++++++++++++++++++++++++++ components/esp_eth/test/test_emac.c | 32 +++++++++++++++++++++++----- 5 files changed, 92 insertions(+), 5 deletions(-) diff --git a/components/esp_eth/CMakeLists.txt b/components/esp_eth/CMakeLists.txt index ed9845218f..147caf9888 100644 --- a/components/esp_eth/CMakeLists.txt +++ b/components/esp_eth/CMakeLists.txt @@ -17,3 +17,6 @@ idf_component_register(SRCS "${esp_eth_srcs}" INCLUDE_DIRS "include" REQUIRES "esp_event" PRIV_REQUIRES "tcpip_adapter" "driver" "log") + +# uses C11 atomic feature +set_source_files_properties(src/esp_eth.c PROPERTIES COMPILE_FLAGS -std=gnu11) diff --git a/components/esp_eth/component.mk b/components/esp_eth/component.mk index a9c95f19af..c9991de515 100644 --- a/components/esp_eth/component.mk +++ b/components/esp_eth/component.mk @@ -11,3 +11,6 @@ endif ifndef CONFIG_ETH_SPI_ETHERNET_DM9051 COMPONENT_OBJEXCLUDE += src/esp_eth_mac_dm9051.o src/esp_eth_phy_dm9051.o endif + +# uses C11 atomic feature +src/esp_eth.o: CFLAGS += -std=gnu11 diff --git a/components/esp_eth/include/esp_eth.h b/components/esp_eth/include/esp_eth.h index cf4b570502..6f4cb0fad5 100644 --- a/components/esp_eth/include/esp_eth.h +++ b/components/esp_eth/include/esp_eth.h @@ -117,12 +117,16 @@ esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_ /** * @brief Uninstall Ethernet driver +* @note It's not recommended to uninstall Ethernet driver unless it won't get used any more in application code. +* To uninstall Ethernet driver, you have to make sure, all references to the driver are released. +* Ethernet driver can only be uninstalled successfully when reference counter equals to one. * * @param[in] hdl: handle of Ethernet driver * * @return * - ESP_OK: uninstall esp_eth driver successfully * - ESP_ERR_INVALID_ARG: uninstall esp_eth driver failed because of some invalid argument +* - ESP_ERR_INVALID_STATE: uninstall esp_eth driver failed because it has more than one reference * - ESP_FAIL: uninstall esp_eth driver failed because some other error occurred */ esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl); @@ -169,6 +173,31 @@ esp_err_t esp_eth_receive(esp_eth_handle_t hdl, uint8_t *buf, uint32_t *length); */ esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data); +/** +* @brief Increase Ethernet driver reference +* @note Ethernet driver handle can be obtained by os timer, netif, etc. +* It's dangerous when thread A is using Ethernet but thread B uninstall the driver. +* Using reference counter can prevent such risk, but care should be taken, when you obtain Ethernet driver, +* this API must be invoked so that the driver won't be uninstalled during your using time. +* +* +* @param[in] hdl: handle of Ethernet driver +* @return +* - ESP_OK: increase reference successfully +* - ESP_ERR_INVALID_ARG: increase reference failed because of some invalid argument +*/ +esp_err_t esp_eth_increase_reference(esp_eth_handle_t hdl); + +/** +* @brief Decrease Ethernet driver reference +* +* @param[in] hdl: handle of Ethernet driver +* @return +* - ESP_OK: increase reference successfully +* - ESP_ERR_INVALID_ARG: increase reference failed because of some invalid argument +*/ +esp_err_t esp_eth_decrease_reference(esp_eth_handle_t hdl); + #ifdef __cplusplus } #endif diff --git a/components/esp_eth/src/esp_eth.c b/components/esp_eth/src/esp_eth.c index ea813687d4..9444f6b32b 100644 --- a/components/esp_eth/src/esp_eth.c +++ b/components/esp_eth/src/esp_eth.c @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #include +#include #include "esp_log.h" #include "esp_eth.h" #include "esp_event.h" @@ -51,6 +52,7 @@ typedef struct { eth_speed_t speed; eth_duplex_t duplex; eth_link_t link; + atomic_int ref_count; esp_err_t (*stack_input)(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length); esp_err_t (*on_lowlevel_init_done)(esp_eth_handle_t eth_handle); esp_err_t (*on_lowlevel_deinit_done)(esp_eth_handle_t eth_handle); @@ -145,7 +147,9 @@ static void eth_check_link_timer_cb(TimerHandle_t xTimer) { esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)pvTimerGetTimerID(xTimer); esp_eth_phy_t *phy = eth_driver->phy; + esp_eth_increase_reference(eth_driver); phy->get_link(phy); + esp_eth_decrease_reference(eth_driver); } ////////////////////////////////User face APIs//////////////////////////////////////////////// @@ -164,6 +168,7 @@ esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_ ETH_CHECK(mac && phy, "can't set eth->mac or eth->phy to null", err, ESP_ERR_INVALID_ARG); esp_eth_driver_t *eth_driver = calloc(1, sizeof(esp_eth_driver_t)); ETH_CHECK(eth_driver, "request memory for eth_driver failed", err, ESP_ERR_NO_MEM); + atomic_init(ð_driver->ref_count, 1); eth_driver->mac = mac; eth_driver->phy = phy; eth_driver->link = ETH_LINK_DOWN; @@ -210,6 +215,9 @@ esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl) esp_err_t ret = ESP_OK; esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG); + // don't uninstall driver unless there's only one reference + ETH_CHECK(atomic_load(ð_driver->ref_count) == 1, + "more than one reference to ethernet driver", err, ESP_ERR_INVALID_STATE); esp_eth_mac_t *mac = eth_driver->mac; esp_eth_phy_t *phy = eth_driver->phy; ETH_CHECK(xTimerDelete(eth_driver->check_link_timer, 0) == pdPASS, "delete eth_link_timer failed", err, ESP_FAIL); @@ -284,3 +292,25 @@ esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data) err: return ret; } + +esp_err_t esp_eth_increase_reference(esp_eth_handle_t hdl) +{ + esp_err_t ret = ESP_OK; + esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; + ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG); + atomic_fetch_add(ð_driver->ref_count, 1); + return ESP_OK; +err: + return ret; +} + +esp_err_t esp_eth_decrease_reference(esp_eth_handle_t hdl) +{ + esp_err_t ret = ESP_OK; + esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; + ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG); + atomic_fetch_sub(ð_driver->ref_count, 1); + return ESP_OK; +err: + return ret; +} diff --git a/components/esp_eth/test/test_emac.c b/components/esp_eth/test/test_emac.c index 78995d8c5e..3a036518fb 100644 --- a/components/esp_eth/test/test_emac.c +++ b/components/esp_eth/test/test_emac.c @@ -67,6 +67,24 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base, xEventGroupSetBits(eth_event_group, ETH_GOT_IP_BIT); } + +static esp_err_t test_uninstall_driver(esp_eth_handle_t eth_hdl, uint32_t ms_to_wait) +{ + int i = 0; + ms_to_wait += 100; + for (i = 0; i < ms_to_wait / 100; i++) { + vTaskDelay(pdMS_TO_TICKS(100)); + if (esp_eth_driver_uninstall(eth_hdl) == ESP_OK) { + break; + } + } + if (i < ms_to_wait / 10) { + return ESP_OK; + } else { + return ESP_FAIL; + } +} + TEST_CASE("esp32 ethernet io test", "[ethernet][test_env=UT_T2_Ethernet]") { TEST_ESP_OK(esp_event_loop_create_default()); @@ -90,7 +108,8 @@ TEST_CASE("esp32 ethernet io test", "[ethernet][test_env=UT_T2_Ethernet]") TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_PHY_ADDR, &phy_addr)); ESP_LOGI(TAG, "Ethernet PHY Address: %d", phy_addr); TEST_ASSERT(phy_addr >= 0 && phy_addr <= 31); - TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle)); + /* driver should be uninstalled within 2 seconds */ + TEST_ESP_OK(test_uninstall_driver(eth_handle, 2000)); TEST_ESP_OK(phy->del(phy)); TEST_ESP_OK(mac->del(mac)); TEST_ESP_OK(esp_event_loop_delete_default()); @@ -116,7 +135,8 @@ TEST_CASE("esp32 ethernet event test", "[ethernet][test_env=UT_T2_Ethernet]") /* wait for connection establish */ bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS)); TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT); - TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle)); + /* driver should be uninstalled within 2 seconds */ + TEST_ESP_OK(test_uninstall_driver(eth_handle, 2000)); /* wait for connection stop */ bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS)); TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT); @@ -149,7 +169,8 @@ TEST_CASE("esp32 ethernet dhcp test", "[ethernet][test_env=UT_T2_Ethernet]") /* wait for IP lease */ bits = xEventGroupWaitBits(eth_event_group, ETH_GOT_IP_BIT, true, true, pdMS_TO_TICKS(ETH_GET_IP_TIMEOUT_MS)); TEST_ASSERT((bits & ETH_GOT_IP_BIT) == ETH_GOT_IP_BIT); - TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle)); + /* driver should be uninstalled within 2 seconds */ + TEST_ESP_OK(test_uninstall_driver(eth_handle, 2000)); /* wait for connection stop */ bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS)); TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT); @@ -186,7 +207,7 @@ TEST_CASE("dm9051 io test", "[ethernet][ignore]") }; TEST_ESP_OK(spi_bus_add_device(HSPI_HOST, &devcfg, &spi_handle)); gpio_install_isr_service(0); - tcpip_adapter_init(); + test_case_uses_tcpip(); TEST_ESP_OK(esp_event_loop_create_default()); TEST_ESP_OK(tcpip_adapter_set_default_eth_handlers()); TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL)); @@ -200,7 +221,8 @@ TEST_CASE("dm9051 io test", "[ethernet][ignore]") esp_eth_handle_t eth_handle = NULL; TEST_ESP_OK(esp_eth_driver_install(&config, ð_handle)); vTaskDelay(pdMS_TO_TICKS(portMAX_DELAY)); - TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle)); + /* driver should be uninstalled within 2 seconds */ + TEST_ESP_OK(test_uninstall_driver(eth_handle, 2000)); TEST_ESP_OK(phy->del(phy)); TEST_ESP_OK(mac->del(mac)); TEST_ESP_OK(esp_event_loop_delete_default()); From 96e6049dabf0fb836be3802985448b136bcd382d Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 28 Nov 2019 13:42:14 +0800 Subject: [PATCH 4/6] ethernet:add start stop control --- components/esp_eth/include/esp_eth.h | 29 +++++++++ components/esp_eth/src/esp_eth.c | 58 ++++++++++++++--- components/esp_eth/src/esp_eth_phy_dm9051.c | 1 + components/esp_eth/src/esp_eth_phy_dp83848.c | 1 + components/esp_eth/src/esp_eth_phy_ip101.c | 1 + components/esp_eth/src/esp_eth_phy_lan8720.c | 1 + components/esp_eth/src/esp_eth_phy_rtl8201.c | 1 + components/esp_eth/test/test_emac.c | 65 +++++++++++++++---- .../protocol_examples_common/connect.c | 2 + .../basic/main/ethernet_example_main.c | 1 + .../eth2ap/main/ethernet_example_main.c | 1 + examples/ethernet/iperf/main/cmd_ethernet.c | 1 + 12 files changed, 142 insertions(+), 20 deletions(-) diff --git a/components/esp_eth/include/esp_eth.h b/components/esp_eth/include/esp_eth.h index 6f4cb0fad5..a093c6e830 100644 --- a/components/esp_eth/include/esp_eth.h +++ b/components/esp_eth/include/esp_eth.h @@ -131,6 +131,35 @@ esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_ */ esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl); +/** +* @brief Start Ethernet driver +* +* @note This API will start driver state machine and internal software timer (for checking link status). +* +* @param[in] hdl handle of Ethernet driver +* +* @return +* - ESP_OK: start esp_eth driver successfully +* - ESP_ERR_INVALID_ARG: start esp_eth driver failed because of some invalid argument +* - ESP_ERR_INVALID_STATE: start esp_eth driver failed because driver has started already +* - ESP_FAIL: start esp_eth driver failed because some other error occurred +*/ +esp_err_t esp_eth_start(esp_eth_handle_t hdl); + +/** +* @brief Stop Ethernet driver +* +* @note This function does the oppsite operation of `esp_eth_start`. +* +* @param[in] hdl handle of Ethernet driver +* @return +* - ESP_OK: stop esp_eth driver successfully +* - ESP_ERR_INVALID_ARG: stop esp_eth driver failed because of some invalid argument +* - ESP_ERR_INVALID_STATE: stop esp_eth driver failed because driver has not started yet +* - ESP_FAIL: stop esp_eth driver failed because some other error occurred +*/ +esp_err_t esp_eth_stop(esp_eth_handle_t hdl); + /** * @brief General Transmit * diff --git a/components/esp_eth/src/esp_eth.c b/components/esp_eth/src/esp_eth.c index 9444f6b32b..0a8395957c 100644 --- a/components/esp_eth/src/esp_eth.c +++ b/components/esp_eth/src/esp_eth.c @@ -34,6 +34,8 @@ static const char *TAG = "esp_eth"; ESP_EVENT_DEFINE_BASE(ETH_EVENT); +#define ESP_ETH_FLAGS_STARTED (1<<0) + /** * @brief The Ethernet driver mainly consists of PHY, MAC and * the mediator who will handle the request/response from/to MAC, PHY and Users. @@ -53,6 +55,7 @@ typedef struct { eth_duplex_t duplex; eth_link_t link; atomic_int ref_count; + uint32_t flags; esp_err_t (*stack_input)(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length); esp_err_t (*on_lowlevel_init_done)(esp_eth_handle_t eth_handle); esp_err_t (*on_lowlevel_deinit_done)(esp_eth_handle_t eth_handle); @@ -190,15 +193,8 @@ esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_ eth_driver->check_link_timer = xTimerCreate("eth_link_timer", pdMS_TO_TICKS(config->check_link_period_ms), pdTRUE, eth_driver, eth_check_link_timer_cb); ETH_CHECK(eth_driver->check_link_timer, "create eth_link_timer failed", err_create_timer, ESP_FAIL); - ETH_CHECK(xTimerStart(eth_driver->check_link_timer, 0) == pdPASS, "start eth_link_timer failed", err_start_timer, ESP_FAIL); - ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_START, ð_driver, sizeof(eth_driver), 0) == ESP_OK, - "send ETHERNET_EVENT_START event failed", err_event, ESP_FAIL); *out_hdl = (esp_eth_handle_t)eth_driver; return ESP_OK; -err_event: - xTimerStop(eth_driver->check_link_timer, 0); -err_start_timer: - xTimerDelete(eth_driver->check_link_timer, 0); err_create_timer: phy->deinit(phy); err_init_phy: @@ -221,8 +217,6 @@ esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl) esp_eth_mac_t *mac = eth_driver->mac; esp_eth_phy_t *phy = eth_driver->phy; ETH_CHECK(xTimerDelete(eth_driver->check_link_timer, 0) == pdPASS, "delete eth_link_timer failed", err, ESP_FAIL); - ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_STOP, ð_driver, sizeof(eth_driver), 0) == ESP_OK, - "send ETHERNET_EVENT_STOP event failed", err, ESP_FAIL); ETH_CHECK(phy->deinit(phy) == ESP_OK, "deinit phy failed", err, ESP_FAIL); ETH_CHECK(mac->deinit(mac) == ESP_OK, "deinit mac failed", err, ESP_FAIL); free(eth_driver); @@ -231,6 +225,52 @@ err: return ret; } +esp_err_t esp_eth_start(esp_eth_handle_t hdl) +{ + esp_err_t ret = ESP_OK; + esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; + ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG); + // check if driver has started + if (eth_driver->flags & ESP_ETH_FLAGS_STARTED) { + ESP_LOGW(TAG, "driver started already"); + ret = ESP_ERR_INVALID_STATE; + goto err; + } + eth_driver->flags |= ESP_ETH_FLAGS_STARTED; + ETH_CHECK(eth_driver->phy->reset(eth_driver->phy) == ESP_OK, "reset phy failed", err, ESP_FAIL); + ETH_CHECK(xTimerStart(eth_driver->check_link_timer, 0) == pdPASS, + "start eth_link_timer failed", err, ESP_FAIL); + ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_START, ð_driver, sizeof(eth_driver), 0) == ESP_OK, + "send ETHERNET_EVENT_START event failed", err_event, ESP_FAIL); + return ESP_OK; +err_event: + xTimerStop(eth_driver->check_link_timer, 0); +err: + return ret; +} + +esp_err_t esp_eth_stop(esp_eth_handle_t hdl) +{ + esp_err_t ret = ESP_OK; + esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; + ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG); + // check if driver has started + if (eth_driver->flags & ESP_ETH_FLAGS_STARTED) { + eth_driver->flags &= ~ESP_ETH_FLAGS_STARTED; + ETH_CHECK(xTimerStop(eth_driver->check_link_timer, 0) == pdPASS, + "stop eth_link_timer failed", err, ESP_FAIL); + ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_STOP, ð_driver, sizeof(eth_driver), 0) == ESP_OK, + "send ETHERNET_EVENT_STOP event failed", err, ESP_FAIL); + } else { + ESP_LOGW(TAG, "driver not started yet"); + ret = ESP_ERR_INVALID_STATE; + goto err; + } + return ESP_OK; +err: + return ret; +} + esp_err_t esp_eth_transmit(esp_eth_handle_t hdl, uint8_t *buf, uint32_t length) { esp_err_t ret = ESP_OK; diff --git a/components/esp_eth/src/esp_eth_phy_dm9051.c b/components/esp_eth/src/esp_eth_phy_dm9051.c index b7d167b5ed..d423b6ba15 100644 --- a/components/esp_eth/src/esp_eth_phy_dm9051.c +++ b/components/esp_eth/src/esp_eth_phy_dm9051.c @@ -122,6 +122,7 @@ err: static esp_err_t dm9051_reset(esp_eth_phy_t *phy) { phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + dm9051->link_status = ETH_LINK_DOWN; esp_eth_mediator_t *eth = dm9051->eth; dscr_reg_t dscr; PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, "read DSCR failed", err); diff --git a/components/esp_eth/src/esp_eth_phy_dp83848.c b/components/esp_eth/src/esp_eth_phy_dp83848.c index e62ced932d..520d7ae0cb 100644 --- a/components/esp_eth/src/esp_eth_phy_dp83848.c +++ b/components/esp_eth/src/esp_eth_phy_dp83848.c @@ -128,6 +128,7 @@ err: static esp_err_t dp83848_reset(esp_eth_phy_t *phy) { phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); + dp83848->link_status = ETH_LINK_DOWN; esp_eth_mediator_t *eth = dp83848->eth; bmcr_reg_t bmcr = {.reset = 1}; PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); diff --git a/components/esp_eth/src/esp_eth_phy_ip101.c b/components/esp_eth/src/esp_eth_phy_ip101.c index 3fb51d1ea0..847fc65137 100644 --- a/components/esp_eth/src/esp_eth_phy_ip101.c +++ b/components/esp_eth/src/esp_eth_phy_ip101.c @@ -157,6 +157,7 @@ err: static esp_err_t ip101_reset(esp_eth_phy_t *phy) { phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); + ip101->link_status = ETH_LINK_DOWN; esp_eth_mediator_t *eth = ip101->eth; bmcr_reg_t bmcr = {.reset = 1}; PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); diff --git a/components/esp_eth/src/esp_eth_phy_lan8720.c b/components/esp_eth/src/esp_eth_phy_lan8720.c index 98a91e10ab..f513b44818 100644 --- a/components/esp_eth/src/esp_eth_phy_lan8720.c +++ b/components/esp_eth/src/esp_eth_phy_lan8720.c @@ -200,6 +200,7 @@ err: static esp_err_t lan8720_reset(esp_eth_phy_t *phy) { phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); + lan8720->link_status = ETH_LINK_DOWN; esp_eth_mediator_t *eth = lan8720->eth; bmcr_reg_t bmcr = {.reset = 1}; PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); diff --git a/components/esp_eth/src/esp_eth_phy_rtl8201.c b/components/esp_eth/src/esp_eth_phy_rtl8201.c index 7b97a12342..bbd4aae05a 100644 --- a/components/esp_eth/src/esp_eth_phy_rtl8201.c +++ b/components/esp_eth/src/esp_eth_phy_rtl8201.c @@ -118,6 +118,7 @@ err: static esp_err_t rtl8201_reset(esp_eth_phy_t *phy) { phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); + rtl8201->link_status = ETH_LINK_DOWN; esp_eth_mediator_t *eth = rtl8201->eth; bmcr_reg_t bmcr = {.reset = 1}; PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); diff --git a/components/esp_eth/test/test_emac.c b/components/esp_eth/test/test_emac.c index 3a036518fb..fae610a69f 100644 --- a/components/esp_eth/test/test_emac.c +++ b/components/esp_eth/test/test_emac.c @@ -87,7 +87,6 @@ static esp_err_t test_uninstall_driver(esp_eth_handle_t eth_hdl, uint32_t ms_to_ TEST_CASE("esp32 ethernet io test", "[ethernet][test_env=UT_T2_Ethernet]") { - TEST_ESP_OK(esp_event_loop_create_default()); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); @@ -95,7 +94,6 @@ TEST_CASE("esp32 ethernet io test", "[ethernet][test_env=UT_T2_Ethernet]") esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_handle_t eth_handle = NULL; TEST_ESP_OK(esp_eth_driver_install(ð_config, ð_handle)); - vTaskDelay(pdMS_TO_TICKS(1000)); /* get MAC address */ uint8_t mac_addr[6]; memset(mac_addr, 0, sizeof(mac_addr)); @@ -112,7 +110,6 @@ TEST_CASE("esp32 ethernet io test", "[ethernet][test_env=UT_T2_Ethernet]") TEST_ESP_OK(test_uninstall_driver(eth_handle, 2000)); TEST_ESP_OK(phy->del(phy)); TEST_ESP_OK(mac->del(mac)); - TEST_ESP_OK(esp_event_loop_delete_default()); } TEST_CASE("esp32 ethernet event test", "[ethernet][test_env=UT_T2_Ethernet]") @@ -129,19 +126,20 @@ TEST_CASE("esp32 ethernet event test", "[ethernet][test_env=UT_T2_Ethernet]") esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_handle_t eth_handle = NULL; TEST_ESP_OK(esp_eth_driver_install(ð_config, ð_handle)); + TEST_ESP_OK(esp_eth_start(eth_handle)); /* wait for connection start */ bits = xEventGroupWaitBits(eth_event_group, ETH_START_BIT, true, true, pdMS_TO_TICKS(ETH_START_TIMEOUT_MS)); TEST_ASSERT((bits & ETH_START_BIT) == ETH_START_BIT); /* wait for connection establish */ bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS)); TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT); - /* driver should be uninstalled within 2 seconds */ - TEST_ESP_OK(test_uninstall_driver(eth_handle, 2000)); + // stop Ethernet driver + TEST_ESP_OK(esp_eth_stop(eth_handle)); /* wait for connection stop */ bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS)); TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT); - // "check link timer callback" might owned the reference of phy object, make sure it has release it - vTaskDelay(pdMS_TO_TICKS(2000)); + /* driver should be uninstalled within 2 seconds */ + TEST_ESP_OK(test_uninstall_driver(eth_handle, 2000)); TEST_ESP_OK(phy->del(phy)); TEST_ESP_OK(mac->del(mac)); TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler)); @@ -166,16 +164,58 @@ TEST_CASE("esp32 ethernet dhcp test", "[ethernet][test_env=UT_T2_Ethernet]") esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_handle_t eth_handle = NULL; TEST_ESP_OK(esp_eth_driver_install(ð_config, ð_handle)); + TEST_ESP_OK(esp_eth_start(eth_handle)); /* wait for IP lease */ bits = xEventGroupWaitBits(eth_event_group, ETH_GOT_IP_BIT, true, true, pdMS_TO_TICKS(ETH_GET_IP_TIMEOUT_MS)); TEST_ASSERT((bits & ETH_GOT_IP_BIT) == ETH_GOT_IP_BIT); - /* driver should be uninstalled within 2 seconds */ - TEST_ESP_OK(test_uninstall_driver(eth_handle, 2000)); + // stop Ethernet driver + TEST_ESP_OK(esp_eth_stop(eth_handle)); /* wait for connection stop */ bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS)); TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT); - // "check link timer callback" might owned the reference of phy object, make sure it has release it - vTaskDelay(pdMS_TO_TICKS(2000)); + /* driver should be uninstalled within 2 seconds */ + TEST_ESP_OK(test_uninstall_driver(eth_handle, 2000)); + TEST_ESP_OK(phy->del(phy)); + TEST_ESP_OK(mac->del(mac)); + TEST_ESP_OK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler)); + TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler)); + TEST_ESP_OK(tcpip_adapter_clear_default_eth_handlers()); + TEST_ESP_OK(esp_event_loop_delete_default()); + vEventGroupDelete(eth_event_group); +} + +TEST_CASE("esp32 ethernet start/stop stress test", "[ethernet][test_env=UT_T2_Ethernet][timeout=240]") +{ + EventBits_t bits = 0; + EventGroupHandle_t eth_event_group = xEventGroupCreate(); + TEST_ASSERT(eth_event_group != NULL); + test_case_uses_tcpip(); + TEST_ESP_OK(esp_event_loop_create_default()); + TEST_ESP_OK(tcpip_adapter_set_default_eth_handlers()); + TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, eth_event_group)); + TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, eth_event_group)); + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); + esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); + esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); + esp_eth_handle_t eth_handle = NULL; + TEST_ESP_OK(esp_eth_driver_install(ð_config, ð_handle)); + + for (int i = 0; i < 10; i++) { + TEST_ESP_OK(esp_eth_start(eth_handle)); + /* wait for IP lease */ + bits = xEventGroupWaitBits(eth_event_group, ETH_GOT_IP_BIT, true, true, pdMS_TO_TICKS(ETH_GET_IP_TIMEOUT_MS)); + TEST_ASSERT((bits & ETH_GOT_IP_BIT) == ETH_GOT_IP_BIT); + // stop Ethernet driver + TEST_ESP_OK(esp_eth_stop(eth_handle)); + /* wait for connection stop */ + bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS)); + TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT); + } + + /* driver should be uninstalled within 2 seconds */ + TEST_ESP_OK(test_uninstall_driver(eth_handle, 2000)); TEST_ESP_OK(phy->del(phy)); TEST_ESP_OK(mac->del(mac)); TEST_ESP_OK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler)); @@ -220,7 +260,10 @@ TEST_CASE("dm9051 io test", "[ethernet][ignore]") esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_handle_t eth_handle = NULL; TEST_ESP_OK(esp_eth_driver_install(&config, ð_handle)); + TEST_ESP_OK(esp_eth_start(eth_handle)); vTaskDelay(pdMS_TO_TICKS(portMAX_DELAY)); + // stop Ethernet driver + TEST_ESP_OK(esp_eth_stop(eth_handle)); /* driver should be uninstalled within 2 seconds */ TEST_ESP_OK(test_uninstall_driver(eth_handle, 2000)); TEST_ESP_OK(phy->del(phy)); diff --git a/examples/common_components/protocol_examples_common/connect.c b/examples/common_components/protocol_examples_common/connect.c index 06c5212b7a..dfaee392a5 100644 --- a/examples/common_components/protocol_examples_common/connect.c +++ b/examples/common_components/protocol_examples_common/connect.c @@ -232,6 +232,7 @@ static void start() #endif esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy); ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle)); + ESP_ERROR_CHECK(esp_eth_start(s_eth_handle)); s_connection_name = "Ethernet"; } @@ -242,6 +243,7 @@ static void stop() ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6)); ESP_ERROR_CHECK(esp_event_handler_unregister(ETH_EVENT, ETHERNET_EVENT_CONNECTED, &on_eth_event)); #endif + ESP_ERROR_CHECK(esp_eth_stop(s_eth_handle)); ESP_ERROR_CHECK(esp_eth_driver_uninstall(s_eth_handle)); ESP_ERROR_CHECK(s_phy->del(s_phy)); ESP_ERROR_CHECK(s_mac->del(s_mac)); diff --git a/examples/ethernet/basic/main/ethernet_example_main.c b/examples/ethernet/basic/main/ethernet_example_main.c index e161f435c7..d33f28f42b 100644 --- a/examples/ethernet/basic/main/ethernet_example_main.c +++ b/examples/ethernet/basic/main/ethernet_example_main.c @@ -118,4 +118,5 @@ void app_main() esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_handle_t eth_handle = NULL; ESP_ERROR_CHECK(esp_eth_driver_install(&config, ð_handle)); + ESP_ERROR_CHECK(esp_eth_start(eth_handle)); } diff --git a/examples/ethernet/eth2ap/main/ethernet_example_main.c b/examples/ethernet/eth2ap/main/ethernet_example_main.c index 004183945b..4baace1acf 100644 --- a/examples/ethernet/eth2ap/main/ethernet_example_main.c +++ b/examples/ethernet/eth2ap/main/ethernet_example_main.c @@ -191,6 +191,7 @@ static void initialize_ethernet(void) config.stack_input = pkt_eth2wifi; ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle)); esp_eth_ioctl(s_eth_handle, ETH_CMD_S_PROMISCUOUS, (void *)true); + ESP_ERROR_CHECK(esp_eth_start(s_eth_handle)); } static void initialize_wifi(void) diff --git a/examples/ethernet/iperf/main/cmd_ethernet.c b/examples/ethernet/iperf/main/cmd_ethernet.c index 48c3b35eb6..992973945a 100644 --- a/examples/ethernet/iperf/main/cmd_ethernet.c +++ b/examples/ethernet/iperf/main/cmd_ethernet.c @@ -228,6 +228,7 @@ void register_ethernet() #endif esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); ESP_ERROR_CHECK(esp_eth_driver_install(&config, ð_handle)); + ESP_ERROR_CHECK(esp_eth_start(eth_handle)); eth_control_args.control = arg_str1(NULL, NULL, "", "Get info of Ethernet"); eth_control_args.end = arg_end(1); From 97defec6cd28a7c0ac2459c616b7682a96e75113 Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 28 Nov 2019 16:00:18 +0800 Subject: [PATCH 5/6] ethernet:a bunch of bugfix from master --- components/esp_eth/src/esp_eth_mac_dm9051.c | 102 +++++++++---- components/esp_eth/src/esp_eth_mac_esp32.c | 100 +++++++------ components/esp_eth/src/esp_eth_phy_dm9051.c | 134 ++++++++++------- components/esp_eth/src/esp_eth_phy_dp83848.c | 128 +++++++++------- components/esp_eth/src/esp_eth_phy_ip101.c | 150 ++++++++++--------- components/esp_eth/src/esp_eth_phy_lan8720.c | 146 ++++++++++-------- components/esp_eth/src/esp_eth_phy_rtl8201.c | 129 +++++++++------- components/soc/esp32/emac_hal.c | 8 +- components/soc/esp32/include/hal/emac.h | 2 +- 9 files changed, 517 insertions(+), 382 deletions(-) diff --git a/components/esp_eth/src/esp_eth_mac_dm9051.c b/components/esp_eth/src/esp_eth_mac_dm9051.c index 1e7bb99c34..599f1b6558 100644 --- a/components/esp_eth/src/esp_eth_mac_dm9051.c +++ b/components/esp_eth/src/esp_eth_mac_dm9051.c @@ -40,7 +40,6 @@ static const char *TAG = "emac_dm9051"; } \ } while (0) -#define RX_QUEUE_WAIT_MS (100) #define DM9051_SPI_LOCK_TIMEOUT_MS (50) #define DM9051_PHY_OPERATION_TIMEOUT_US (1000) @@ -172,6 +171,30 @@ static esp_err_t dm9051_memory_read(emac_dm9051_t *emac, uint8_t *buffer, uint32 return ret; } +/** + * @brief peek buffer from dm9051 internal memory (without internal cursor moved) + */ +static esp_err_t dm9051_memory_peek(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len) +{ + esp_err_t ret = ESP_OK; + spi_transaction_t trans = { + .cmd = DM9051_SPI_RD, + .addr = DM9051_MRCMDX1, + .length = len * 8, + .rx_buffer = buffer + }; + if (dm9051_lock(emac)) { + if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { + ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); + ret = ESP_FAIL; + } + dm9051_unlock(emac); + } else { + ret = ESP_ERR_TIMEOUT; + } + return ret; +} + /** * @brief read mac address from internal registers */ @@ -254,10 +277,10 @@ static esp_err_t dm9051_verify_id(emac_dm9051_t *emac) uint8_t id[2]; MAC_CHECK(dm9051_register_read(emac, DM9051_VIDL, &id[0]) == ESP_OK, "read VIDL failed", err, ESP_FAIL); MAC_CHECK(dm9051_register_read(emac, DM9051_VIDH, &id[1]) == ESP_OK, "read VIDH failed", err, ESP_FAIL); - MAC_CHECK(0x0A46 == *(uint16_t *)id, "wrong Vendor ID", err, ESP_ERR_INVALID_VERSION); + MAC_CHECK(0x0A == id[1] && 0x46 == id[0], "wrong Vendor ID", err, ESP_ERR_INVALID_VERSION); MAC_CHECK(dm9051_register_read(emac, DM9051_PIDL, &id[0]) == ESP_OK, "read PIDL failed", err, ESP_FAIL); MAC_CHECK(dm9051_register_read(emac, DM9051_PIDH, &id[1]) == ESP_OK, "read PIDH failed", err, ESP_FAIL); - MAC_CHECK(0x9051 == *(uint16_t *)id, "wrong Product ID", err, ESP_ERR_INVALID_VERSION); + MAC_CHECK(0x90 == id[1] && 0x51 == id[0], "wrong Product ID", err, ESP_ERR_INVALID_VERSION); return ESP_OK; err: return ret; @@ -365,26 +388,27 @@ static void emac_dm9051_task(void *arg) uint8_t *buffer = NULL; uint32_t length = 0; while (1) { - if (ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS))) { - /* clear interrupt status */ - dm9051_register_read(emac, DM9051_ISR, &status); - dm9051_register_write(emac, DM9051_ISR, status); - /* packet received */ - if (status & ISR_PR) { - do { - buffer = (uint8_t *)heap_caps_malloc(ETH_MAX_PACKET_SIZE, MALLOC_CAP_DMA); - if (emac->parent.receive(&emac->parent, buffer, &length) == ESP_OK) { - /* pass the buffer to stack (e.g. TCP/IP layer) */ - if (length) { - emac->eth->stack_input(emac->eth, buffer, length); - } else { - free(buffer); - } + // block indefinitely until some task notifies me + ulTaskNotifyTake(pdFALSE, portMAX_DELAY); + /* clear interrupt status */ + dm9051_register_read(emac, DM9051_ISR, &status); + dm9051_register_write(emac, DM9051_ISR, status); + /* packet received */ + if (status & ISR_PR) { + do { + length = ETH_MAX_PACKET_SIZE; + buffer = (uint8_t *)heap_caps_malloc(length, MALLOC_CAP_DMA); + if (emac->parent.receive(&emac->parent, buffer, &length) == ESP_OK) { + /* pass the buffer to stack (e.g. TCP/IP layer) */ + if (length) { + emac->eth->stack_input(emac->eth, buffer, length); } else { free(buffer); } - } while (emac->packets_remain); - } + } else { + free(buffer); + } + } while (emac->packets_remain); } } vTaskDelete(NULL); @@ -608,13 +632,26 @@ static esp_err_t emac_dm9051_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t if (rxbyte > 1) { MAC_CHECK(dm9051_stop(emac) == ESP_OK, "stop dm9051 failed", err, ESP_FAIL); /* reset rx fifo pointer */ - MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX) == ESP_OK, "write MPTRCR failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX) == ESP_OK, + "write MPTRCR failed", err, ESP_FAIL); ets_delay_us(10); MAC_CHECK(dm9051_start(emac) == ESP_OK, "start dm9051 failed", err, ESP_FAIL); MAC_CHECK(false, "reset rx fifo pointer", err, ESP_FAIL); } else if (rxbyte) { - MAC_CHECK(dm9051_memory_read(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK, "read rx header failed", err, ESP_FAIL); + MAC_CHECK(dm9051_memory_peek(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK, + "peek rx header failed", err, ESP_FAIL); rx_len = header.length_low + (header.length_high << 8); + /* check if the buffer can hold all the incoming data */ + if (*length < rx_len - 4) { + ESP_LOGE(TAG, "buffer size too small"); + /* tell upper layer the size we need */ + *length = rx_len - 4; + ret = ESP_ERR_INVALID_SIZE; + goto err; + } + MAC_CHECK(*length >= rx_len - 4, "buffer size too small", err, ESP_ERR_INVALID_SIZE); + MAC_CHECK(dm9051_memory_read(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK, + "read rx header failed", err, ESP_FAIL); MAC_CHECK(dm9051_memory_read(emac, buf, rx_len) == ESP_OK, "read rx data failed", err, ESP_FAIL); MAC_CHECK(!(header.status & 0xBF), "receive status error: %xH", err, ESP_FAIL, header.status); *length = rx_len - 4; // substract the CRC length (4Bytes) @@ -681,9 +718,10 @@ static esp_err_t emac_dm9051_del(esp_eth_mac_t *mac) esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, const eth_mac_config_t *mac_config) { esp_eth_mac_t *ret = NULL; + emac_dm9051_t *emac = NULL; MAC_CHECK(dm9051_config, "can't set dm9051 specific config to null", err, NULL); MAC_CHECK(mac_config, "can't set mac config to null", err, NULL); - emac_dm9051_t *emac = calloc(1, sizeof(emac_dm9051_t)); + emac = calloc(1, sizeof(emac_dm9051_t)); MAC_CHECK(emac, "calloc emac failed", err, NULL); /* dm9051 receive is driven by interrupt only for now*/ MAC_CHECK(dm9051_config->int_gpio_num >= 0, "error interrupt gpio number", err, NULL); @@ -707,16 +745,22 @@ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, emac->parent.receive = emac_dm9051_receive; /* create mutex */ emac->spi_lock = xSemaphoreCreateMutex(); - MAC_CHECK(emac->spi_lock, "create lock failed", err_lock, NULL); + MAC_CHECK(emac->spi_lock, "create lock failed", err, NULL); /* create dm9051 task */ BaseType_t xReturned = xTaskCreate(emac_dm9051_task, "dm9051_tsk", mac_config->rx_task_stack_size, emac, mac_config->rx_task_prio, &emac->rx_task_hdl); - MAC_CHECK(xReturned == pdPASS, "create dm9051 task failed", err_tsk, NULL); + MAC_CHECK(xReturned == pdPASS, "create dm9051 task failed", err, NULL); return &(emac->parent); -err_tsk: - vSemaphoreDelete(emac->spi_lock); -err_lock: - free(emac); + err: + if (emac) { + if (emac->rx_task_hdl) { + vTaskDelete(emac->rx_task_hdl); + } + if (emac->spi_lock) { + vSemaphoreDelete(emac->spi_lock); + } + free(emac); + } return ret; } diff --git a/components/esp_eth/src/esp_eth_mac_esp32.c b/components/esp_eth/src/esp_eth_mac_esp32.c index e68c9e8e67..03a5b53bb6 100644 --- a/components/esp_eth/src/esp_eth_mac_esp32.c +++ b/components/esp_eth/src/esp_eth_mac_esp32.c @@ -41,7 +41,6 @@ static const char *TAG = "emac_esp32"; } \ } while (0) -#define RX_QUEUE_WAIT_MS (20) #define PHY_OPERATION_TIMEOUT_US (1000) typedef struct { @@ -227,7 +226,16 @@ static esp_err_t emac_esp32_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t * esp_err_t ret = ESP_OK; emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); MAC_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG); - *length = emac_hal_receive_frame(&emac->hal, buf, &emac->frames_remain); + uint32_t receive_len = emac_hal_receive_frame(&emac->hal, buf, *length, &emac->frames_remain); + /* we need to check the return value in case the buffer size is not enough */ + if (*length < receive_len) { + ESP_LOGE(TAG, "buffer size too small"); + /* tell upper layer the size we need */ + *length = receive_len; + ret = ESP_ERR_INVALID_SIZE; + goto err; + } + *length = receive_len; return ESP_OK; err: return ret; @@ -239,21 +247,22 @@ static void emac_esp32_rx_task(void *arg) uint8_t *buffer = NULL; uint32_t length = 0; while (1) { - if (ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS))) { - do { - buffer = (uint8_t *)malloc(ETH_MAX_PACKET_SIZE); - if (emac_esp32_receive(&emac->parent, buffer, &length) == ESP_OK) { - /* pass the buffer to stack (e.g. TCP/IP layer) */ - if (length) { - emac->eth->stack_input(emac->eth, buffer, length); - } else { - free(buffer); - } + // block indefinitely until some task notifies me + ulTaskNotifyTake(pdFALSE, portMAX_DELAY); + do { + length = ETH_MAX_PACKET_SIZE; + buffer = (uint8_t *)malloc(length); + if (emac_esp32_receive(&emac->parent, buffer, &length) == ESP_OK) { + /* pass the buffer to stack (e.g. TCP/IP layer) */ + if (length) { + emac->eth->stack_input(emac->eth, buffer, length); } else { free(buffer); } - } while (emac->frames_remain); - } + } else { + free(buffer); + } + } while (emac->frames_remain); } vTaskDelete(NULL); } @@ -353,43 +362,30 @@ IRAM_ATTR void emac_esp32_isr_handler(void *args) esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) { esp_eth_mac_t *ret = NULL; + void *descriptors = NULL; + emac_esp32_t *emac = NULL; MAC_CHECK(config, "can't set mac config to null", err, NULL); - emac_esp32_t *emac = calloc(1, sizeof(emac_esp32_t)); + emac = calloc(1, sizeof(emac_esp32_t)); MAC_CHECK(emac, "calloc emac failed", err, NULL); /* alloc memory for ethernet dma descriptor */ uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) + CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t); - void *descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA); - MAC_CHECK(descriptors, "calloc descriptors failed", err_desc, NULL); + descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA); + MAC_CHECK(descriptors, "calloc descriptors failed", err, NULL); int i = 0; /* alloc memory for ethernet dma buffer */ for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { emac->rx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA); if (!(emac->rx_buf[i])) { - break; + goto err; } } - if (i != CONFIG_ETH_DMA_RX_BUFFER_NUM) { - for (--i; i >= 0; i--) { - free(emac->rx_buf[i]); - } - goto err_buffer; - } for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { emac->tx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA); if (!(emac->tx_buf[i])) { - break; + goto err; } } - if (i != CONFIG_ETH_DMA_TX_BUFFER_NUM) { - for (--i; i >= 0; i--) { - free(emac->tx_buf[i]); - } - for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { - free(emac->rx_buf[i]); - } - goto err_buffer; - } /* initialize hal layer driver */ emac_hal_init(&emac->hal, descriptors, emac->rx_buf, emac->tx_buf); emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; @@ -412,26 +408,32 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) /* Interrupt configuration */ MAC_CHECK(esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_esp32_isr_handler, &emac->hal, &(emac->intr_hdl)) == ESP_OK, - "alloc emac interrupt failed", err_intr, NULL); + "alloc emac interrupt failed", err, NULL); /* create rx task */ BaseType_t xReturned = xTaskCreate(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac, config->rx_task_prio, &emac->rx_task_hdl); - MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err_task, NULL); + MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err, NULL); return &(emac->parent); -err_task: - esp_intr_free(emac->intr_hdl); -err_intr: - for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { - free(emac->tx_buf[i]); - } - for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { - free(emac->rx_buf[i]); - } -err_buffer: - free(descriptors); -err_desc: - free(emac); + err: + if (emac) { + if (emac->rx_task_hdl) { + vTaskDelete(emac->rx_task_hdl); + } + if (emac->intr_hdl) { + esp_intr_free(emac->intr_hdl); + } + for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { + free(emac->tx_buf[i]); + } + for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { + free(emac->rx_buf[i]); + } + free(emac); + } + if (descriptors) { + free(descriptors); + } return ret; } diff --git a/components/esp_eth/src/esp_eth_phy_dm9051.c b/components/esp_eth/src/esp_eth_phy_dm9051.c index d423b6ba15..c3775f2042 100644 --- a/components/esp_eth/src/esp_eth_phy_dm9051.c +++ b/components/esp_eth/src/esp_eth_phy_dm9051.c @@ -80,7 +80,6 @@ typedef union { typedef struct { esp_eth_phy_t parent; esp_eth_mediator_t *eth; - const char *name; uint32_t addr; uint32_t reset_timeout_ms; uint32_t autonego_timeout_ms; @@ -88,9 +87,49 @@ typedef struct { int reset_gpio_num; } phy_dm9051_t; +static esp_err_t dm9051_update_link_duplex_speed(phy_dm9051_t *dm9051) +{ + esp_eth_mediator_t *eth = dm9051->eth; + eth_speed_t speed = ETH_SPEED_10M; + eth_duplex_t duplex = ETH_DUPLEX_HALF; + bmsr_reg_t bmsr; + dscsr_reg_t dscsr; + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + /* check if link status changed */ + if (dm9051->link_status != link) { + /* when link up, read negotiation result */ + if (link == ETH_LINK_UP) { + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, + "read DSCSR failed", err); + if (dscsr.fdx100 || dscsr.hdx100) { + speed = ETH_SPEED_100M; + } else { + speed = ETH_SPEED_10M; + } + if (dscsr.fdx100 || dscsr.fdx10) { + duplex = ETH_DUPLEX_FULL; + } else { + duplex = ETH_DUPLEX_HALF; + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, + "change speed failed", err); + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, + "change duplex failed", err); + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, + "change link failed", err); + dm9051->link_status = link; + } + return ESP_OK; +err: + return ESP_FAIL; +} + static esp_err_t dm9051_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) { - PHY_CHECK(eth, "can't set mediator for dm9051 to null", err); + PHY_CHECK(eth, "can't set mediator to null", err); phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); dm9051->eth = eth; return ESP_OK; @@ -101,19 +140,8 @@ err: static esp_err_t dm9051_get_link(esp_eth_phy_t *phy) { phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); - esp_eth_mediator_t *eth = dm9051->eth; - bmsr_reg_t bmsr; - - PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; - if (dm9051->link_status != link) { - if (link == ETH_LINK_UP) { - phy->negotiate(phy); - } else { - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); - dm9051->link_status = link; - } - } + /* Updata information about link, speed, duplex */ + PHY_CHECK(dm9051_update_link_duplex_speed(dm9051) == ESP_OK, "update link duplex speed failed", err); return ESP_OK; err: return ESP_FAIL; @@ -125,17 +153,22 @@ static esp_err_t dm9051_reset(esp_eth_phy_t *phy) dm9051->link_status = ETH_LINK_DOWN; esp_eth_mediator_t *eth = dm9051->eth; dscr_reg_t dscr; - PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, "read DSCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, + "read DSCR failed", err); dscr.smrst = 1; - PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, dscr.val) == ESP_OK, "write DSCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, dscr.val) == ESP_OK, + "write DSCR failed", err); bmcr_reg_t bmcr = {.reset = 1}; - PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); /* Wait for reset complete */ uint32_t to = 0; for (to = 0; to < dm9051->reset_timeout_ms / 10; to++) { vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, "read DSCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, + "read DSCR failed", err); if (!bmcr.reset && !dscr.smrst) { break; } @@ -170,15 +203,18 @@ static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy) .en_auto_nego = 1, /* Auto Negotiation */ .restart_auto_nego = 1 /* Restart Auto Negotiation */ }; - PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); /* Wait for auto negotiation complete */ bmsr_reg_t bmsr; dscsr_reg_t dscsr; uint32_t to = 0; for (to = 0; to < dm9051->autonego_timeout_ms / 10; to++) { vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, "read DSCSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, + "read DSCSR failed", err); if (bmsr.auto_nego_complete && dscsr.anmb & 0x08) { break; } @@ -187,27 +223,7 @@ static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy) ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout"); } /* Updata information about link, speed, duplex */ - PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, "read DSCSR failed", err); - eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; - eth_speed_t speed = ETH_SPEED_10M; - eth_duplex_t duplex = ETH_DUPLEX_HALF; - if (dscsr.fdx100 || dscsr.hdx100) { - speed = ETH_SPEED_100M; - } else { - speed = ETH_SPEED_10M; - } - if (dscsr.fdx100 || dscsr.fdx10) { - duplex = ETH_DUPLEX_FULL; - } else { - duplex = ETH_DUPLEX_HALF; - } - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err); - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err); - if (dm9051->link_status != link) { - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); - dm9051->link_status = link; - } + PHY_CHECK(dm9051_update_link_duplex_speed(dm9051) == ESP_OK, "update link duplex speed failed", err); return ESP_OK; err: return ESP_FAIL; @@ -218,7 +234,8 @@ static esp_err_t dm9051_pwrctl(esp_eth_phy_t *phy, bool enable) phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); esp_eth_mediator_t *eth = dm9051->eth; bmcr_reg_t bmcr; - PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!enable) { /* Enable IEEE Power Down Mode */ bmcr.power_down = 1; @@ -226,8 +243,10 @@ static esp_err_t dm9051_pwrctl(esp_eth_phy_t *phy, bool enable) /* Disable IEEE Power Down Mode */ bmcr.power_down = 0; } - PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!enable) { PHY_CHECK(bmcr.power_down == 1, "power down failed", err); } else { @@ -247,7 +266,7 @@ static esp_err_t dm9051_set_addr(esp_eth_phy_t *phy, uint32_t addr) static esp_err_t dm9051_get_addr(esp_eth_phy_t *phy, uint32_t *addr) { - PHY_CHECK(addr, "get phy address failed", err); + PHY_CHECK(addr, "addr can't be null", err); phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); *addr = dm9051->addr; return ESP_OK; @@ -267,15 +286,18 @@ static esp_err_t dm9051_init(esp_eth_phy_t *phy) phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); esp_eth_mediator_t *eth = dm9051->eth; /* Power on Ethernet PHY */ - PHY_CHECK(dm9051_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err); + PHY_CHECK(dm9051_pwrctl(phy, true) == ESP_OK, "power control failed", err); /* Reset Ethernet PHY */ - PHY_CHECK(dm9051_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err); + PHY_CHECK(dm9051_reset(phy) == ESP_OK, "reset failed", err); /* Check PHY ID */ phyidr1_reg_t id1; phyidr2_reg_t id2; - PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err); - PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err); - PHY_CHECK(id1.oui_msb == 0x0181 && id2.oui_lsb == 0x2E && id2.vendor_model == 0x0A, "wrong PHY chip ID", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, + "read ID1 failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, + "read ID2 failed", err); + PHY_CHECK(id1.oui_msb == 0x0181 && id2.oui_lsb == 0x2E && id2.vendor_model == 0x0A, + "wrong chip ID", err); return ESP_OK; err: return ESP_FAIL; @@ -284,7 +306,7 @@ err: static esp_err_t dm9051_deinit(esp_eth_phy_t *phy) { /* Power off Ethernet PHY */ - PHY_CHECK(dm9051_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err); + PHY_CHECK(dm9051_pwrctl(phy, false) == ESP_OK, "power control failed", err); return ESP_OK; err: return ESP_FAIL; @@ -295,8 +317,7 @@ esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config) PHY_CHECK(config, "can't set phy config to null", err); PHY_CHECK(config->phy_addr == 1, "dm9051's phy address can only set to 1", err); phy_dm9051_t *dm9051 = calloc(1, sizeof(phy_dm9051_t)); - PHY_CHECK(dm9051, "calloc dm9051 object failed", err); - dm9051->name = "dm9051"; + PHY_CHECK(dm9051, "calloc dm9051 failed", err); dm9051->addr = config->phy_addr; dm9051->reset_timeout_ms = config->reset_timeout_ms; dm9051->reset_gpio_num = config->reset_gpio_num; @@ -313,7 +334,6 @@ esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config) dm9051->parent.get_addr = dm9051_get_addr; dm9051->parent.set_addr = dm9051_set_addr; dm9051->parent.del = dm9051_del; - return &(dm9051->parent); err: return NULL; diff --git a/components/esp_eth/src/esp_eth_phy_dp83848.c b/components/esp_eth/src/esp_eth_phy_dp83848.c index 520d7ae0cb..fbb41391a9 100644 --- a/components/esp_eth/src/esp_eth_phy_dp83848.c +++ b/components/esp_eth/src/esp_eth_phy_dp83848.c @@ -86,7 +86,6 @@ typedef union { typedef struct { esp_eth_phy_t parent; esp_eth_mediator_t *eth; - const char *name; uint32_t addr; uint32_t reset_timeout_ms; uint32_t autonego_timeout_ms; @@ -94,9 +93,49 @@ typedef struct { int reset_gpio_num; } phy_dp83848_t; +static esp_err_t dp83848_update_link_duplex_speed(phy_dp83848_t *dp83848) +{ + esp_eth_mediator_t *eth = dp83848->eth; + eth_speed_t speed = ETH_SPEED_10M; + eth_duplex_t duplex = ETH_DUPLEX_HALF; + bmsr_reg_t bmsr; + physts_reg_t physts; + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + /* check if link status changed */ + if (dp83848->link_status != link) { + /* when link up, read negotiation result */ + if (link == ETH_LINK_UP) { + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK, + "read PHYSTS failed", err); + if (physts.speed_status) { + speed = ETH_SPEED_10M; + } else { + speed = ETH_SPEED_100M; + } + if (physts.duplex_status) { + duplex = ETH_DUPLEX_FULL; + } else { + duplex = ETH_DUPLEX_HALF; + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, + "change speed failed", err); + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, + "change duplex failed", err); + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, + "change link failed", err); + dp83848->link_status = link; + } + return ESP_OK; +err: + return ESP_FAIL; +} + static esp_err_t dp83848_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) { - PHY_CHECK(eth, "can't set mediator for dp83848 to null", err); + PHY_CHECK(eth, "can't set mediator to null", err); phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); dp83848->eth = eth; return ESP_OK; @@ -107,19 +146,8 @@ err: static esp_err_t dp83848_get_link(esp_eth_phy_t *phy) { phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); - esp_eth_mediator_t *eth = dp83848->eth; - bmsr_reg_t bmsr; - - PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; - if (dp83848->link_status != link) { - if (link == ETH_LINK_UP) { - phy->negotiate(phy); - } else { - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); - dp83848->link_status = link; - } - } + /* Updata information about link, speed, duplex */ + PHY_CHECK(dp83848_update_link_duplex_speed(dp83848) == ESP_OK, "update link duplex speed failed", err); return ESP_OK; err: return ESP_FAIL; @@ -131,17 +159,19 @@ static esp_err_t dp83848_reset(esp_eth_phy_t *phy) dp83848->link_status = ETH_LINK_DOWN; esp_eth_mediator_t *eth = dp83848->eth; bmcr_reg_t bmcr = {.reset = 1}; - PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); /* Wait for reset complete */ uint32_t to = 0; for (to = 0; to < dp83848->reset_timeout_ms / 10; to++) { vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!bmcr.reset) { break; } } - PHY_CHECK(to < dp83848->reset_timeout_ms / 10, "PHY reset timeout", err); + PHY_CHECK(to < dp83848->reset_timeout_ms / 10, "reset timeout", err); return ESP_OK; err: return ESP_FAIL; @@ -170,45 +200,28 @@ static esp_err_t dp83848_negotiate(esp_eth_phy_t *phy) .en_auto_nego = 1, /* Auto Negotiation */ .restart_auto_nego = 1 /* Restart Auto Negotiation */ }; - PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); /* Wait for auto negotiation complete */ bmsr_reg_t bmsr; physts_reg_t physts; uint32_t to = 0; for (to = 0; to < dp83848->autonego_timeout_ms / 10; to++) { vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK, "read PHYSTS failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK, + "read PHYSTS failed", err); if (bmsr.auto_nego_complete && physts.auto_nego_complete) { break; } } /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ if (to >= dp83848->autonego_timeout_ms / 10) { - ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout"); + ESP_LOGW(TAG, "auto negotiation timeout"); } /* Updata information about link, speed, duplex */ - PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK, "read PHYSTS failed", err); - eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; - eth_speed_t speed = ETH_SPEED_10M; - eth_duplex_t duplex = ETH_DUPLEX_HALF; - if (physts.speed_status) { - speed = ETH_SPEED_10M; - } else { - speed = ETH_SPEED_100M; - } - if (physts.duplex_status) { - duplex = ETH_DUPLEX_FULL; - } else { - duplex = ETH_DUPLEX_HALF; - } - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err); - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err); - if (dp83848->link_status != link) { - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); - dp83848->link_status = link; - } + PHY_CHECK(dp83848_update_link_duplex_speed(dp83848) == ESP_OK, "update link duplex speed failed", err); return ESP_OK; err: return ESP_FAIL; @@ -219,7 +232,8 @@ static esp_err_t dp83848_pwrctl(esp_eth_phy_t *phy, bool enable) phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); esp_eth_mediator_t *eth = dp83848->eth; bmcr_reg_t bmcr; - PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!enable) { /* Enable IEEE Power Down Mode */ bmcr.power_down = 1; @@ -227,8 +241,10 @@ static esp_err_t dp83848_pwrctl(esp_eth_phy_t *phy, bool enable) /* Disable IEEE Power Down Mode */ bmcr.power_down = 0; } - PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!enable) { PHY_CHECK(bmcr.power_down == 1, "power down failed", err); } else { @@ -248,7 +264,7 @@ static esp_err_t dp83848_set_addr(esp_eth_phy_t *phy, uint32_t addr) static esp_err_t dp83848_get_addr(esp_eth_phy_t *phy, uint32_t *addr) { - PHY_CHECK(addr, "get phy address failed", err); + PHY_CHECK(addr, "addr can't be null", err); phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); *addr = dp83848->addr; return ESP_OK; @@ -268,15 +284,18 @@ static esp_err_t dp83848_init(esp_eth_phy_t *phy) phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); esp_eth_mediator_t *eth = dp83848->eth; /* Power on Ethernet PHY */ - PHY_CHECK(dp83848_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err); + PHY_CHECK(dp83848_pwrctl(phy, true) == ESP_OK, "power control failed", err); /* Reset Ethernet PHY */ - PHY_CHECK(dp83848_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err); + PHY_CHECK(dp83848_reset(phy) == ESP_OK, "reset failed", err); /* Check PHY ID */ phyidr1_reg_t id1; phyidr2_reg_t id2; - PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err); - PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err); - PHY_CHECK(id1.oui_msb == 0x2000 && id2.oui_lsb == 0x17 && id2.vendor_model == 0x09, "wrong PHY chip ID", err); + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, + "read ID1 failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, + "read ID2 failed", err); + PHY_CHECK(id1.oui_msb == 0x2000 && id2.oui_lsb == 0x17 && id2.vendor_model == 0x09, + "wrong chip ID", err); return ESP_OK; err: return ESP_FAIL; @@ -285,7 +304,7 @@ err: static esp_err_t dp83848_deinit(esp_eth_phy_t *phy) { /* Power off Ethernet PHY */ - PHY_CHECK(dp83848_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err); + PHY_CHECK(dp83848_pwrctl(phy, false) == ESP_OK, "power control failed", err); return ESP_OK; err: return ESP_FAIL; @@ -295,8 +314,7 @@ esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config) { PHY_CHECK(config, "can't set phy config to null", err); phy_dp83848_t *dp83848 = calloc(1, sizeof(phy_dp83848_t)); - PHY_CHECK(dp83848, "calloc dp83848 object failed", err); - dp83848->name = "dp83848"; + PHY_CHECK(dp83848, "calloc dp83848 failed", err); dp83848->addr = config->phy_addr; dp83848->reset_timeout_ms = config->reset_timeout_ms; dp83848->link_status = ETH_LINK_DOWN; diff --git a/components/esp_eth/src/esp_eth_phy_ip101.c b/components/esp_eth/src/esp_eth_phy_ip101.c index 847fc65137..8bb852b25b 100644 --- a/components/esp_eth/src/esp_eth_phy_ip101.c +++ b/components/esp_eth/src/esp_eth_phy_ip101.c @@ -103,7 +103,6 @@ typedef union { typedef struct { esp_eth_phy_t parent; esp_eth_mediator_t *eth; - const char *name; uint32_t addr; uint32_t reset_timeout_ms; uint32_t autonego_timeout_ms; @@ -123,9 +122,62 @@ err: return ESP_FAIL; } +static esp_err_t ip101_update_link_duplex_speed(phy_ip101_t *ip101) +{ + esp_eth_mediator_t *eth = ip101->eth; + eth_speed_t speed = ETH_SPEED_10M; + eth_duplex_t duplex = ETH_DUPLEX_HALF; + cssr_reg_t cssr; + bmsr_reg_t bmsr; + PHY_CHECK(ip101_page_select(ip101, 16) == ESP_OK, "select page 16 failed", err); + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + /* check if link status changed */ + if (ip101->link_status != link) { + /* when link up, read negotiation result */ + if (link == ETH_LINK_UP) { + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_CSSR_REG_ADDR, &(cssr.val)) == ESP_OK, + "read CSSR failed", err); + switch (cssr.op_mode) { + case 1: //10M Half + speed = ETH_SPEED_10M; + duplex = ETH_DUPLEX_HALF; + break; + case 2: //100M Half + speed = ETH_SPEED_100M; + duplex = ETH_DUPLEX_HALF; + break; + case 5: //10M Full + speed = ETH_SPEED_10M; + duplex = ETH_DUPLEX_FULL; + break; + case 6: //100M Full + speed = ETH_SPEED_100M; + duplex = ETH_DUPLEX_FULL; + break; + default: + break; + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, + "change speed failed", err); + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, + "change duplex failed", err); + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, + "chagne link failed", err); + ip101->link_status = link; + } + return ESP_OK; +err: + return ESP_FAIL; +} + static esp_err_t ip101_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) { - PHY_CHECK(eth, "can't set mediator for ip101 to null", err); + PHY_CHECK(eth, "can't set mediator to null", err); phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); ip101->eth = eth; return ESP_OK; @@ -136,19 +188,8 @@ err: static esp_err_t ip101_get_link(esp_eth_phy_t *phy) { phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); - esp_eth_mediator_t *eth = ip101->eth; - bmsr_reg_t bmsr; - - PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; - if (ip101->link_status != link) { - if (link == ETH_LINK_UP) { - phy->negotiate(phy); - } else { - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); - ip101->link_status = link; - } - } + /* Updata information about link, speed, duplex */ + PHY_CHECK(ip101_update_link_duplex_speed(ip101) == ESP_OK, "update link duplex speed failed", err); return ESP_OK; err: return ESP_FAIL; @@ -160,17 +201,19 @@ static esp_err_t ip101_reset(esp_eth_phy_t *phy) ip101->link_status = ETH_LINK_DOWN; esp_eth_mediator_t *eth = ip101->eth; bmcr_reg_t bmcr = {.reset = 1}; - PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); /* wait for reset complete */ - uint32_t to = 0; + uint32_t to = 0; for (to = 0; to < ip101->reset_timeout_ms / 10; to++) { vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!bmcr.reset) { break; } } - PHY_CHECK(to < ip101->reset_timeout_ms / 10, "PHY reset timeout", err); + PHY_CHECK(to < ip101->reset_timeout_ms / 10, "reset timeout", err); return ESP_OK; err: return ESP_FAIL; @@ -192,65 +235,32 @@ static esp_err_t ip101_negotiate(esp_eth_phy_t *phy) { phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); esp_eth_mediator_t *eth = ip101->eth; - /* Start auto negotiation */ + /* Restart auto negotiation */ bmcr_reg_t bmcr = { .speed_select = 1, /* 100Mbps */ .duplex_mode = 1, /* Full Duplex */ .en_auto_nego = 1, /* Auto Negotiation */ .restart_auto_nego = 1 /* Restart Auto Negotiation */ }; - PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); /* Wait for auto negotiation complete */ bmsr_reg_t bmsr; uint32_t to = 0; for (to = 0; to < ip101->autonego_timeout_ms / 10; to++) { vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + "read BMSR failed", err); if (bmsr.auto_nego_complete) { break; } } /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ if (to >= ip101->autonego_timeout_ms / 10) { - ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout"); + ESP_LOGW(TAG, "auto negotiation timeout"); } - PHY_CHECK(ip101_page_select(ip101, 16) == ESP_OK, "select page failed", err); /* Updata information about link, speed, duplex */ - cssr_reg_t cssr; - PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_CSSR_REG_ADDR, &(cssr.val)) == ESP_OK, "read CSSR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; - eth_speed_t speed = ETH_SPEED_10M; - eth_duplex_t duplex = ETH_DUPLEX_HALF; - switch (cssr.op_mode) { - case 0: //Link off - link = ETH_LINK_DOWN; - break; - case 1: //10M Half - speed = ETH_SPEED_10M; - duplex = ETH_DUPLEX_HALF; - break; - case 2: //100M Half - speed = ETH_SPEED_100M; - duplex = ETH_DUPLEX_HALF; - break; - case 5: //10M Full - speed = ETH_SPEED_10M; - duplex = ETH_DUPLEX_FULL; - break; - case 6: //100M Full - speed = ETH_SPEED_100M; - duplex = ETH_DUPLEX_FULL; - break; - default: - break; - } - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err); - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err); - if (ip101->link_status != link) { - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); - ip101->link_status = link; - } + PHY_CHECK(ip101_update_link_duplex_speed(ip101) == ESP_OK, "update link duplex speed failed", err); return ESP_OK; err: return ESP_FAIL; @@ -261,7 +271,8 @@ static esp_err_t ip101_pwrctl(esp_eth_phy_t *phy, bool enable) phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); esp_eth_mediator_t *eth = ip101->eth; bmcr_reg_t bmcr; - PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!enable) { /* Enable IEEE Power Down Mode */ bmcr.power_down = 1; @@ -269,8 +280,10 @@ static esp_err_t ip101_pwrctl(esp_eth_phy_t *phy, bool enable) /* Disable IEEE Power Down Mode */ bmcr.power_down = 0; } - PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!enable) { PHY_CHECK(bmcr.power_down == 1, "power down failed", err); } else { @@ -290,7 +303,7 @@ static esp_err_t ip101_set_addr(esp_eth_phy_t *phy, uint32_t addr) static esp_err_t ip101_get_addr(esp_eth_phy_t *phy, uint32_t *addr) { - PHY_CHECK(addr, "get phy address failed", err); + PHY_CHECK(addr, "addr can't be null", err); phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); *addr = ip101->addr; return ESP_OK; @@ -310,15 +323,15 @@ static esp_err_t ip101_init(esp_eth_phy_t *phy) phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); esp_eth_mediator_t *eth = ip101->eth; /* Power on Ethernet PHY */ - PHY_CHECK(ip101_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err); + PHY_CHECK(ip101_pwrctl(phy, true) == ESP_OK, "power control failed", err); /* Reset Ethernet PHY */ - PHY_CHECK(ip101_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err); + PHY_CHECK(ip101_reset(phy) == ESP_OK, "reset failed", err); /* Check PHY ID */ phyidr1_reg_t id1; phyidr2_reg_t id2; PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err); PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err); - PHY_CHECK(id1.oui_msb == 0x243 && id2.oui_lsb == 0x3 && id2.vendor_model == 0x5, "wrong PHY chip ID", err); + PHY_CHECK(id1.oui_msb == 0x243 && id2.oui_lsb == 0x3 && id2.vendor_model == 0x5, "wrong chip ID", err); return ESP_OK; err: return ESP_FAIL; @@ -327,7 +340,7 @@ err: static esp_err_t ip101_deinit(esp_eth_phy_t *phy) { /* Power off Ethernet PHY */ - PHY_CHECK(ip101_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err); + PHY_CHECK(ip101_pwrctl(phy, false) == ESP_OK, "power control failed", err); return ESP_OK; err: return ESP_FAIL; @@ -337,8 +350,7 @@ esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config) { PHY_CHECK(config, "can't set phy config to null", err); phy_ip101_t *ip101 = calloc(1, sizeof(phy_ip101_t)); - PHY_CHECK(ip101, "calloc ip101 object failed", err); - ip101->name = "ip101"; + PHY_CHECK(ip101, "calloc ip101 failed", err); ip101->addr = config->phy_addr; ip101->reset_timeout_ms = config->reset_timeout_ms; ip101->reset_gpio_num = config->reset_gpio_num; diff --git a/components/esp_eth/src/esp_eth_phy_lan8720.c b/components/esp_eth/src/esp_eth_phy_lan8720.c index f513b44818..d7d62bb781 100644 --- a/components/esp_eth/src/esp_eth_phy_lan8720.c +++ b/components/esp_eth/src/esp_eth_phy_lan8720.c @@ -158,7 +158,6 @@ typedef union { typedef struct { esp_eth_phy_t parent; esp_eth_mediator_t *eth; - const char *name; uint32_t addr; uint32_t reset_timeout_ms; uint32_t autonego_timeout_ms; @@ -166,9 +165,59 @@ typedef struct { int reset_gpio_num; } phy_lan8720_t; +static esp_err_t lan8720_update_link_duplex_speed(phy_lan8720_t *lan8720) +{ + esp_eth_mediator_t *eth = lan8720->eth; + eth_speed_t speed = ETH_SPEED_10M; + eth_duplex_t duplex = ETH_DUPLEX_HALF; + bmsr_reg_t bmsr; + pscsr_reg_t pscsr; + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + /* check if link status changed */ + if (lan8720->link_status != link) { + /* when link up, read negotiation result */ + if (link == ETH_LINK_UP) { + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK, + "read PSCSR failed", err); + switch (pscsr.speed_indication) { + case 1: //10Base-T half-duplex + speed = ETH_SPEED_10M; + duplex = ETH_DUPLEX_HALF; + break; + case 2: //100Base-TX half-duplex + speed = ETH_SPEED_100M; + duplex = ETH_DUPLEX_HALF; + break; + case 5: //10Base-T full-duplex + speed = ETH_SPEED_10M; + duplex = ETH_DUPLEX_FULL; + break; + case 6: //100Base-TX full-duplex + speed = ETH_SPEED_100M; + duplex = ETH_DUPLEX_FULL; + break; + default: + break; + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, + "change speed failed", err); + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, + "change duplex failed", err); + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, + "change link failed", err); + lan8720->link_status = link; + } + return ESP_OK; +err: + return ESP_FAIL; +} + static esp_err_t lan8720_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) { - PHY_CHECK(eth, "can't set mediator for lan8720 to null", err); + PHY_CHECK(eth, "can't set mediator to null", err); phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); lan8720->eth = eth; return ESP_OK; @@ -179,19 +228,8 @@ err: static esp_err_t lan8720_get_link(esp_eth_phy_t *phy) { phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); - esp_eth_mediator_t *eth = lan8720->eth; - bmsr_reg_t bmsr; - - PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; - if (lan8720->link_status != link) { - if (link == ETH_LINK_UP) { - phy->negotiate(phy); - } else { - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); - lan8720->link_status = link; - } - } + /* Updata information about link, speed, duplex */ + PHY_CHECK(lan8720_update_link_duplex_speed(lan8720) == ESP_OK, "update link duplex speed failed", err); return ESP_OK; err: return ESP_FAIL; @@ -203,17 +241,19 @@ static esp_err_t lan8720_reset(esp_eth_phy_t *phy) lan8720->link_status = ETH_LINK_DOWN; esp_eth_mediator_t *eth = lan8720->eth; bmcr_reg_t bmcr = {.reset = 1}; - PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); /* wait for reset complete */ uint32_t to = 0; for (to = 0; to < lan8720->reset_timeout_ms / 10; to++) { vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!bmcr.reset) { break; } } - PHY_CHECK(to < lan8720->reset_timeout_ms / 10, "PHY reset timeout", err); + PHY_CHECK(to < lan8720->reset_timeout_ms / 10, "reset timeout", err); return ESP_OK; err: return ESP_FAIL; @@ -235,7 +275,7 @@ static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy) { phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); esp_eth_mediator_t *eth = lan8720->eth; - /* Start auto negotiation */ + /* Restart auto negotiation */ bmcr_reg_t bmcr = { .speed_select = 1, /* 100Mbps */ .duplex_mode = 1, /* Full Duplex */ @@ -249,48 +289,20 @@ static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy) int32_t to = 0; for (to = 0; to < lan8720->autonego_timeout_ms / 10; to++) { vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK, "read PSCSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK, + "read PSCSR failed", err); if (bmsr.auto_nego_complete && pscsr.auto_nego_done) { break; } } /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ if (to >= lan8720->autonego_timeout_ms / 10) { - ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout"); + ESP_LOGW(TAG, "auto negotiation timeout"); } /* Updata information about link, speed, duplex */ - PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK, "read PSCSR failed", err); - eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; - eth_speed_t speed = ETH_SPEED_10M; - eth_duplex_t duplex = ETH_DUPLEX_HALF; - switch (pscsr.speed_indication) { - case 1: //10Base-T half-duplex - speed = ETH_SPEED_10M; - duplex = ETH_DUPLEX_HALF; - break; - case 2: //100Base-TX half-duplex - speed = ETH_SPEED_100M; - duplex = ETH_DUPLEX_HALF; - break; - case 5: //10Base-T full-duplex - speed = ETH_SPEED_10M; - duplex = ETH_DUPLEX_FULL; - break; - case 6: //100Base-TX full-duplex - speed = ETH_SPEED_100M; - duplex = ETH_DUPLEX_FULL; - break; - default: - break; - } - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err); - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err); - if (lan8720->link_status != link) { - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); - lan8720->link_status = link; - } + PHY_CHECK(lan8720_update_link_duplex_speed(lan8720) == ESP_OK, "update link duplex speed failed", err); return ESP_OK; err: return ESP_FAIL; @@ -301,7 +313,8 @@ static esp_err_t lan8720_pwrctl(esp_eth_phy_t *phy, bool enable) phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); esp_eth_mediator_t *eth = lan8720->eth; bmcr_reg_t bmcr; - PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!enable) { /* General Power Down Mode */ bmcr.power_down = 1; @@ -309,8 +322,10 @@ static esp_err_t lan8720_pwrctl(esp_eth_phy_t *phy, bool enable) /* Normal operation Mode */ bmcr.power_down = 0; } - PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!enable) { PHY_CHECK(bmcr.power_down == 1, "power down failed", err); } else { @@ -330,7 +345,7 @@ static esp_err_t lan8720_set_addr(esp_eth_phy_t *phy, uint32_t addr) static esp_err_t lan8720_get_addr(esp_eth_phy_t *phy, uint32_t *addr) { - PHY_CHECK(addr, "get phy address failed", err); + PHY_CHECK(addr, "addr can't be null", err); phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); *addr = lan8720->addr; return ESP_OK; @@ -350,15 +365,17 @@ static esp_err_t lan8720_init(esp_eth_phy_t *phy) phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); esp_eth_mediator_t *eth = lan8720->eth; /* Power on Ethernet PHY */ - PHY_CHECK(lan8720_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err); + PHY_CHECK(lan8720_pwrctl(phy, true) == ESP_OK, "power control failed", err); /* Reset Ethernet PHY */ - PHY_CHECK(lan8720_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err); + PHY_CHECK(lan8720_reset(phy) == ESP_OK, "reset failed", err); /* Check PHY ID */ phyidr1_reg_t id1; phyidr2_reg_t id2; - PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err); - PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err); - PHY_CHECK(id1.oui_msb == 0x7 && id2.oui_lsb == 0x30 && id2.vendor_model == 0xF, "wrong PHY chip ID", err); + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, + "read ID1 failed", err); + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, + "read ID2 failed", err); + PHY_CHECK(id1.oui_msb == 0x7 && id2.oui_lsb == 0x30 && id2.vendor_model == 0xF, "wrong chip ID", err); return ESP_OK; err: return ESP_FAIL; @@ -367,7 +384,7 @@ err: static esp_err_t lan8720_deinit(esp_eth_phy_t *phy) { /* Power off Ethernet PHY */ - PHY_CHECK(lan8720_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err); + PHY_CHECK(lan8720_pwrctl(phy, false) == ESP_OK, "power control failed", err); return ESP_OK; err: return ESP_FAIL; @@ -377,8 +394,7 @@ esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config) { PHY_CHECK(config, "can't set phy config to null", err); phy_lan8720_t *lan8720 = calloc(1, sizeof(phy_lan8720_t)); - PHY_CHECK(lan8720, "calloc lan8720 object failed", err); - lan8720->name = "lan8720"; + PHY_CHECK(lan8720, "calloc lan8720 failed", err); lan8720->addr = config->phy_addr; lan8720->reset_gpio_num = config->reset_gpio_num; lan8720->reset_timeout_ms = config->reset_timeout_ms; diff --git a/components/esp_eth/src/esp_eth_phy_rtl8201.c b/components/esp_eth/src/esp_eth_phy_rtl8201.c index bbd4aae05a..814563fdc1 100644 --- a/components/esp_eth/src/esp_eth_phy_rtl8201.c +++ b/components/esp_eth/src/esp_eth_phy_rtl8201.c @@ -64,7 +64,6 @@ typedef union { typedef struct { esp_eth_phy_t parent; esp_eth_mediator_t *eth; - const char *name; uint32_t addr; uint32_t reset_timeout_ms; uint32_t autonego_timeout_ms; @@ -84,9 +83,50 @@ err: return ESP_FAIL; } +static esp_err_t rtl8201_update_link_duplex_speed(phy_rtl8201_t *rtl8201) +{ + esp_eth_mediator_t *eth = rtl8201->eth; + eth_speed_t speed = ETH_SPEED_10M; + eth_duplex_t duplex = ETH_DUPLEX_HALF; + bmcr_reg_t bmcr; + bmsr_reg_t bmsr; + PHY_CHECK(rtl8201_page_select(rtl8201, 0) == ESP_OK, "select page 0 failed", err); + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + /* check if link status changed */ + if (rtl8201->link_status != link) { + /* when link up, read negotiation result */ + if (link == ETH_LINK_UP) { + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); + if (bmcr.speed_select) { + speed = ETH_SPEED_100M; + } else { + speed = ETH_SPEED_10M; + } + if (bmcr.duplex_mode) { + duplex = ETH_DUPLEX_FULL; + } else { + duplex = ETH_DUPLEX_HALF; + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, + "change speed failed", err); + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, + "change duplex failed", err); + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, + "change link failed", err); + rtl8201->link_status = link; + } + return ESP_OK; +err: + return ESP_FAIL; +} + static esp_err_t rtl8201_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) { - PHY_CHECK(eth, "can't set mediator for rtl8201 to null", err); + PHY_CHECK(eth, "can't set mediator to null", err); phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); rtl8201->eth = eth; return ESP_OK; @@ -97,19 +137,8 @@ err: static esp_err_t rtl8201_get_link(esp_eth_phy_t *phy) { phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); - esp_eth_mediator_t *eth = rtl8201->eth; - bmsr_reg_t bmsr; - - PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; - if (rtl8201->link_status != link) { - if (link == ETH_LINK_UP) { - phy->negotiate(phy); - } else { - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); - rtl8201->link_status = link; - } - } + /* Updata information about link, speed, duplex */ + PHY_CHECK(rtl8201_update_link_duplex_speed(rtl8201) == ESP_OK, "update link duplex speed failed", err); return ESP_OK; err: return ESP_FAIL; @@ -121,17 +150,19 @@ static esp_err_t rtl8201_reset(esp_eth_phy_t *phy) rtl8201->link_status = ETH_LINK_DOWN; esp_eth_mediator_t *eth = rtl8201->eth; bmcr_reg_t bmcr = {.reset = 1}; - PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); /* Wait for reset complete */ uint32_t to = 0; for (to = 0; to < rtl8201->reset_timeout_ms / 10; to++) { vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!bmcr.reset) { break; } } - PHY_CHECK(to < rtl8201->reset_timeout_ms / 10, "PHY reset timeout", err); + PHY_CHECK(to < rtl8201->reset_timeout_ms / 10, "reset timeout", err); return ESP_OK; err: return ESP_FAIL; @@ -153,51 +184,32 @@ static esp_err_t rtl8201_negotiate(esp_eth_phy_t *phy) { phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); esp_eth_mediator_t *eth = rtl8201->eth; - /* Start auto negotiation */ + /* Restart auto negotiation */ bmcr_reg_t bmcr = { .speed_select = 1, /* 100Mbps */ .duplex_mode = 1, /* Full Duplex */ .en_auto_nego = 1, /* Auto Negotiation */ .restart_auto_nego = 1 /* Restart Auto Negotiation */ }; - PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); /* Wait for auto negotiation complete */ bmsr_reg_t bmsr; uint32_t to = 0; for (to = 0; to < rtl8201->autonego_timeout_ms / 10; to++) { vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + "read BMSR failed", err); if (bmsr.auto_nego_complete) { break; } } /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ if (to >= rtl8201->autonego_timeout_ms / 10) { - ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout"); + ESP_LOGW(TAG, "auto negotiation timeout"); } - PHY_CHECK(rtl8201_page_select(rtl8201, 0) == ESP_OK, "select page failed", err); /* Updata information about link, speed, duplex */ - PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; - eth_speed_t speed = ETH_SPEED_10M; - eth_duplex_t duplex = ETH_DUPLEX_HALF; - if (bmcr.speed_select) { - speed = ETH_SPEED_100M; - } else { - speed = ETH_SPEED_10M; - } - if (bmcr.duplex_mode) { - duplex = ETH_DUPLEX_FULL; - } else { - duplex = ETH_DUPLEX_HALF; - } - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err); - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err); - if (rtl8201->link_status != link) { - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); - rtl8201->link_status = link; - } + PHY_CHECK(rtl8201_update_link_duplex_speed(rtl8201) == ESP_OK, "update link duplex speed failed", err); return ESP_OK; err: return ESP_FAIL; @@ -208,7 +220,8 @@ static esp_err_t rtl8201_pwrctl(esp_eth_phy_t *phy, bool enable) phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); esp_eth_mediator_t *eth = rtl8201->eth; bmcr_reg_t bmcr; - PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!enable) { /* Enable IEEE Power Down Mode */ bmcr.power_down = 1; @@ -216,8 +229,10 @@ static esp_err_t rtl8201_pwrctl(esp_eth_phy_t *phy, bool enable) /* Disable IEEE Power Down Mode */ bmcr.power_down = 0; } - PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); if (!enable) { PHY_CHECK(bmcr.power_down == 1, "power down failed", err); } else { @@ -237,7 +252,7 @@ static esp_err_t rtl8201_set_addr(esp_eth_phy_t *phy, uint32_t addr) static esp_err_t rtl8201_get_addr(esp_eth_phy_t *phy, uint32_t *addr) { - PHY_CHECK(addr, "get phy address failed", err); + PHY_CHECK(addr, "addr can't be null", err); phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); *addr = rtl8201->addr; return ESP_OK; @@ -257,15 +272,18 @@ static esp_err_t rtl8201_init(esp_eth_phy_t *phy) phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); esp_eth_mediator_t *eth = rtl8201->eth; /* Power on Ethernet PHY */ - PHY_CHECK(rtl8201_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err); + PHY_CHECK(rtl8201_pwrctl(phy, true) == ESP_OK, "power control failed", err); /* Reset Ethernet PHY */ - PHY_CHECK(rtl8201_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err); + PHY_CHECK(rtl8201_reset(phy) == ESP_OK, "reset failed", err); /* Check PHY ID */ phyidr1_reg_t id1; phyidr2_reg_t id2; - PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err); - PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err); - PHY_CHECK(id1.oui_msb == 0x1C && id2.oui_lsb == 0x32 && id2.vendor_model == 0x1, "wrong PHY chip ID", err); + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, + "read ID1 failed", err); + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, + "read ID2 failed", err); + PHY_CHECK(id1.oui_msb == 0x1C && id2.oui_lsb == 0x32 && id2.vendor_model == 0x1, + "wrong chip ID", err); return ESP_OK; err: return ESP_FAIL; @@ -274,7 +292,7 @@ err: static esp_err_t rtl8201_deinit(esp_eth_phy_t *phy) { /* Power off Ethernet PHY */ - PHY_CHECK(rtl8201_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err); + PHY_CHECK(rtl8201_pwrctl(phy, false) == ESP_OK, "power control failed", err); return ESP_OK; err: return ESP_FAIL; @@ -284,8 +302,7 @@ esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config) { PHY_CHECK(config, "can't set phy config to null", err); phy_rtl8201_t *rtl8201 = calloc(1, sizeof(phy_rtl8201_t)); - PHY_CHECK(rtl8201, "calloc rtl8201 object failed", err); - rtl8201->name = "rtl8201"; + PHY_CHECK(rtl8201, "calloc rtl8201 failed", err); rtl8201->addr = config->phy_addr; rtl8201->reset_gpio_num = config->reset_gpio_num; rtl8201->reset_timeout_ms = config->reset_timeout_ms; diff --git a/components/soc/esp32/emac_hal.c b/components/soc/esp32/emac_hal.c index 93ff771db1..9b0c52e24a 100644 --- a/components/soc/esp32/emac_hal.c +++ b/components/soc/esp32/emac_hal.c @@ -482,7 +482,7 @@ void emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t len hal->dma_regs->dmatxpolldemand = 0; } -uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t *frames_remain) +uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain) { eth_dma_rx_descriptor_t *desc_iter = NULL; eth_dma_rx_descriptor_t *first_desc = NULL; @@ -501,6 +501,12 @@ uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t if (desc_iter->RDES0.LastDescriptor) { /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */ len = desc_iter->RDES0.FrameLength - ETH_CRC_LENGTH; + /* check if the buffer can store the whole frame */ + if (len > size) { + /* return the real size that we want */ + /* user need to compare the return value to the size they prepared when this function returned */ + return len; + } /* update unhandled frame count */ frame_count++; } diff --git a/components/soc/esp32/include/hal/emac.h b/components/soc/esp32/include/hal/emac.h index 1b21897b6a..824b896327 100644 --- a/components/soc/esp32/include/hal/emac.h +++ b/components/soc/esp32/include/hal/emac.h @@ -380,7 +380,7 @@ uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal); void emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length); -uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t *frames_remain); +uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain); void emac_hal_isr(void *arg); From 0508ad525aef53de4b4fb1a28d45b0f294b4f13f Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 29 Nov 2019 14:49:02 +0800 Subject: [PATCH 6/6] ethernet: add pm lock --- components/esp_eth/src/esp_eth_mac_esp32.c | 24 +++++++++++++++++++ .../api-reference/system/power_management.rst | 2 +- .../api-reference/system/power_management.rst | 2 +- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/components/esp_eth/src/esp_eth_mac_esp32.c b/components/esp_eth/src/esp_eth_mac_esp32.c index 03a5b53bb6..7f0ffdd4bf 100644 --- a/components/esp_eth/src/esp_eth_mac_esp32.c +++ b/components/esp_eth/src/esp_eth_mac_esp32.c @@ -19,6 +19,7 @@ #include "esp_attr.h" #include "esp_log.h" #include "esp_eth.h" +#include "esp_pm.h" #include "esp_system.h" #include "esp_heap_caps.h" #include "esp_intr_alloc.h" @@ -57,6 +58,9 @@ typedef struct { uint8_t *rx_buf[CONFIG_ETH_DMA_RX_BUFFER_NUM]; uint8_t *tx_buf[CONFIG_ETH_DMA_TX_BUFFER_NUM]; bool isr_need_yield; +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_handle_t pm_lock; +#endif } emac_esp32_t; static esp_err_t emac_esp32_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth) @@ -314,6 +318,9 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac) MAC_CHECK(esp_read_mac(emac->addr, ESP_MAC_ETH) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL); /* set MAC address to emac register */ emac_hal_set_address(&emac->hal, emac->addr); +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_acquire(emac->pm_lock); +#endif return ESP_OK; err: eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); @@ -325,6 +332,9 @@ static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac) { emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); esp_eth_mediator_t *eth = emac->eth; +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_release(emac->pm_lock); +#endif emac_hal_stop(&emac->hal); eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); periph_module_disable(PERIPH_EMAC_MODULE); @@ -335,6 +345,11 @@ static esp_err_t emac_esp32_del(esp_eth_mac_t *mac) { emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); esp_intr_free(emac->intr_hdl); +#ifdef CONFIG_PM_ENABLE + if (emac->pm_lock) { + esp_pm_lock_delete(emac->pm_lock); + } +#endif vTaskDelete(emac->rx_task_hdl); int i = 0; for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { @@ -409,6 +424,10 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) MAC_CHECK(esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_esp32_isr_handler, &emac->hal, &(emac->intr_hdl)) == ESP_OK, "alloc emac interrupt failed", err, NULL); +#ifdef CONFIG_PM_ENABLE + MAC_CHECK(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "emac_esp32", &emac->pm_lock) == ESP_OK, + "create pm lock failed", err, NULL); +#endif /* create rx task */ BaseType_t xReturned = xTaskCreate(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac, config->rx_task_prio, &emac->rx_task_hdl); @@ -429,6 +448,11 @@ err: for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { free(emac->rx_buf[i]); } +#ifdef CONFIG_PM_ENABLE + if (emac->pm_lock) { + esp_pm_lock_delete(emac->pm_lock); + } +#endif free(emac); } if (descriptors) { diff --git a/docs/en/api-reference/system/power_management.rst b/docs/en/api-reference/system/power_management.rst index a10b9b03bc..6a965f47fe 100644 --- a/docs/en/api-reference/system/power_management.rst +++ b/docs/en/api-reference/system/power_management.rst @@ -125,7 +125,7 @@ Currently, the following peripheral drivers are aware of DFS and will use the `` The following drivers will hold the ``ESP_PM_APB_FREQ_MAX`` lock while the driver is enabled: - **SPI slave**: between calls to :cpp:func:`spi_slave_initialize` and :cpp:func:`spi_slave_free`. -- **Ethernet**: between calls to :cpp:func:`esp_eth_enable` and :cpp:func:`esp_eth_disable`. +- **Ethernet**: between calls to :cpp:func:`esp_eth_driver_install` and :cpp:func:`esp_eth_driver_uninstall`. - **WiFi**: between calls to :cpp:func:`esp_wifi_start` and :cpp:func:`esp_wifi_stop`. If modem sleep is enabled, the lock will be released for the periods of time when radio is disabled. - **Bluetooth**: between calls to :cpp:func:`esp_bt_controller_enable` and :cpp:func:`esp_bt_controller_disable`. If Bluetooth modem sleep is enabled, the ``ESP_PM_APB_FREQ_MAX`` lock will be released for the periods of time when radio is disabled. However the ``ESP_PM_NO_LIGHT_SLEEP`` lock will still be held, unless :ref:`CONFIG_BTDM_LOW_POWER_CLOCK` option is set to "External 32kHz crystal". - **CAN**: between calls to :cpp:func:`can_driver_install` and :cpp:func:`can_driver_uninstall`. diff --git a/docs/zh_CN/api-reference/system/power_management.rst b/docs/zh_CN/api-reference/system/power_management.rst index a37a97be4d..350020e877 100644 --- a/docs/zh_CN/api-reference/system/power_management.rst +++ b/docs/zh_CN/api-reference/system/power_management.rst @@ -111,7 +111,7 @@ ESP32 支持下表中所述的三种电源管理锁。 启用以下驱动程序时,将占用 ``ESP_PM_APB_FREQ_MAX`` 锁: - **SPI slave**:从调用 :cpp:func:`spi_slave_initialize` 至 :cpp:func:`spi_slave_free` 期间。 -- **Ethernet**:从调用 :cpp:func:`esp_eth_enable` 至 :cpp:func:`esp_eth_disable` 期间。 +- **Ethernet**:从调用 :cpp:func:`esp_eth_driver_install` 至 :cpp:func:`esp_eth_driver_uninstall` 期间。 - **WiFi**:从调用 :cpp:func:`esp_wifi_start` 至 :cpp:func:`esp_wifi_stop` 期间。如果启用了调制解调器睡眠模式,广播关闭时将释放此管理锁。 - **Bluetooth**:从调用 :cpp:func:`esp_bt_controller_enable` 至 :cpp:func:`esp_bt_controller_disable` 期间。如果启用了蓝牙调制解调器,广播关闭时将释放此管理锁。但依然占用 ``ESP_PM_NO_LIGHT_SLEEP`` 锁。 - **CAN**:从调用 :cpp:func:`can_driver_install` 至 :cpp:func:`can_driver_uninstall` 期间。