#include "ethernet.h" #include #include #include "driver/gpio.h" #include "driver/spi_master.h" #include "esp_eth.h" #include "esp_event.h" #include "esp_log.h" #include "esp_mac.h" #include "esp_netif.h" #include "freertos/FreeRTOS.h" #include "freertos/event_groups.h" static const char *TAG = "ethernet"; // Waveshare ESP32-S3-ETH W5500 wiring (same as matter-esp32-heating-monitor). #define ETH_SPI_HOST SPI2_HOST #define ETH_SPI_SCLK_GPIO 13 #define ETH_SPI_MOSI_GPIO 11 #define ETH_SPI_MISO_GPIO 12 #define ETH_SPI_CS_GPIO 14 #define ETH_SPI_INT_GPIO 10 #define ETH_SPI_RST_GPIO 9 #define ETH_SPI_CLOCK_MHZ 25 #define GOT_IP_BIT BIT0 static EventGroupHandle_t s_events; static char s_ip[16] = "0.0.0.0"; static void on_eth_event(void *arg, esp_event_base_t base, int32_t id, void *data) { switch (id) { case ETHERNET_EVENT_CONNECTED: ESP_LOGI(TAG, "Link up"); break; case ETHERNET_EVENT_DISCONNECTED: ESP_LOGW(TAG, "Link down"); xEventGroupClearBits(s_events, GOT_IP_BIT); strcpy(s_ip, "0.0.0.0"); break; default: break; } } static void on_got_ip(void *arg, esp_event_base_t base, int32_t id, void *data) { ip_event_got_ip_t *event = (ip_event_got_ip_t *)data; snprintf(s_ip, sizeof(s_ip), IPSTR, IP2STR(&event->ip_info.ip)); ESP_LOGI(TAG, "Got IP %s", s_ip); xEventGroupSetBits(s_events, GOT_IP_BIT); } esp_err_t ethernet_start(void) { s_events = xEventGroupCreate(); // The W5500 signals RX through a GPIO interrupt. esp_err_t err = gpio_install_isr_service(0); if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { return err; } esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH(); esp_netif_t *netif = esp_netif_new(&netif_cfg); spi_bus_config_t buscfg = { .mosi_io_num = ETH_SPI_MOSI_GPIO, .miso_io_num = ETH_SPI_MISO_GPIO, .sclk_io_num = ETH_SPI_SCLK_GPIO, .quadwp_io_num = -1, .quadhd_io_num = -1, }; ESP_ERROR_CHECK(spi_bus_initialize(ETH_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO)); spi_device_interface_config_t devcfg = { .mode = 0, .clock_speed_hz = ETH_SPI_CLOCK_MHZ * 1000 * 1000, .spics_io_num = ETH_SPI_CS_GPIO, .queue_size = 20, }; eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(ETH_SPI_HOST, &devcfg); w5500_config.int_gpio_num = ETH_SPI_INT_GPIO; eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); phy_config.reset_gpio_num = ETH_SPI_RST_GPIO; esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config); esp_eth_config_t eth_cfg = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_handle_t eth = NULL; ESP_ERROR_CHECK(esp_eth_driver_install(ð_cfg, ð)); // The W5500 has no MAC of its own; derive one from the SoC eFuse. uint8_t mac_addr[6]; ESP_ERROR_CHECK(esp_read_mac(mac_addr, ESP_MAC_ETH)); ESP_ERROR_CHECK(esp_eth_ioctl(eth, ETH_CMD_S_MAC_ADDR, mac_addr)); ESP_ERROR_CHECK(esp_netif_attach(netif, esp_eth_new_netif_glue(eth))); ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &on_eth_event, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &on_got_ip, NULL)); ESP_ERROR_CHECK(esp_eth_start(eth)); ESP_LOGI(TAG, "W5500 started"); return ESP_OK; } bool ethernet_wait_for_ip(int timeout_ms) { EventBits_t bits = xEventGroupWaitBits(s_events, GOT_IP_BIT, pdFALSE, pdTRUE, pdMS_TO_TICKS(timeout_ms)); return (bits & GOT_IP_BIT) != 0; } const char *ethernet_ip_string(void) { return s_ip; }